Module RTLdefgenproof

Require Import Coqlib.
Require Import Errors.
Require Import Maps.
Require Import AST.
Require Import Events.
Require Import Integers.
Require Import Floats.
Require Import Values.
Require Import Memory.
Require Import Globalenvs.
Require Import Smallstep.
Require Import Op.
Require Import Registers.
Require Import Annotations.
Require Import RTL.
Require Import RTLdefgen.
Require Import RTLdefgenspec.
Require Import Behaviors.
Require Import MoreAxioms.

Theorem FSIM:
  forall p, forward_simulation (semantics_block' p) (RTL.semantics p).
Proof.
  intros. eapply Forward_simulation with (fsim_order := ltof _ (fun _ => O)).
  - eapply well_founded_ltof.
  - instantiate (1 := fun i s1 s2 => i = s1 /\ s1 = s2).
    intros. exists s1; exists s1; split; auto.
  - intros. simpl in H. destruct H; subst. inv H0. econstructor.
  - simpl; intros. destruct H0; subst.
    exists s1'; exists s1'; split; auto.
    left. eapply plus_one. inv H.
    + eapply exec_Inop; eauto.
    + eapply exec_Iop; eauto.
    + eapply exec_Iload; eauto.
    + eapply exec_Istore; eauto.
    + eapply exec_Icall; eauto.
    + eapply exec_Itailcall; eauto.
    + eapply exec_Ibuiltin; eauto.
    + eapply exec_Icond; eauto.
    + eapply exec_Ijumptable; eauto.
    + eapply exec_Ireturn; eauto.
    + eapply exec_function_internal; eauto.
    + eapply exec_function_external;eauto.
    + eapply exec_return; eauto.
  - intros. simpl. reflexivity.
Defined.

Section PRESERVATION.

  Variable prog: program.
  Variable tprog: program.
  Hypothesis TRANSF: transf_program prog = OK tprog.
  Definition ge := Genv.globalenv prog.
  Definition tge := Genv.globalenv tprog.
  Let STK := Psucc (Psucc (fold_left Pmax ((map fst (prog_defs prog)) ++ prog_public prog) 1%positive)).
  Let SIZE := Psucc STK.
  
  Hypothesis DEFSAFE: forall beh, program_behaves (RTL.semantics tprog) beh -> not_wrong beh.
  Hypothesis SAFE: forall beh, program_behaves (RTL.semantics prog) beh -> not_wrong beh.

  Opaque Z.mul. Opaque Z.sub.

  Lemma TRANSF':
    transform_partial_augment_program (transf_fundef prog (Genv.globalenv prog) STK SIZE)
         (fun v : unit => OK v) ((STK, Gvar STK_globvar) :: (SIZE, Gvar SIZE_globvar) :: nil)
         (prog_main prog) prog = OK tprog.
Proof.
    unfold transf_program in TRANSF.
    destruct (list_norepet_dec peq (map fst (prog_defs prog))); inv TRANSF.
    destruct (check_init_data_list_size (map snd (prog_defs prog))); inv H0.
    auto.
  Qed.
  
  Lemma init_state_exists:
    exists s, initial_state prog s.
Proof.
    destruct (Classical_Prop.classic (exists s, initial_state prog s)); auto.
    assert (program_behaves (RTL.semantics prog) (Goes_wrong E0)).
    { eapply program_goes_initially_wrong. unfold not in *; intros.
      eapply H; eauto. }
    generalize (SAFE (Goes_wrong E0) H0); intros. inv H1.
  Qed.

  Lemma init_state_exists':
    exists s, initial_state tprog s.
Proof.
    destruct (Classical_Prop.classic (exists s, initial_state tprog s)); auto.
    assert (program_behaves (RTL.semantics tprog) (Goes_wrong E0)).
    { eapply program_goes_initially_wrong. unfold not in *; intros.
      eapply H; eauto. }
    generalize (DEFSAFE (Goes_wrong E0) H0); intros. inv H1.
  Qed.

  Lemma SIZE_exists:
    exists b, Genv.find_symbol tge SIZE = Some b
         /\ Genv.find_var_info tge b = Some SIZE_globvar.
Proof.
    eapply Genv.find_new_var_exists; eauto.
    - simpl. eapply TRANSF'.
    - econstructor.
      + intro. inv H; auto.
        eapply (Pos.succ_discr STK); auto.
      + econstructor; eauto. econstructor.
    - eapply in_cons. eapply in_eq.
  Qed.

  Lemma STK_exists:
    exists b, Genv.find_symbol tge STK = Some b
         /\ Genv.find_var_info tge b = Some STK_globvar.
Proof.
    eapply Genv.find_new_var_exists; eauto.
    - simpl. eapply TRANSF'.
    - simpl. econstructor.
      + intro. inv H; auto.
        eapply (Pos.succ_discr STK); auto.
      + econstructor; eauto. econstructor.
    - eapply in_eq.
  Qed.
  
  Lemma symbols_preserved:
    forall (s: ident),
      ~ In s (STK::SIZE::nil) ->
      Genv.find_symbol tge s = Genv.find_symbol ge s.
Proof.
    intro. unfold ge, tge.
    intros. eapply Genv.find_symbol_transf_augment.
    exact TRANSF'. exact H.
  Qed.

  Lemma public_preserved:
    forall (s: ident),
      ~ In s (STK::SIZE::nil) ->
      Genv.public_symbol tge s = Genv.public_symbol ge s.
Proof.
    intro. unfold ge, tge.
    intros. eapply Genv.public_symbol_transf_augment.
    exact TRANSF'. exact H.
  Qed.

  Lemma varinfo_preserved:
    forall b v, Genv.find_var_info ge b = Some v ->
           Genv.find_var_info tge b = Some v.
Proof.
    intros. unfold ge, tge.
    exploit Genv.find_var_info_transf_augment.
    exact TRANSF'. exact H. intros [v' [A B]].
    unfold transf_globvar in B. monadInv B. rewrite A.
    destruct v; simpl in *. inv EQ. auto.
  Qed.

  Lemma functions_translated:
    forall (v: val) (f: RTL.fundef),
      Genv.find_funct ge v = Some f ->
      exists tf,
        Genv.find_funct tge v = Some tf /\ transf_fundef prog ge STK SIZE f = OK tf.
Proof.
    eapply (Genv.find_funct_transf_augment (transf_fundef prog ge STK SIZE) _ _ _ _ TRANSF').
  Qed.
  
  Lemma function_ptr_translated:
    forall (b: block) (f: RTL.fundef),
      Genv.find_funct_ptr ge b = Some f ->
      exists tf,
        Genv.find_funct_ptr tge b = Some tf /\ transf_fundef prog ge STK SIZE f = OK tf.
Proof.
    eapply (Genv.find_funct_ptr_transf_augment (transf_fundef prog ge STK SIZE) _ _ _ _ TRANSF').
  Qed.
  
  Lemma sig_function_translated:
    forall f tf,
      transf_fundef prog ge STK SIZE f = OK tf ->
      funsig tf = funsig f.
Proof.
    intros; destruct f; monadInv H.
    unfold transf_function in EQ.
    monadInv EQ; auto.
    auto.
  Qed.

  Lemma stacksize_translated:
    forall f tf,
      transf_function prog ge STK SIZE f = OK tf -> tf.(fn_stacksize) = f.(fn_stacksize).
Proof.
    unfold transf_function; intros. monadInv H; auto.
  Qed.

  Lemma find_function_translated:
    forall j n ros rs fd trs,
      match ros with
      | inl r => rs#r = trs#r
      | inr s => ~ In s (STK::SIZE::nil)
      end ->
      find_function ge ros rs = Some fd ->
      regs_agree j n rs trs ->
      exists tfd, find_function tge ros trs = Some tfd /\ transf_fundef prog ge STK SIZE fd = OK tfd.
Proof.
    intros. destruct ros as [r|id]; simpl in *.
    - apply functions_translated. rewrite <- H; auto.
    - rewrite symbols_preserved. destruct (Genv.find_symbol ge id); try discriminate.
      apply function_ptr_translated; auto. exact H.
  Qed.
  
  Lemma fold_left_Pmax_invariant:
    forall l m n,
      Ple m n ->
      Ple m (fold_left Pmax l n).
Proof.
    induction l; intros; auto.
    apply IHl. xomega.
  Qed.
    
  Lemma fold_left_Pmax_invariant_aux:
    forall l m n,
      Ple m n ->
      Ple (fold_left Pmax l m) (fold_left Pmax l n).
Proof.
    induction l; intros; auto.
    simpl. apply IHl. xomega.
  Qed.

  Lemma new_globs_are_new:
    forall s l,
      In s l ->
      Ple s (fold_left Pmax l xH).
Proof.
    induction l; intros.
    - inv H.
    - simpl in H. destruct H.
      + simpl. eapply (fold_left_Pmax_invariant l s (Pmax 1 a)).
        rewrite H; xomega.
      + eapply IHl in H. simpl.
        eapply Ple_trans; eauto.
        eapply fold_left_Pmax_invariant_aux; eauto. xomega.
  Qed.
  
  Lemma STK_is_new:
    ~ In STK (List.map fst prog.(prog_defs)).
Proof.
    intro. generalize (new_globs_are_new STK (map fst (prog_defs prog) ++ prog_public prog) (in_or_app _ _ _ (or_introl H))).
    unfold STK in *. xomega.
  Qed.

  Lemma SIZE_is_new:
    ~ In SIZE (List.map fst prog.(prog_defs)).
Proof.
    intro. generalize (new_globs_are_new SIZE (map fst (prog_defs prog) ++ prog_public prog) (in_or_app _ _ _ (or_introl H))).
    unfold STK in *. unfold SIZE in *. xomega.
  Qed.

  Lemma STK_not_public:
    ~ In STK prog.(prog_public).
Proof.
    intro. generalize (new_globs_are_new STK (map fst (prog_defs prog) ++ prog_public prog) (in_or_app _ _ _ (or_intror H))).
    unfold STK in *. xomega.
  Qed.
  
  Lemma SIZE_not_public:
    ~ In SIZE prog.(prog_public).
Proof.
    intro. generalize (new_globs_are_new SIZE (map fst (prog_defs prog) ++ prog_public prog) (in_or_app _ _ _ (or_intror H))).
    unfold STK in *. unfold SIZE in *. xomega.
  Qed.

  Lemma STK_SIZE_are_new:
    forall id b,
      Genv.find_symbol ge id = Some b ->
      ~ In id (STK::SIZE::nil).
Proof.
    intros. eapply Genv.find_symbol_inversion in H.
    intro. simpl in H0. destruct H0 as [H0 | [H0 | H0]]; inversion H0.
    - unfold prog_defs_names in H.
      eapply STK_is_new. rewrite <- H1 in H. eapply H.
    - unfold prog_defs_names in H.
      eapply SIZE_is_new. rewrite <- H1 in H. eapply H.
  Qed.

  Lemma norepet_prog_defs:
    list_norepet (map fst (prog_defs prog)).
Proof.
    unfold transf_program in TRANSF.
    destruct (list_norepet_dec peq (map fst (prog_defs prog))); auto; inv TRANSF.
  Qed.

  Lemma check_init_data_list_size_spec:
    forall l,
      check_init_data_list_size l = true ->
      forall gv, In (Gvar gv) l -> Genv.init_data_list_size (gvar_init gv) <= Int.max_unsigned.
Proof.
    induction l.
    - intros. inv H0.
    - intros. simpl in H. destruct H0.
      + subst a. destruct (zle (Genv.init_data_list_size (gvar_init gv)) Int.max_unsigned); inv H. auto.
      + destruct a.
        * eapply IHl; eauto.
        * destruct (zle (Genv.init_data_list_size (gvar_init v)) Int.max_unsigned); inv H.
          eapply IHl; eauto.
  Qed.

  Lemma prog_defs_init_data_is_bounded:
    forall gv, In (Gvar gv) (map snd prog.(prog_defs)) -> Genv.init_data_list_size (gvar_init gv) <= Int.max_unsigned.
Proof.
    eapply check_init_data_list_size_spec.
    unfold transf_program in TRANSF.
    destruct (list_norepet_dec peq (map fst (prog_defs prog))); inv TRANSF.
    destruct (check_init_data_list_size (map snd (prog_defs prog))); inv H0; auto.
  Qed.
    
  Lemma tr_local_regs_correct:
    forall kappa j sp sp' stk f tf n pc1 ofs depth regs regs' pc2 pcs vals rs trs m,
      tr_local_regs STK kappa f (fn_code tf) pc1 ofs depth n regs regs' pc2 pcs ->
      addr_of_local kappa (Vptr sp' Int.zero) ofs n vals ->
      regs_agree j (max_reg_function f) rs trs ->
      (forall r : positive, Plt (max_reg_function f) r -> rs # r = Vundef) ->
      (exists n, Mem.loadv Mint32 m (Genv.symbol_address tge SIZE Int.zero) = Some (Vint n)
            /\ Mem.loadv Mint32 m (Val.add (Genv.symbol_address tge STK (Int.repr (-4 * Z.of_nat depth))) (Vint n)) = Some (Vptr sp' Int.zero)) ->
      exists trs', star step tge (State stk tf sp pc1 trs m) E0 (State stk tf sp pc2 trs' m) /\
              list_forall2 (fun reg val => trs' # reg = val) regs vals /\
              regs_agree j (max_reg_function f) rs trs' /\
              forall reg, ~ In reg (regs ++ regs') -> trs#reg = trs'#reg.
Proof.
    induction n; intros.
    - inv H. inv H0.
      exists trs; split; try (econstructor; eauto); econstructor.
    - inv H; inv H0. remember H3. clear Heqe. destruct H3 as [ndepth [X Y]].
      assert (regs_agree j (max_reg_function f) rs ((trs # (Pos.succ (Pos.succ reg)) <- (Vint ndepth)) # (Pos.succ reg) <- (Vptr sp' Int.zero)) # reg <- (Val.add (Vptr sp' Int.zero) (Vint ofs))).
      + unfold regs_agree. intros; destruct (plt (max_reg_function f) r).
        * right; split; auto.
          rewrite H2; eauto.
        * left; split; try xomega.
          generalize (H1 r). intros [[D E] | D]; try xomega.
          rewrite PMap.gso; eauto; try xomega. rewrite PMap.gso; eauto; try xomega.
          rewrite PMap.gso; eauto; try xomega.
      + generalize (IHn (Pos.succ (Psucc (Psucc pc1))) _ _ _ _ pc2 _ _ _ _ m H8 H13 H H2 e). intros [trs' [A [B [C D]]]].
        exists trs'; repeat split.
        * econstructor 2.
          { eapply exec_Iload.
            - eauto.
            - simpl. reflexivity.
            - exact X. }
          { econstructor 2.
            - eapply exec_Iload; eauto.
              simpl. rewrite PMap.gss. reflexivity.
            - eapply star_step.
              + eapply exec_Iop; eauto.
                simpl. rewrite PMap.gss.
                instantiate (1 := (Val.add (Vptr sp' Int.zero) (Vint ofs))).
                destruct (Int.eq_dec ofs Int.zero).
                * simpl. rewrite Int.add_zero_l.
                  subst ofs. reflexivity.
                * simpl. reflexivity.
              + eapply A.
              + eauto.
            - eauto. }
          { eauto. }
        * destruct (ArithLib.Zdivides_dec (align_chunk kappa) (Int.unsigned ofs)); try congruence.
          econstructor; eauto.
          rewrite <- (D _ H10). rewrite PMap.gss; eauto.
        * assumption.
        * intros. rewrite <- D.
          { rewrite not_in_app in H0. destruct H0.
            repeat rewrite not_in_cons in H3. destruct H3 as [H3 [? ?]].
            rewrite not_in_cons in H0; destruct H0.
            rewrite PMap.gso; eauto.
            rewrite PMap.gso; eauto.
            rewrite PMap.gso; eauto. }
          { rewrite not_in_app in H0. destruct H0.
            repeat rewrite not_in_cons in H3. destruct H3 as [H3 [? ?]].
            rewrite not_in_cons in H0; destruct H0.
            eapply not_in_app; eauto. }
      + destruct (ArithLib.Zdivides_dec (align_chunk kappa) (Int.unsigned ofs)); try congruence.
        eapply IHn; eauto.
  Qed.
  
  Lemma tr_global_regs_correct:
    forall kappa j sp stk f tf id b n pc1 ofs regs pc2 pcs vals rs trs m,
      tr_global_regs kappa f (fn_code tf) pc1 id ofs n regs pc2 pcs ->
      addr_of_global kappa b ofs n vals ->
      regs_agree j (max_reg_function f) rs trs ->
      (forall r : positive, Plt (max_reg_function f) r -> rs # r = Vundef) ->
      Genv.find_symbol ge id = Some b ->
      ~ In id (STK::SIZE::nil) ->
      exists trs', star step tge (State stk tf sp pc1 trs m) E0 (State stk tf sp pc2 trs' m) /\
              list_forall2 (fun reg val => trs' # reg = val) regs vals /\
              regs_agree j (max_reg_function f) rs trs' /\
              forall reg, ~ In reg regs -> trs#reg = trs'#reg.
Proof.
    induction n; intros.
    - inv H. inv H0.
      exists trs; split; try (econstructor; eauto); econstructor.
    - inv H; inv H0.
      assert (regs_agree j (max_reg_function f) rs (trs # reg <- (Vptr b ofs))).
      + unfold regs_agree. intros; destruct (plt (max_reg_function f) r).
        * right; split; auto.
          rewrite H2; eauto.
        * left; split; try xomega.
          generalize (H1 r). intros [[D E] | D]; try xomega.
          rewrite PMap.gso; eauto. xomega.
      + generalize (IHn (Pos.succ pc1) _ _ pc2 _ _ _ _ m H7 H9 H H2 H3 H4). intros [trs' [A [B [C D]]]].
        exists trs'; repeat split.
        * eapply star_step; eauto.
          { eapply exec_Iop; eauto.
            simpl. unfold Genv.symbol_address.
            rewrite symbols_preserved. rewrite H3; reflexivity. auto. }
          { eauto. }
        * destruct (ArithLib.Zdivides_dec (align_chunk kappa) (Int.unsigned ofs)); try congruence.
          econstructor; eauto.
          rewrite <- D; eauto. rewrite PMap.gss; eauto.
        * assumption.
        * intros. rewrite <- D.
          { rewrite PMap.gso; eauto.
            rewrite not_in_cons in H0.
            destruct H0; assumption. }
          { rewrite not_in_cons in H0.
            destruct H0; assumption. }
      + destruct (ArithLib.Zdivides_dec (align_chunk kappa) (Int.unsigned ofs)); try congruence.
        eapply IHn; eauto.
  Qed.

  Inductive shadowstack_is_sound (stk: list val) (m :mem): Prop :=
  | shadowstack_is_sound_intro:
      (let n := length stk in
       Mem.loadv Mint32 m (Genv.symbol_address tge SIZE Int.zero) = Some (Vint (Int.repr (4 * ((Z.of_nat n) - 1))))
       /\ (forall depth sp, pop depth stk = Some sp <->
                      ((depth < length stk)%nat /\ Mem.loadv Mint32 m (Val.add (Genv.symbol_address tge STK (Int.repr (-4 * Z.of_nat depth))) (Vint (Int.repr (4 * ((Z.of_nat n) - 1))))) = Some sp))) ->
      shadowstack_is_sound stk m.

  Lemma divides_none_implies_local:
    forall kappa f c n pc1 base depth regs regs' pc2 pcs,
      (forall x, In x (int_ranges n base) -> ~ (align_chunk kappa | x)) ->
      tr_local_regs STK kappa f c pc1 base depth n regs regs' pc2 pcs ->
      tr_local_regs STK kappa f c pc1 base depth n nil nil pc1 nil.
Proof.
    induction n; intros.
    - econstructor; eauto.
    - simpl in H. inv H0.
      + generalize (H _ (or_introl eq_refl)). intros.
        exfalso; eapply H0; eauto.
      + econstructor 2; eauto.
  Qed.

  Lemma divides_none_implies_global:
    forall kappa f c n pc1 id base regs pc2 pcs,
      (forall x, In x (int_ranges n base) -> ~ (align_chunk kappa | x)) ->
      tr_global_regs kappa f c pc1 id base n regs pc2 pcs ->
      tr_global_regs kappa f c pc1 id base n nil pc1 nil.
Proof.
    induction n; intros.
    - econstructor; eauto.
    - simpl in H; inv H0.
      + generalize (H _ (or_introl eq_refl)). intros.
        exfalso; eapply H0; eauto.
      + econstructor 2; eauto.
  Qed.
    
  Lemma tr_regs_annot_correct:
    forall kappa j sp stk f tf alpha pc1 regs regs' pc2 pcs vals rs trs m
      (PTRS: forall ptr,
          In ptr (sp::(List.map (fun s => match s with Stackframe res f sp pc rs => sp end) stk)) ->
          exists b, ptr = Vptr b Int.zero)
      (Hdivex: forall depth varname base bound, In (ABlocal depth varname (base, bound)) alpha ->
                                           forall size, Int.unsigned (Int.sub bound base) + 1 = Z.pos size ->
                                                   exists x, In x (int_ranges (Pos.to_nat size) base) /\ ((align_chunk kappa) | x)),
      tr_regs_annot prog STK kappa f (fn_code tf) pc1 alpha regs regs' pc2 pcs ->
      addr_of_annotations kappa tge (sp::(List.map (fun s => match s with Stackframe res f sp pc rs => sp end) stk)) alpha vals ->
      regs_agree j (max_reg_function f) rs trs ->
      (forall r : positive, Plt (max_reg_function f) r -> rs # r = Vundef) ->
      shadowstack_is_sound (sp::(List.map (fun s => match s with Stackframe res f sp pc rs => sp end) stk)) m ->
      exists trs', star step tge (State stk tf sp pc1 trs m) E0 (State stk tf sp pc2 trs' m) /\
              list_forall2 (fun reg val => trs' # reg = val) regs vals /\
              regs_agree j (max_reg_function f) rs trs' /\
              forall reg, ~ In reg (regs ++ regs') -> trs#reg = trs'#reg.
Proof.
    induction alpha; intros.
    - inv H. inv H0.
      exists trs; split; try (econstructor; eauto); econstructor.
    - inv H; inv H0.
      + rewrite H15 in H7. simpl in H7.
        generalize (Hdivex _ _ _ _ (in_eq _ _) _ H15). intros s.
        generalize (pop_is_in _ _ _ H16). intros PU. eapply PTRS in PU. destruct PU as [bsp PU]. subst sp0.
        generalize H3; intros HSS. inv H3. destruct H as [A H]. generalize ((proj1 (H _ _)) H16). intros [B' B].
        exploit tr_local_regs_correct; eauto. intros [trs' [HE [HF [HG HH]]]].
        generalize (IHalpha _ _ _ _ _ _ _ _ m PTRS (fun depth varname base bound Hin size Heq => Hdivex depth varname base bound (in_cons _ _ _ Hin) _ Heq) H6 H18 HG H2 HSS). intros [trs'' [HA [HB [HC HD]]]].
        exists trs''; repeat split.
        * eapply star_trans; eauto.
        * eapply list_forall2_app; eauto.
          eapply list_disjoint_sym in H8. eapply list_disjoint_sym in H10.
          generalize (list_disjoint_app _ _ _ _ H8 H10). intros C.
          eapply list_forall2_list_disjoint; eauto.
        * assumption.
        * intros. rewrite not_in_app in H0. destruct H0.
          rewrite not_in_app in H0, H3. destruct H0, H3.
          rewrite HH; eauto. eapply HD; eauto.
          eapply not_in_app; auto. eapply not_in_app; auto.
      + rewrite H14 in H8. simpl in H8.
        exploit tr_global_regs_correct; eauto. rewrite <- symbols_preserved; eauto.
        eapply STK_SIZE_are_new; eauto. eapply STK_SIZE_are_new; eauto. intros [trs' [HE [HF [HG HH]]]].
        generalize (IHalpha _ _ _ _ _ _ _ _ m PTRS (fun depth varname base bound Hin size Heq => Hdivex depth varname base bound (in_cons _ _ _ Hin) _ Heq) H7 H16 HG H2 H3). intros [trs'' [HA [HB [HC HD]]]].
        exists trs''; repeat split.
        * eapply star_trans; eauto.
        * eapply list_forall2_app; eauto.
          eapply list_forall2_list_disjoint; eauto.
          eapply list_disjoint_sym in H9. eapply list_disjoint_sym in H13.
          eapply list_disjoint_app; eauto.
        * assumption.
        * intros. rewrite not_in_app in H. destruct H.
          rewrite not_in_app in H. destruct H.
          rewrite HH; eauto. eapply HD; eauto.
          rewrite not_in_app; eauto.
  Qed.

  Inductive addr_of_annotations_singleton (ge: Genv.t fundef unit) (sps: list val): list ablock -> list (val + (val * val)) -> Prop :=
  | addr_of_annotations_singleton_local:
      forall depth varname sp base bound alpha vals,
        pop depth sps = Some sp ->
        addr_of_annotations_singleton ge sps alpha vals ->
        addr_of_annotations_singleton ge sps ((ABlocal depth varname (base, bound))::alpha) ((if Int.eq_dec base bound then inl (Val.add sp (Vint base)) else inr (Val.add sp (Vint base), Val.add sp (Vint bound)))::vals)
  | addr_of_annotations_singleton_global:
      forall id b base bound alpha vals,
        Genv.find_symbol ge b = Some id ->
        addr_of_annotations_singleton ge sps alpha vals ->
        addr_of_annotations_singleton ge sps ((ABglobal b (base, bound))::alpha) ((if Int.eq_dec base bound then inl (Vptr id base) else inr (Vptr id base, Vptr id bound))::vals)
  | addr_of_annotations_singleton_nil:
      addr_of_annotations_singleton ge sps nil nil.

  Definition match_reg_val rs (r: reg + (reg * reg)) (v: val + (val * val)): Prop :=
    match r with
    | inl r =>
      match v with
      | inl v => rs # r = v
      | _ => False
      end
    | inr (r, r') =>
      match v with
      | inr (v, v') => rs # r = v /\ rs # r' = v'
      | _ => False
      end
    end.

  Lemma tr_local_regs_singleton_correct:
    forall j sp sp' stk f tf pc1 depth base bound regs regs' pc2 pcs rs trs m,
      tr_local_regs' STK f (fn_code tf) pc1 depth base bound regs regs' pc2 pcs ->
      regs_agree j (max_reg_function f) rs trs ->
      (forall r : positive, Plt (max_reg_function f) r -> rs # r = Vundef) ->
      (exists n, Mem.loadv Mint32 m (Genv.symbol_address tge SIZE Int.zero) = Some (Vint n)
            /\ Mem.loadv Mint32 m (Val.add (Genv.symbol_address tge STK (Int.repr (-4 * Z.of_nat depth))) (Vint n)) = Some (Vptr sp' Int.zero)) ->
      exists trs', star step tge (State stk tf sp pc1 trs m) E0 (State stk tf sp pc2 trs' m) /\
              (match regs with inl r => trs'#r = Vptr sp' base | inr (r, r') => trs'#r = Vptr sp' base /\ trs'#r' = Vptr sp' bound end) /\
              regs_agree j (max_reg_function f) rs trs' /\
              forall reg, ~ In reg (match regs with inl r => r::regs' | inr (r, r') => r::r'::regs' end) -> trs#reg = trs'#reg.
Proof.
    intros. inv H.
    - destruct H2 as [n [HA HB]].
      eexists. split.
      + econstructor. eapply exec_Iload. exact H4.
        simpl. eauto. exact HA.
        eapply star_step. eapply exec_Iload. exact H5.
        simpl. rewrite PMap.gss. eauto. exact HB.
        eapply star_one. eapply exec_Iop. exact H6.
        simpl. rewrite PMap.gss. destruct (Int.eq_dec bound Int.zero).
        rewrite <- e. simpl. eauto. simpl. rewrite Int.add_zero_l. eauto. eauto. eauto.
      + repeat split.
        * rewrite PMap.gss; auto.
        * unfold regs_agree. intros; destruct (plt (max_reg_function f) r0).
          { right; split; auto.
            rewrite H1; eauto. }
          { left; split; try xomega.
            generalize (H0 r0). intros [[D E] | D]; try xomega.
            rewrite PMap.gso; eauto; try xomega. rewrite PMap.gso; eauto; try xomega.
            rewrite PMap.gso; eauto; try xomega. }
        * intros. repeat rewrite PMap.gso; auto.
          intro; eapply H. subst. eapply in_cons. eapply in_cons. eapply in_eq.
          intro; eapply H. subst. eapply in_cons. eapply in_eq.
          intro; eapply H. subst. eapply in_eq.
    - destruct H2 as [n [HA HB]].
      eexists. split.
      + econstructor. eapply exec_Iload. exact H4.
        simpl. eauto. exact HA.
        eapply star_step. eapply exec_Iload. exact H5.
        simpl. rewrite PMap.gss. eauto. exact HB.
        eapply star_step. eapply exec_Iop. exact H6.
        simpl. rewrite PMap.gss. destruct (Int.eq_dec base Int.zero).
        rewrite <- e. simpl. eauto. simpl. rewrite Int.add_zero_l. eauto.
        eapply star_step. eapply exec_Iload. exact H7.
        simpl. eauto. exact HA.
        eapply star_step. eapply exec_Iload. exact H8.
        simpl. rewrite PMap.gss. eauto. exact HB.
        eapply star_one. eapply exec_Iop. exact H9.
        simpl. rewrite PMap.gss. destruct (Int.eq_dec bound Int.zero).
        rewrite <- e. simpl. eauto. simpl. rewrite Int.add_zero_l. eauto. eauto. eauto. eauto. eauto. eauto.
      + repeat split.
        * rewrite PMap.gso; try xomega. rewrite PMap.gso; try xomega.
          rewrite PMap.gso; try xomega. rewrite PMap.gss; auto.
        * rewrite PMap.gss; auto.
        * unfold regs_agree. intros; destruct (plt (max_reg_function f) r0).
          { right; split; auto.
            rewrite H1; eauto. }
          { left; split; try xomega.
            generalize (H0 r0). intros [[D E] | D]; try xomega.
            rewrite PMap.gso; eauto; try xomega. rewrite PMap.gso; eauto; try xomega.
            rewrite PMap.gso; eauto; try xomega. rewrite PMap.gso; eauto; try xomega.
            rewrite PMap.gso; eauto; try xomega. rewrite PMap.gso; eauto; try xomega. }
        * intros. repeat rewrite PMap.gso; auto.
          intro; eapply H. subst. eapply in_cons. eapply in_cons. eapply in_cons. eapply in_eq.
          intro; eapply H. subst. eapply in_cons. eapply in_cons. eapply in_eq.
          intro; eapply H. subst. eapply in_eq.
          intro; eapply H. subst. eapply in_cons. eapply in_cons. eapply in_cons. eapply in_eq.
          intro; eapply H. subst. eapply in_cons. eapply in_cons. eapply in_eq.
          intro; eapply H. subst. eapply in_cons. eapply in_eq.
  Qed.

  Lemma tr_global_regs_singleton_correct:
    forall j sp stk f tf id b pc1 base bound regs pc2 pcs rs trs m,
      tr_global_regs' f (fn_code tf) pc1 id base bound regs pc2 pcs ->
      regs_agree j (max_reg_function f) rs trs ->
      (forall r : positive, Plt (max_reg_function f) r -> rs # r = Vundef) ->
      Genv.find_symbol ge id = Some b ->
      ~ In id (STK::SIZE::nil) ->
      exists trs', star step tge (State stk tf sp pc1 trs m) E0 (State stk tf sp pc2 trs' m) /\
              (match regs with inl r => trs'#r = Vptr b base | inr (r, r') => trs'#r = Vptr b base /\ trs'#r' = Vptr b bound end) /\
              regs_agree j (max_reg_function f) rs trs' /\
              forall reg, ~ In reg (match regs with inl r => r::nil | inr (r, r') => r::r'::nil end) -> trs#reg = trs'#reg.
Proof.
    intros. inv H.
    - eexists; split.
      + eapply star_one. eapply exec_Iop; eauto.
        simpl. unfold Genv.symbol_address. rewrite symbols_preserved; try eassumption. rewrite H2. eauto.
      + repeat split.
        * eapply PMap.gss.
        * unfold regs_agree. intros; destruct (plt (max_reg_function f) r0).
          { right; split; auto.
            rewrite H1; eauto. }
          { left; split; try xomega.
            generalize (H0 r0). intros [[D E] | D]; try xomega.
            rewrite PMap.gso; eauto. xomega. }
        * intros. rewrite PMap.gso; auto.
          intro; eapply H; subst; eapply in_eq.
    - eexists; split.
      + eapply star_step. eapply exec_Iop; eauto.
        simpl. unfold Genv.symbol_address. rewrite symbols_preserved; try eassumption. rewrite H2; eauto.
        eapply star_one. eapply exec_Iop; eauto.
        simpl. unfold Genv.symbol_address. rewrite symbols_preserved; try eassumption. rewrite H2; eauto. eauto.
      + repeat split.
        * rewrite PMap.gso; try xomega. eapply PMap.gss.
        * eapply PMap.gss.
        * unfold regs_agree. intros; destruct (plt (max_reg_function f) r0).
          { right; split; auto.
            rewrite H1; eauto. }
          { left; split; try xomega.
            generalize (H0 r0). intros [[D E] | D]; try xomega.
            rewrite PMap.gso; eauto. rewrite PMap.gso; eauto. xomega. xomega. }
        * intros. repeat rewrite PMap.gso; auto.
          intro; eapply H; subst; eapply in_eq.
          intro; eapply H; subst; eapply in_cons; eapply in_eq.
  Qed.

  Lemma tr_regs_annot_correct_singleton:
    forall j sp stk f tf alpha pc1 regs regs' pc2 pcs vals rs trs m
      (PTRS: forall ptr,
          In ptr (sp::(List.map (fun s => match s with Stackframe res f sp pc rs => sp end) stk)) ->
          exists b, ptr = Vptr b Int.zero),
      tr_regs_annot' prog STK f (fn_code tf) pc1 alpha regs regs' pc2 pcs ->
      addr_of_annotations_singleton tge (sp::(List.map (fun s => match s with Stackframe res f sp pc rs => sp end) stk)) alpha vals ->
      regs_agree j (max_reg_function f) rs trs ->
      (forall r : positive, Plt (max_reg_function f) r -> rs # r = Vundef) ->
      shadowstack_is_sound (sp::(List.map (fun s => match s with Stackframe res f sp pc rs => sp end) stk)) m ->
      exists trs', star step tge (State stk tf sp pc1 trs m) E0 (State stk tf sp pc2 trs' m) /\
              list_forall2 (match_reg_val trs') regs vals /\
              regs_agree j (max_reg_function f) rs trs' /\
              forall reg, ~ In reg ((fold_right (fun x acc => match x with inl r => r::acc | inr (r, r') => r::r'::acc end) nil regs) ++ regs') -> trs#reg = trs'#reg.
Proof.
    induction alpha; intros.
    - inv H. inv H0.
      exists trs; split; try (econstructor; eauto); econstructor.
    - inv H; inv H0.
      + generalize (pop_is_in _ _ _ H15). intros PU. eapply PTRS in PU. destruct PU as [bsp PU]. subst sp0.
        generalize H3; intros HSS. inv H3. destruct H as [A H]. generalize ((proj1 (H _ _)) H15). intros [B' B].
        exploit tr_local_regs_singleton_correct; eauto. intros [trs' [HE [HF [HG HH]]]].
        generalize (IHalpha _ _ _ _ _ _ _ _ m PTRS H6 H16 HG H2 HSS). intros [trs'' [HA [HB [HC HD]]]].
        exists trs''; repeat split.
        * eapply star_trans; eauto.
        * econstructor; eauto.
          red. destruct regs1.
          { destruct (Int.eq_dec base bound).
            - subst base. simpl. rewrite Int.add_zero_l.
              rewrite <- HD; auto. simpl in H8.
              intro. eapply in_app in H0. destruct H0.
              + inv H8. eapply H5; auto.
              + apply (H10 r r (in_eq _ _) H0 eq_refl).
            - inv H7. eapply n; auto. }
          { destruct p. destruct (Int.eq_dec base bound).
            - inv H7; congruence.
            - simpl. rewrite ! Int.add_zero_l.
              rewrite <- ! HD; auto.
              + intro. eapply in_app in H0. destruct H0.
                * inv H8. inv H11. eapply H8; auto.
                * apply (H10 r0 r0 (in_cons _ _ _ (in_eq _ _)) H0 eq_refl).
              + intro. eapply in_app in H0. destruct H0.
                * inv H8. eapply H5; auto. right; auto.
                * apply (H10 r r (in_eq _ _) H0 eq_refl). }
        * exact HC.
        * intros. rewrite HH. rewrite <- HD; auto.
          { intro. eapply H0. simpl. eapply in_app in H3. destruct H3.
            - eapply in_or_app. left. destruct regs1.
              + right; auto.
              + destruct p; right; right; auto.
            - eapply in_or_app. right. eapply in_or_app. right; auto. }
          { intro. eapply H0. simpl. destruct regs1.
            - destruct H3.
              + left; auto.
              + eapply in_or_app. right. eapply in_or_app. left; auto.
            - destruct p. destruct H3.
              + left; auto.
              + destruct H3.
                * right; left; auto.
                * eapply in_or_app. right. eapply in_or_app. left; auto. }
      + exploit tr_global_regs_singleton_correct; eauto. eapply STK_SIZE_are_new. unfold ge. exact H6. intros [trs' [HE [HF [HG HH]]]].
        generalize (symbols_preserved id (STK_SIZE_are_new _ _ H6)). intros HA. unfold ge in HA. rewrite H6 in HA; inv HA. rewrite H12 in H0; inv H0.
        generalize (IHalpha _ _ _ _ _ _ _ _ m PTRS H7 H14 HG H2 H3). intros [trs'' [HA [HB [HC HD]]]].
        exists trs''; repeat split.
        * eapply star_trans; eauto.
        * econstructor; eauto.
          red. destruct regs1.
          { destruct (Int.eq_dec base bound).
            - subst base. rewrite <- HD; auto.
              intro. eapply in_app in H. destruct H.
              + inv H9. eapply H5; auto.
              + eapply (H13 r r (in_eq _ _) H eq_refl).
            - inv H8; congruence. }
          { destruct p. destruct (Int.eq_dec base bound).
            - inv H8; congruence.
            - rewrite <- ! HD; auto.
              + intro. eapply in_app in H. destruct H.
                * inv H9. inv H10. eapply H9; auto.
                * apply (H13 r0 r0 (in_cons _ _ _ (in_eq _ _)) H eq_refl).
              + intro. eapply in_app in H. destruct H.
                * inv H9. eapply H5. right; auto.
                * apply (H13 r r (in_eq _ _) H eq_refl). }
        * exact HC.
        * intros. rewrite HH. rewrite <- HD; auto.
          { intro. eapply H. eapply in_or_app. eapply in_app in H0.
            destruct H0.
            - left. destruct regs1; simpl.
              + right. auto.
              + destruct p. right; right; auto.
            - right; auto. }
          { intro. eapply H. eapply in_or_app. left. destruct regs1; simpl.
            - destruct H0; auto. inv H0.
            - destruct p. destruct H0; auto.
              + subst r; left; auto.
              + destruct H0. subst r0. right; auto.
                left; auto. inv H0. }
  Qed.

  Lemma tr_cmp_regs_correct:
    forall j ts sp f tf reg0 regs pc1 pc2 pcs m rs trs vals,
      tr_cmp_regs (fn_code tf) pc1 reg0 regs pc2 pcs ->
      ~ In reg0 regs ->
      list_forall2 (fun reg val => trs#reg = val) regs vals ->
      regs_agree j (max_reg_function f) rs trs ->
      (forall r, In r regs -> Plt (max_reg_function f) r) ->
      (forall r, Plt (max_reg_function f) r -> rs#r = Vundef) ->
      list_norepet regs ->
      exists trs', star step tge (State ts tf sp pc1 trs m) E0 (State ts tf sp pc2 trs' m) /\
              list_forall2 (fun reg val => trs'#reg = Val.of_optbool (eval_condition (Ccompu Ceq) ((trs#reg0)::val::nil) m)) regs vals /\
              forall reg, ~ In reg regs -> trs#reg = trs'#reg.
Proof.
    induction regs; intros.
    - inv H. inv H1.
      exists trs; repeat split; econstructor; eauto.
    - inv H. inv H1. rewrite not_in_cons in H0. destruct H0.
      assert (regs_agree j (max_reg_function f) rs (trs # a <- (Val.of_optbool (eval_condition (Ccompu Ceq) (trs # reg0 :: trs # a :: nil) m)))).
      + unfold regs_agree; intros.
        destruct (plt (max_reg_function f) r).
        * right; split; auto. rewrite H4; auto.
        * generalize (H3 a (in_eq _ _)); intros.
          left; split; try xomega. rewrite PMap.gso; try xomega.
          generalize (H2 r); intros [[HA HB] | [HA HB]]; try xomega; auto.
      + inv H5.
        generalize (IHregs (Psucc pc1) pc2 pcs0 m rs (trs # a <- (Val.of_optbool (eval_condition (Ccompu Ceq) (trs # reg0 :: trs # a :: nil) m))) bl H14 H0 (list_forall2_not_in _ _ _ _ _ _ H9 H8) H1 (fun Hr HH => H3 Hr (in_cons _ _ _ HH)) H4 H10).
        intros [trs' [A [B C]]]. exists trs'; repeat split.
        * eapply star_step.
          { eapply exec_Iop; eauto.
            unfold eval_operation; eauto. }
          { eapply A. }
          { eauto. }
        * econstructor; eauto.
          { rewrite <- C; eauto. rewrite PMap.gss; eauto. }
          { rewrite PMap.gso in B; eauto. }
        * intros. rewrite not_in_cons in H5. destruct H5.
          rewrite <- C; eauto. rewrite PMap.gso; eauto.
  Qed.

  Definition match_reg_val' m rs rs' (r0: reg) (r: reg + (reg * reg)) (v: val + (val * val)): Prop :=
    match r with
    | inl r =>
      match v with
      | inl v => rs'#r = Val.of_optbool (eval_condition (Ccompu Ceq) (v::(rs#r0)::nil) m)
      | _ => False
      end
    | inr (r, r') =>
      match v with
      | inr (v, v') => rs'#r = (Val.and (Val.of_optbool (Val.cmpu_bool (Mem.valid_pointer m) Cle v rs#r0)) (Val.of_optbool (Val.cmpu_bool (Mem.valid_pointer m) Cle rs#r0 v')))
      | _ => False
      end
    end.

  Lemma list_forall2_not_in':
    forall trs regs vl a v,
      list_forall2 (match_reg_val trs) regs vl ->
      ~ In a (fold_right (fun x acc => match x with | inl r => r::acc | inr (r, r') => r::r'::acc end) nil regs) ->
      list_forall2 (match_reg_val (trs # a <- v)) regs vl.
Proof.
    induction 1; intros.
    - econstructor.
    - econstructor; eauto.
      + unfold match_reg_val. unfold match_reg_val in H.
        destruct a1; destruct b1; auto.
        * rewrite PMap.gso; auto. intro; eapply H1. subst a. eapply in_eq.
        * destruct p. destruct p0. destruct H; split; rewrite PMap.gso; auto; intro; subst a; eapply H1.
          { eapply in_eq. }
          { eapply in_cons. eapply in_eq. }
      + eapply IHlist_forall2. simpl in H1. destruct a1.
        * eapply not_in_cons in H1. destruct H1; auto.
        * destruct p. eapply not_in_cons in H1. destruct H1.
          eapply not_in_cons in H2. destruct H2; auto.
  Qed.

  Lemma list_forall2_not_in'':
    forall m trs trs' reg0 regs vl a v,
      list_forall2 (match_reg_val' m (trs # a <- v) trs' reg0) regs vl ->
      ~ In a (fold_right (fun x acc => match x with | inl r => r::acc | inr (r, r') => r::r'::acc end) nil regs) ->
      a <> reg0 ->
      list_forall2 (match_reg_val' m trs trs' reg0) regs vl.
Proof.
    induction 1; intros.
    - econstructor.
    - econstructor; eauto.
      + unfold match_reg_val'. unfold match_reg_val' in H.
        destruct a1; destruct b1; auto.
        * rewrite PMap.gso in H; auto.
        * destruct p. destruct p0. rewrite ! PMap.gso in H; destruct H; auto; intro; subst a; eapply H1.
      + eapply IHlist_forall2. simpl in H1. destruct a1.
        * intro. eapply H1. right; auto.
        * intro. eapply H1. destruct p. right. right. auto.
        * auto.
  Qed.

  Lemma list_forall2_not_in_2:
    forall m trs trs' reg0 regs vl a v,
      list_forall2 (match_reg_val' m trs trs' reg0) regs vl ->
      ~ In a (fold_right (fun x acc => match x with | inl r => r::acc | inr (r, r') => r::r'::acc end) nil regs) ->
      list_forall2 (match_reg_val' m trs (trs'#a <- v) reg0) regs vl.
Proof.
    induction 1; intros.
    - econstructor.
    - econstructor; eauto.
      + unfold match_reg_val'. unfold match_reg_val' in H.
        destruct a1; destruct b1; auto.
        * rewrite PMap.gso; auto.
          simpl in H1. intro; eapply H1; auto.
        * destruct p. destruct p0. rewrite PMap.gso; destruct H; auto; intro; subst a; eapply H1.
          simpl. auto.
      + eapply IHlist_forall2. simpl in H1. destruct a1.
        * intro. eapply H1. right; auto.
        * intro. eapply H1. destruct p. right. right. auto.
  Qed.

  Lemma tr_cmp_regs_correct_singleton:
    forall j ts sp f tf reg0 regs pc1 pc2 pcs m rs trs vals,
      tr_cmp_regs' (fn_code tf) pc1 reg0 regs pc2 pcs ->
      ~ In reg0 (fold_right (fun x acc => match x with | inl r => r::acc | inr (r, r') => r::r'::acc end) nil regs) ->
      list_forall2 (match_reg_val trs) regs vals ->
      regs_agree j (max_reg_function f) rs trs ->
      (forall r, In r regs -> match r with | inl r => Plt (max_reg_function f) r | inr (r, r') => Plt (max_reg_function f) r /\ Plt (max_reg_function f) r' end) ->
      (forall r, Plt (max_reg_function f) r -> rs#r = Vundef) ->
      list_norepet (fold_right (fun x acc => match x with | inl r => r::acc | inr (r, r') => r::r'::acc end) nil regs) ->
      exists trs', star step tge (State ts tf sp pc1 trs m) E0 (State ts tf sp pc2 trs' m) /\
              list_forall2 (match_reg_val' m trs trs' reg0) regs vals /\
              forall reg, ~ In reg (fold_right (fun x acc => match x with | inl r => r::acc | inr (r, r') => r::r'::acc end) nil regs) -> trs#reg = trs'#reg.
Proof.
    induction regs; intros.
    - inv H. inv H1.
      exists trs; repeat split; econstructor; eauto.
    - inv H.
      + inv H1. assert (regs_agree j (max_reg_function f) rs (trs # reg2 <- (Val.of_optbool (eval_condition (Ccompu Ceq) (trs # reg2 :: trs # reg0 :: nil) m)))).
        { unfold regs_agree; intros.
          destruct (plt (max_reg_function f) r).
          - right; split; auto. rewrite H4; auto.
          - generalize (H3 (inl reg2) (in_eq _ _)); intros.
            left; split; try xomega. rewrite PMap.gso; try xomega.
            generalize (H2 r); intros [[HA HB] | [HA HB]]; try xomega; auto. }
        simpl in H0. eapply not_in_cons in H0. destruct H0.
        exploit (IHregs (Psucc pc1) pc2 pcs0 m rs (trs # reg2 <- (Val.of_optbool (eval_condition (Ccompu Ceq) (trs # reg2 :: trs # reg0 :: nil) m))) bl H14 H1).
        { eapply list_forall2_not_in'; eauto. simpl in H5. inv H5; auto. }
        { exact H. }
        { intros. eapply H3. eapply in_cons; auto. }
        { exact H4. }
        { simpl in H5. inv H5; auto. }
        intros [trs' [A [B C]]]. exists trs'; repeat split.
        * eapply star_trans; eauto. eapply star_one. eapply exec_Iop; eauto.
          unfold eval_operation; eauto.
        * econstructor; eauto.
          { simpl. rewrite <- C; eauto. simpl in H7.
            destruct b1; auto. rewrite PMap.gss. simpl. rewrite H7. reflexivity.
            simpl in H5. inv H5. auto. }
          { eapply list_forall2_not_in''; eauto. simpl in H5; inv H5; auto. }
        * intros. rewrite <- C; eauto. rewrite PMap.gso; eauto.
          intro. eapply H6; left; auto. intro. eapply H6; right; auto.
      + inv H1. assert (regs_agree j (max_reg_function f) rs (((trs # reg2 <- (Val.of_optbool (Val.cmpu_bool (Mem.valid_pointer m) Cle trs # reg2 trs # reg0))) # reg3 <- (Val.of_optbool (Val.cmpu_bool (Mem.valid_pointer m) Cle trs # reg0 trs # reg3))) # reg2 <- (Val.and (Val.of_optbool (Val.cmpu_bool (Mem.valid_pointer m) Cle trs # reg2 trs # reg0)) (Val.of_optbool (Val.cmpu_bool (Mem.valid_pointer m) Cle trs # reg0 trs # reg3))))).
        { unfold regs_agree; intros.
          destruct (plt (max_reg_function f) r).
          - right; split; auto. rewrite H4; auto.
          - generalize (H3 _ (in_eq _ _)). intros [A B].
            left; split; try xomega. rewrite ! PMap.gso; try xomega.
            generalize (H2 r); intros [[HA HB] | [HA HB]]; try xomega; auto. }
        eapply not_in_cons in H0. destruct H0. eapply not_in_cons in H1. destruct H1.
        exploit (IHregs (Psucc (Psucc (Psucc pc1))) pc2 pcs0 m rs (((trs # reg2 <- (Val.of_optbool (Val.cmpu_bool (Mem.valid_pointer m) Cle trs # reg2 trs # reg0))) # reg3 <- (Val.of_optbool (Val.cmpu_bool (Mem.valid_pointer m) Cle trs # reg0 trs # reg3))) # reg2 <- (Val.and (Val.of_optbool (Val.cmpu_bool (Mem.valid_pointer m) Cle trs # reg2 trs # reg0)) (Val.of_optbool (Val.cmpu_bool (Mem.valid_pointer m) Cle trs # reg0 trs # reg3)))) bl H16 H6).
        { eapply list_forall2_not_in'; eauto.
          eapply list_forall2_not_in'; eauto.
          eapply list_forall2_not_in'; eauto.
          inv H5. intro. eapply H14; right; auto.
          inv H5. inv H15. intro. eapply H12; auto.
          inv H5. intro. eapply H14; right; auto. }
        { exact H. }
        { intros. eapply H3. right; auto. }
        { exact H4. }
        { simpl in H5. inv H5; inv H15; auto. }
        intros [trs' [A [B C]]]. exists trs'; repeat split.
        * eapply star_trans; eauto. eapply star_step.
          eapply exec_Iop; eauto. simpl. eauto. eapply star_step.
          eapply exec_Iop; eauto. simpl. rewrite PMap.gso; auto. eapply star_step.
          eapply exec_Iop; eauto. simpl. rewrite ! PMap.gss. rewrite PMap.gso. rewrite PMap.gss. rewrite ! PMap.gso. eauto.
          inv H5. intro. eapply H14; left; auto.
          inv H5. intro. eapply H14; left; auto.
          rewrite PMap.gso. eapply star_refl.
          inv H5. intro. eapply H14; left; auto. eauto. eauto. eauto. eauto.
        * econstructor; eauto.
          simpl. simpl in H7. destruct b1; auto. destruct p. rewrite <- C.
          rewrite PMap.gss. destruct H7. rewrite H7, H10. auto.
          inv H5; intro. eapply H14; right; auto.
          eapply list_forall2_not_in''. eapply list_forall2_not_in''. eapply list_forall2_not_in''; eauto.
          inv H5; intro. eapply H14; right; auto.
          inv H5; intro. inv H15. eapply H17; auto. auto.
          inv H5; intro. eapply H14; right; auto. auto.
        * intros. rewrite <- C; eauto. repeat rewrite PMap.gso; auto.
          intro. eapply H10. left; auto.
          intro. eapply H10. right; left; auto.
          intro. eapply H10. left; auto.
          intro. eapply H10. right; right; auto.
  Qed.

  Lemma tr_or_regs_true:
    forall ts tf m regs pc1 reg0 pc2 pcs sp trs,
      tr_or_regs (fn_code tf) pc1 reg0 regs pc2 pcs ->
      (forall r, In r regs -> trs#r = Vtrue \/ trs#r = Vfalse) ->
      ~ In reg0 regs ->
      trs#reg0 = Vtrue ->
      exists trs', star step tge (State ts tf (Vptr sp Int.zero) pc1 trs m) E0 (State ts tf (Vptr sp Int.zero) pc2 trs' m) /\ trs'#reg0 = Vtrue /\ forall r, r <> reg0 -> trs'#r = trs#r.
Proof.
    induction regs; intros.
    - inv H; exists trs; split; auto.
      eapply star_refl.
    - inv H. exploit (IHregs (Psucc pc1) reg0 pc2 pcs0 sp (trs # reg0 <- (Val.or trs # reg0 trs # a)) H11).
      + intros. rewrite PMap.gso; eauto.
        * eapply H0. eapply in_cons; eauto.
        * rewrite not_in_cons in H1. destruct H1; eauto.
          destruct (peq reg0 r); try congruence.
      + rewrite not_in_cons in H1; destruct H1; eauto.
      + rewrite H2. generalize (H0 a (in_eq _ _)). intros [A | A].
        * rewrite A; simpl. rewrite PMap.gss. reflexivity.
        * rewrite A; simpl. rewrite PMap.gss. reflexivity.
      + intros [trs' [A [B C]]].
        exists trs'; repeat split; eauto.
        * eapply star_step; eauto.
          { eapply exec_Iop; eauto. }
          { auto. }
        * intros. rewrite (C r H). rewrite PMap.gso; eauto.
  Qed.
  
  Lemma tr_or_regs_correct:
    forall ts tf m regs pc1 reg0 pc2 pcs sp trs,
      tr_or_regs (fn_code tf) pc1 reg0 regs pc2 pcs ->
      (forall r, In r regs -> trs#r = Vtrue \/ trs#r = Vfalse) ->
      ~ In reg0 regs ->
      (exists r, In r regs /\ trs#r = Vtrue) ->
      trs#reg0 = Vtrue \/ trs#reg0 = Vfalse ->
      exists trs', star step tge (State ts tf (Vptr sp Int.zero) pc1 trs m) E0 (State ts tf (Vptr sp Int.zero) pc2 trs' m) /\ trs'#reg0 = Vtrue /\ forall r, r <> reg0 -> trs'#r = trs#r.
Proof.
    induction regs; intros.
    - inv H. destruct H2 as [r [HA HB]]. inv HA.
    - destruct H3.
      + eapply tr_or_regs_true; eauto.
      + destruct H2 as [r [A B]]. destruct A as [A | A].
        * inv A. inv H.
          exploit (tr_or_regs_true ts tf m regs (Psucc pc1) reg0 pc2 pcs0 sp (trs # reg0 <- (Val.or trs # reg0 trs # r)) H11).
          { intros. rewrite PMap.gso; eauto.
            - eapply H0; eapply in_cons; eauto.
            - rewrite not_in_cons in H1; destruct H1. destruct (peq r0 reg0); congruence. }
          { rewrite not_in_cons in H1; destruct H1; assumption. }
          { rewrite B. rewrite H3. rewrite PMap.gss. reflexivity. }
          { intros [trs' [HA [HB HC]]]. exists trs'; repeat split; eauto.
            - eapply star_step; eauto.
              + eapply exec_Iop; eauto.
              + auto.
            - intros. rewrite (HC r0 H). rewrite PMap.gso; eauto. }
        * inv H. exploit (IHregs (Psucc pc1) reg0 pc2 pcs0 sp (trs#reg0 <- (Val.or trs#reg0 trs#a)) H11).
          { intros. rewrite PMap.gso; eauto.
            - eapply H0; eapply in_cons; eauto.
            - rewrite not_in_cons in H1; destruct H1.
              destruct (peq r0 reg0); congruence. }
          { rewrite not_in_cons in H1; destruct H1; assumption. }
          { exists r; split; auto. rewrite PMap.gso; eauto.
            rewrite not_in_cons in H1; destruct H1; destruct (peq r reg0); congruence. }
          { rewrite H3. generalize (H0 a (in_eq _ _)). intros [HA | HA].
            - rewrite HA. rewrite PMap.gss. auto.
            - rewrite HA. rewrite PMap.gss. auto. }
          { intros [trs' [HA [HB HC]]].
            exists trs'; repeat split; auto.
            - eapply star_step; eauto.
              + eapply exec_Iop; eauto.
              + auto.
            - intros. rewrite (HC r0 H). rewrite PMap.gso; eauto. }
  Qed.
  
  Inductive match_stackframes: meminj -> stackframe -> stackframe -> Prop :=
  | match_stackframes_intro:
      forall j res f tf sp tsp pc rs trs
        (FUN: transf_function prog ge STK SIZE f = OK tf)
        (RES: regs_agree j (max_reg_function f) rs trs)
        (PLE: Ple res (max_reg_function f))
        (UNDEF: forall r, Plt (max_reg_function f) r -> rs#r = Vundef)
        (SPINJ: j sp = Some (tsp, 0)),
        match_stackframes j (Stackframe res f (Vptr sp Int.zero) pc rs)
                            (Stackframe res tf (Vptr tsp Int.zero) pc trs).

  Inductive match_states: RTL.state -> RTL.state -> Prop :=
  | match_regular_states:
      forall s ts f tf sp tsp pc rs trs j m tm
        (STACKS: list_forall2 (match_stackframes j) s ts)
        (FUN: transf_function prog ge STK SIZE f = OK tf)
        (RES: regs_agree j (max_reg_function f) rs trs)
        (STEP: forall s0, initial_state prog s0 -> exists t, star step_block' ge s0 t (State s f (Vptr sp Int.zero) pc rs m))
        (STEP': forall s0, initial_state tprog s0 -> exists t, star RTL.step tge s0 t (State ts tf (Vptr tsp Int.zero) pc trs tm))
        (UNDEF: forall r, Plt (max_reg_function f) r -> rs#r = Vundef)
        (MINJ: Mem.inject j m tm)
        (SPINJ: j sp = Some (tsp, 0))
        (GINJ: forall b, Plt b ge.(Genv.genv_next) -> j b = Some (b, 0))
        (STKNOTMAPPED: forall bSTK ofs, Genv.symbol_address tge STK ofs = Vptr bSTK ofs ->
                                   (forall b b' delta, j b = Some (b', delta) -> b' <> bSTK))
        (SIZENOTMAPPED: forall bSIZE ofs, Genv.symbol_address tge SIZE ofs = Vptr bSIZE ofs ->
                                     (forall b b' delta, j b = Some (b', delta) -> b' <> bSIZE))
        (BSTKPLT: forall bSTK, Genv.find_symbol tge STK = Some bSTK -> Plt bSTK (Mem.nextblock tm))
        (BSIZEPLT: forall bSIZE, Genv.find_symbol tge SIZE = Some bSIZE -> Plt bSIZE (Mem.nextblock tm))
        (STKPERM: forall bSTK, Genv.find_symbol tge STK = Some bSTK -> Mem.range_perm tm bSTK 0 512 Cur Writable)
        (SIZEPERM: forall bSIZE, Genv.find_symbol tge SIZE = Some bSIZE -> Mem.range_perm tm bSIZE 0 4 Cur Writable)
        (STKRANGE: forall bSTK, Genv.find_symbol tge STK = Some bSTK -> (forall ofs, Mem.perm tm bSTK ofs Cur Readable <-> 0 <= ofs < 512))
        (SIZERANGE: forall bSIZE, Genv.find_symbol tge SIZE = Some bSIZE -> (forall ofs, Mem.perm tm bSIZE ofs Cur Readable <-> 0 <= ofs < 4))
        (GINJ': forall b b' delta, Plt b ge.(Genv.genv_next) -> j b' = Some (b, delta) -> b = b')
        (NEXTBLOCK: Ple ge.(Genv.genv_next) (Mem.nextblock m))
        (NEXTBLOCK': Ple ge.(Genv.genv_next) (Mem.nextblock tm))
        (SHADOW: shadowstack_is_sound ((Vptr tsp Int.zero)::(List.map (fun s => match s with Stackframe res f sp pc rs => sp end) ts)) tm)
        (CALLSTACK: 4 * Z.of_nat (S (length s)) < 1024)
        (FLATINJ: forall b b' delta, j b = Some (b', delta) -> delta = 0)
        (FLATINJ': forall b1 b2 b, j b1 = Some (b, 0) -> j b2 = Some (b, 0) -> b1 = b2)
        (FLATPERM: forall b b' o k p, j b = Some (b', 0) -> (Mem.perm m b o k p <-> Mem.perm tm b' o k p)),
        match_states (State s f (Vptr sp Int.zero) pc rs m)
                     (State ts tf (Vptr tsp Int.zero) pc trs tm)
  | match_call_states:
      forall s ts f tf args targs j m tm
        (STACKS: list_forall2 (match_stackframes j) s ts)
        (FUN: transf_fundef prog ge STK SIZE f = OK tf)
        (STEP: forall s0, initial_state prog s0 -> exists t, star step_block' ge s0 t (Callstate s f args m))
        (STEP': forall s0, initial_state tprog s0 -> exists t, star RTL.step tge s0 t (Callstate ts tf targs tm))
        (MINJ: Mem.inject j m tm)
        (GINJ: forall b, Plt b ge.(Genv.genv_next) -> j b = Some (b, 0))
        (STKNOTMAPPED: forall bSTK ofs, Genv.symbol_address tge STK ofs = Vptr bSTK ofs ->
                                   (forall b b' delta, j b = Some (b', delta) -> b' <> bSTK))
        (SIZENOTMAPPED: forall bSIZE ofs, Genv.symbol_address tge SIZE ofs = Vptr bSIZE ofs ->
                                     (forall b b' delta, j b = Some (b', delta) -> b' <> bSIZE))
        (BSTKPLT: forall bSTK, Genv.find_symbol tge STK = Some bSTK -> Plt bSTK (Mem.nextblock tm))
        (BSIZEPLT: forall bSIZE, Genv.find_symbol tge SIZE = Some bSIZE -> Plt bSIZE (Mem.nextblock tm))
        (INJARGS: Val.inject_list j args targs)
        (STKPERM: forall bSTK, Genv.find_symbol tge STK = Some bSTK -> Mem.range_perm tm bSTK 0 512 Cur Writable)
        (SIZEPERM: forall bSIZE, Genv.find_symbol tge SIZE = Some bSIZE -> Mem.range_perm tm bSIZE 0 4 Cur Writable)
        (STKRANGE: forall bSTK, Genv.find_symbol tge STK = Some bSTK -> (forall ofs, Mem.perm tm bSTK ofs Cur Readable <-> 0 <= ofs < 512))
        (SIZERANGE: forall bSIZE, Genv.find_symbol tge SIZE = Some bSIZE -> (forall ofs, Mem.perm tm bSIZE ofs Cur Readable <-> 0 <= ofs < 4))
        (GINJ': forall b b' delta, Plt b ge.(Genv.genv_next) -> j b' = Some (b, delta) -> b = b')
        (NEXTBLOCK: Ple ge.(Genv.genv_next) (Mem.nextblock m))
        (NEXTBLOCK': Ple ge.(Genv.genv_next) (Mem.nextblock tm))
        (SHADOW: shadowstack_is_sound (List.map (fun s => match s with Stackframe res f sp pc rs => sp end) ts) tm)
        (CALLSTACK: 4 * Z.of_nat (length s) < 1024)
        (FLATINJ: forall b b' delta, j b = Some (b', delta) -> delta = 0)
        (FLATINJ': forall b1 b2 b, j b1 = Some (b, 0) -> j b2 = Some (b, 0) -> b1 = b2)
        (FLATPERM: forall b b' o k p, j b = Some (b', 0) -> (Mem.perm m b o k p <-> Mem.perm tm b' o k p)),
        match_states (Callstate s f args m)
                     (Callstate ts tf targs tm)
  | match_return_states:
      forall s ts v tv j m tm
        (STACKS: list_forall2 (match_stackframes j) s ts)
        (STEP: forall s0, initial_state prog s0 -> exists t, star step_block' ge s0 t (Returnstate s v m))
        (STEP': forall s0, initial_state tprog s0 -> exists t, star RTL.step tge s0 t (Returnstate ts tv tm))
        (MINJ: Mem.inject j m tm)
        (GINJ: forall b, Plt b ge.(Genv.genv_next) -> j b = Some (b, 0))
        (STKNOTMAPPED: forall bSTK ofs, Genv.symbol_address tge STK ofs = Vptr bSTK ofs ->
                                   (forall b b' delta, j b = Some (b', delta) -> b' <> bSTK))
        (SIZENOTMAPPED: forall bSIZE ofs, Genv.symbol_address tge SIZE ofs = Vptr bSIZE ofs ->
                                     (forall b b' delta, j b = Some (b', delta) -> b' <> bSIZE))
        (BSTKPLT: forall bSTK, Genv.find_symbol tge STK = Some bSTK -> Plt bSTK (Mem.nextblock tm))
        (BSIZEPLT: forall bSIZE, Genv.find_symbol tge SIZE = Some bSIZE -> Plt bSIZE (Mem.nextblock tm))
        (INJV: Val.inject j v tv)
        (STKPERM: forall bSTK, Genv.find_symbol tge STK = Some bSTK -> Mem.range_perm tm bSTK 0 512 Cur Writable)
        (SIZEPERM: forall bSIZE, Genv.find_symbol tge SIZE = Some bSIZE -> Mem.range_perm tm bSIZE 0 4 Cur Writable)
        (STKRANGE: forall bSTK, Genv.find_symbol tge STK = Some bSTK -> (forall ofs, Mem.perm tm bSTK ofs Cur Readable <-> 0 <= ofs < 512))
        (SIZERANGE: forall bSIZE, Genv.find_symbol tge SIZE = Some bSIZE -> (forall ofs, Mem.perm tm bSIZE ofs Cur Readable <-> 0 <= ofs < 4))
        (GINJ': forall b b' delta, Plt b ge.(Genv.genv_next) -> j b' = Some (b, delta) -> b = b')
        (NEXTBLOCK: Ple ge.(Genv.genv_next) (Mem.nextblock m))
        (NEXTBLOCK': Ple ge.(Genv.genv_next) (Mem.nextblock tm))
        (SHADOW: shadowstack_is_sound (List.map (fun s => match s with Stackframe res f sp pc rs => sp end) ts) tm)
        (CALLSTACK: 4 * Z.of_nat (length s) < 1024)
        (FLATINJ: forall b b' delta, j b = Some (b', delta) -> delta = 0)
        (FLATINJ': forall b1 b2 b, j b1 = Some (b, 0) -> j b2 = Some (b, 0) -> b1 = b2)
        (FLATPERM: forall b b' o k p, j b = Some (b', 0) -> (Mem.perm m b o k p <-> Mem.perm tm b' o k p)),
        match_states (Returnstate s v m)
                     (Returnstate ts tv tm).

  Lemma GINJ_implies:
    forall j,
      (forall b, Plt b ge.(Genv.genv_next) -> j b = Some (b, 0)) ->
      forall id b, Genv.find_symbol ge id = Some b -> j b = Some (b, 0).
Proof.
    intros. eapply H. eapply ge.(Genv.genv_symb_range); eauto.
  Qed.
  
  Lemma addr_of_annotations_translated:
    forall kappa j sps tsps alpha vals,
      list_forall2 (fun sp tsp => exists bsp btsp, sp = Vptr bsp Int.zero /\ tsp = Vptr btsp Int.zero /\ j bsp = Some (btsp, 0)) sps tsps ->
      (forall b id, Genv.find_symbol ge id = Some b -> j b = Some (b, 0)) ->
      addr_of_annotations kappa ge sps alpha vals ->
      exists tvals, addr_of_annotations kappa tge tsps alpha tvals /\ list_forall2 (Val.inject j) vals tvals.
Proof.
    induction 3; intros.
    - destruct IHaddr_of_annotations as [tvals [A B]].
      generalize (pop_inject j sps tsps sp H depth H2). intros [tsp [C [bsp [btsp [D [E F]]]]]].
      rewrite D in H3. generalize (addr_of_local_translated _ j _ _ _ _ _ F H3). intros [tvals' [X Y]].
      exists (tvals' ++ tvals). split.
      + econstructor; eauto. rewrite E; auto.
      + eapply list_forall2_app; eauto.
    - destruct IHaddr_of_annotations as [tvals [A B]].
      generalize (STK_SIZE_are_new _ _ H1); intros C.
      generalize (symbols_preserved _ C); intros D. rewrite H1 in D.
      generalize (addr_of_global_translated _ j _ _ _ _ (H0 id b H1) H3). intros [tvals' [X Y]].
      eexists. split.
      + econstructor; eauto.
      + eapply list_forall2_app; eauto.
    - exists nil; split; econstructor; eauto.
  Qed.

  Lemma symbol_address_inject:
    forall j id ofs,
      (forall b id, Genv.find_symbol ge id = Some b -> j b = Some (b, 0)) ->
      Val.inject j (Genv.symbol_address ge id ofs) (Genv.symbol_address tge id ofs).
Proof.
    intros. unfold Genv.symbol_address.
    destruct (Genv.find_symbol ge id) as [b|] eqn:FS; auto.
    generalize (symbols_preserved _ (STK_SIZE_are_new _ _ FS)). intros.
    rewrite <- H0 in FS. rewrite FS. econstructor.
    - eapply H. rewrite H0 in FS; eauto.
    - rewrite Int.add_zero. auto.
  Qed.

  Lemma match_stackframes_sps:
    forall j stk tstk,
      list_forall2 (match_stackframes j) stk tstk ->
      list_forall2 (fun sp tsp => exists bsp btsp, sp = Vptr bsp Int.zero /\ tsp = Vptr btsp Int.zero /\ j bsp = Some (btsp, 0)) (map (fun s => match s with | Stackframe _ _ sp _ _ => sp end) stk) (map (fun s => match s with | Stackframe _ _ sp _ _ => sp end) tstk).
Proof.
    induction 1; intros.
    - simpl. econstructor.
    - inv H; simpl. econstructor; eauto.
  Qed.

  Lemma match_stackframes_sps_are_ptrs:
    forall j stk tstk,
      list_forall2 (match_stackframes j) stk tstk ->
      (forall sp, In sp (map (fun s => match s with | Stackframe _ _ sp _ _ => sp end) tstk) ->
             exists b, sp = Vptr b Int.zero).
Proof.
    induction 1; intros.
    - simpl in H; inv H.
    - inv H; simpl in H1.
      destruct H1; eauto.
  Qed.

  Lemma match_stackframes_sps_are_ptrs':
    forall j stk tstk,
      list_forall2 (match_stackframes j) stk tstk ->
      (forall sp, In sp (map (fun s => match s with | Stackframe _ _ sp _ _ => sp end) stk) ->
             exists b, sp = Vptr b Int.zero).
Proof.
    induction 1; intros.
    - simpl in H; inv H.
    - inv H; simpl in H1.
      destruct H1; eauto.
  Qed.
  
  Lemma eval_condition_translated:
    forall j a ta m tm vals tvals,
      Val.inject j a ta ->
      Mem.inject j m tm ->
      list_forall2 (Val.inject j) vals tvals ->
      (forall v, In v vals -> exists b ofs, v = Vptr b ofs) ->
      (forall (b : block) (ofs : int), In (Vptr b ofs) vals -> eval_condition (Ccompu Ceq) (a :: Vptr b ofs :: nil) m = Some true \/ eval_condition (Ccompu Ceq) (a :: Vptr b ofs :: nil) m = Some false) ->
      (forall (tb : block) (tofs : int), In (Vptr tb tofs) tvals -> eval_condition (Ccompu Ceq) (ta :: Vptr tb tofs :: nil) tm = Some true \/ eval_condition (Ccompu Ceq) (ta :: Vptr tb tofs :: nil) tm = Some false).
Proof.
    induction vals; intros.
    - inv H1. inv H4.
    - inv H1. destruct H4.
      + subst b1. destruct (H2 a0 (in_eq _ _)) as [b [ofs A]]. subst a0.
        inv H7. destruct (H3 _ _ (in_eq _ _)) as [A | A].
        * left. refine (eval_condition_inject _ _ H0 A).
          econstructor; eauto.
        * right. refine (eval_condition_inject _ _ H0 A).
          econstructor; eauto.
      + eapply IHvals; eauto.
        * intros; eapply H2; simpl; eauto.
        * intros; eapply H3; simpl; eauto.
  Qed.

  Lemma not_is_trivial_annotation_implies:
    forall p alpha kappa addr,
      MoreRTL.is_trivial_annotation p alpha kappa addr = false ->
      snd alpha <> nil.
Proof.
    unfold not; intros.
    unfold MoreRTL.is_trivial_annotation in H.
    rewrite H0 in H. inv H.
  Qed.
  
  Lemma shadowstack_is_sound_store:
    forall bSTK bSIZE sps m kappa b ofs v m',
      shadowstack_is_sound sps m ->
      Mem.store kappa m b ofs v = Some m' ->
      Genv.find_symbol tge SIZE = Some bSIZE ->
      Genv.find_symbol tge STK = Some bSTK ->
      b <> bSIZE -> b <> bSTK ->
      shadowstack_is_sound sps m'.
Proof.
    induction 1; intros. destruct H as [A H].
    econstructor. split; intros.
    - unfold Genv.symbol_address in *. rewrite H1, H2 in *.
      unfold Mem.loadv in *; simpl in *.
      erewrite Mem.load_store_other; eauto.
    - split; intros.
      + generalize ((proj1 (H depth sp)) H5) ; intros B.
        unfold Genv.symbol_address in *. rewrite H1, H2 in *.
        unfold Mem.loadv in *; simpl in *.
        erewrite Mem.load_store_other; eauto.
      + unfold Genv.symbol_address in H, H5.
        rewrite H2 in H, H5. simpl in H, H5. unfold Mem.loadv in H, H5.
        erewrite Mem.load_store_other in H5; eauto.
        eapply H in H5. eauto.
  Qed.

  Lemma tr_or_regs_undef:
    forall ts tf m regs pc1 reg0 pc2 pcs sp trs,
      tr_or_regs (fn_code tf) pc1 reg0 regs pc2 pcs ->
      ~ In reg0 regs ->
      trs#reg0 = Vundef ->
      exists trs', star step tge (State ts tf (Vptr sp Int.zero) pc1 trs m) E0 (State ts tf (Vptr sp Int.zero) pc2 trs' m) /\ trs'#reg0 = Vundef /\ forall r, r <> reg0 -> trs'#r = trs#r.
Proof.
    induction regs; intros.
    - inv H; exists trs; split; auto.
      eapply star_refl.
    - inv H. exploit (IHregs (Psucc pc1) reg0 pc2 pcs0 sp (trs # reg0 <- (Val.or trs # reg0 trs # a)) H10).
      + rewrite not_in_cons in H0; destruct H0; eauto.
      + rewrite H1. simpl. rewrite PMap.gss; reflexivity.
      + intros [trs' [A [B C]]].
        exists trs'; repeat split; eauto.
        * eapply star_step; eauto.
          { eapply exec_Iop; eauto. }
          { auto. }
        * intros. rewrite (C r H). rewrite PMap.gso; eauto.
  Qed.

  Lemma tr_or_regs_undef':
    forall ts tf m regs pc1 reg0 pc2 pcs sp trs,
      tr_or_regs (fn_code tf) pc1 reg0 regs pc2 pcs ->
      ~ In reg0 regs ->
      (forall r, In r regs -> trs#r = Vtrue \/ trs#r = Vfalse \/ trs#r = Vundef) ->
      (exists r, trs#r = Vundef /\ In r regs) ->
      trs#reg0 = Vtrue \/ trs#reg0 = Vfalse ->
      exists trs', star step tge (State ts tf (Vptr sp Int.zero) pc1 trs m) E0 (State ts tf (Vptr sp Int.zero) pc2 trs' m) /\ trs'#reg0 = Vundef /\ forall r, r <> reg0 -> trs'#r = trs#r.
Proof.
    induction regs; intros.
    - destruct H2 as [r [A B]]; inv B.
    - inv H. destruct H2 as [r [HA HB]].
      simpl in HB. destruct HB as [HB | HB].
      + subst a. exploit (tr_or_regs_undef); eauto.
        * rewrite not_in_cons in H0; destruct H0; eauto.
        * instantiate (1 := trs#reg0 <- Vundef). rewrite PMap.gss; eauto.
        * intros [trs' [HC [HD HE]]].
          exists trs'; repeat split; eauto.
          { eapply star_left.
            - eapply exec_Iop; eauto.
              simpl. rewrite HA. destruct (trs#reg0); simpl; auto.
            - eapply HC.
            - auto. }
          { intros; rewrite HE; eauto.
            rewrite PMap.gso; eauto. }
      + generalize (H1 a (in_eq _ _)). intros [HC | [HC | HC]].
        * exploit (IHregs (Psucc pc1) reg0 pc2 pcs0 sp (trs # reg0 <- (Val.or trs # reg0 trs # a)) H12).
          { rewrite not_in_cons in H0; destruct H0; eauto. }
          { intros. rewrite not_in_cons in H0. destruct H0 as [H0 H0'].
            destruct (peq r0 reg0); try congruence. rewrite PMap.gso; eauto. eapply H1; eauto.
            eapply in_cons; eauto. }
          { exists r; split; auto. rewrite not_in_cons in H0. destruct H0 as [H0 H0'].
            destruct (peq r reg0); subst. intuition. rewrite PMap.gso; eauto. }
          { destruct H3 as [H3 | H3].
            - rewrite HC; rewrite H3; simpl. rewrite PMap.gss; auto.
            - rewrite HC; rewrite H3; simpl. rewrite PMap.gss; auto. }
          { intros [trs' [HD [HE HF]]].
            exists trs'; repeat split; eauto.
            - eapply star_left.
              + eapply exec_Iop; eauto.
                simpl. eauto.
              + eapply HD.
              + auto.
            - intros. rewrite HF; eauto. rewrite PMap.gso; eauto. }
        * exploit (IHregs (Psucc pc1) reg0 pc2 pcs0 sp (trs # reg0 <- (Val.or trs # reg0 trs # a)) H12).
          { rewrite not_in_cons in H0; destruct H0; eauto. }
          { intros. rewrite not_in_cons in H0. destruct H0 as [H0 H0'].
            destruct (peq r0 reg0); try congruence. rewrite PMap.gso; eauto. eapply H1; eauto.
            eapply in_cons; eauto. }
          { exists r; split; auto. rewrite not_in_cons in H0. destruct H0 as [H0 H0'].
            destruct (peq r reg0); subst. intuition. rewrite PMap.gso; eauto. }
          { destruct H3 as [H3 | H3].
            - rewrite HC; rewrite H3; simpl. rewrite PMap.gss; auto.
            - rewrite HC; rewrite H3; simpl. rewrite PMap.gss; auto. }
          { intros [trs' [HD [HE HF]]].
            exists trs'; repeat split; eauto.
            - eapply star_left.
              + eapply exec_Iop; eauto.
                simpl. eauto.
              + eapply HD.
              + auto.
            - intros. rewrite HF; eauto. rewrite PMap.gso; eauto. }
        * exploit (tr_or_regs_undef); eauto.
          { rewrite not_in_cons in H0; destruct H0; eauto. }
          {instantiate (1 := trs#reg0 <- Vundef). rewrite PMap.gss; eauto. }
          { intros [trs' [HF [HD HE]]].
            exists trs'; repeat split; eauto.
            - eapply star_left.
              + eapply exec_Iop; eauto.
                simpl. rewrite HC. destruct (trs#reg0); simpl; auto.
              + eapply HF.
              + auto.
            - intros; rewrite HE; eauto.
              rewrite PMap.gso; eauto. }
  Qed.

  Lemma not_undef:
    forall regs trs,
      (forall r, In r regs -> trs#r = Vtrue \/ trs#r = Vfalse \/ trs#r = Vundef) ->
      (~ (exists r, trs#r = Vundef /\ In r regs) <-> (forall r, In r regs -> trs#r = Vtrue \/ trs#r = Vfalse)).
Proof.
    intros; split; intros.
    - destruct (Val.eq trs#r Vundef).
      + exfalso. eapply H0. exists r; auto.
      + generalize (H r H1). intros [A | [A | A]]; auto; try congruence.
    - unfold not; intros [r [A B]].
      generalize (H0 r B). intros [C | C]; rewrite C in A; inv A.
  Qed.

  Lemma eval_condition_are_bools:
    forall regs vals a trs m,
      list_forall2 (fun reg val => trs#reg = Val.of_optbool (eval_condition (Ccompu Ceq) (a::val::nil) m)) regs vals ->
      (forall v, In v vals -> exists b ofs, v = Vptr b ofs) ->
      (forall r, In r regs -> trs#r = Vtrue \/ trs#r = Vfalse) ->
      forall b ofs, In (Vptr b ofs) vals -> eval_condition (Ccompu Ceq) (a::(Vptr b ofs)::nil) m = Some true \/
                                      eval_condition (Ccompu Ceq) (a::(Vptr b ofs)::nil) m = Some false.
Proof.
    induction regs; intros.
    - inv H; inv H2.
    - inv H. simpl in H2. destruct H2 as [H2 | H2].
      + subst b1. generalize (H1 a (in_eq _ _)). intros [A | A].
        * rewrite A in H5. destruct (eval_condition (Ccompu Ceq) (a0 :: Vptr b ofs :: nil) m); simpl in H5; inv H5.
          destruct b0; auto.
        * rewrite A in H5. destruct (eval_condition (Ccompu Ceq) (a0 :: Vptr b ofs :: nil) m); simpl in H5; inv H5.
          destruct b0; auto.
      + eapply IHregs; eauto.
        * intros. eapply H0; eauto. eapply in_cons; eauto.
        * intros; eapply H1; eauto. eapply in_cons; eauto.
  Qed.

  Lemma eval_condition_are_bools':
    forall reg0 regs vals trs trs' m,
      list_forall2 (match_reg_val' m trs trs' reg0) regs vals ->
      (forall v, In v vals -> match v with |inl v => exists b ofs, v = Vptr b ofs | inr (v, v') => exists b ofs ofs', v = Vptr b ofs /\ v' = Vptr b ofs' end) ->
      (forall r, In r regs -> match r with inl r => trs'#r = Vtrue \/ trs'#r = Vfalse | inr (r, r') => trs'#r = Vtrue \/ trs'#r = Vfalse end) ->
      forall v, In v vals -> match v with
                       | inl v => eval_condition (Ccompu Ceq) (v::trs#reg0::nil) m = Some true \/
                                 eval_condition (Ccompu Ceq) (v::trs#reg0::nil) m = Some false
                       | inr (v, v') => Val.and (Val.of_optbool (Val.cmpu_bool (Mem.valid_pointer m) Cle v trs # reg0))
                                               (Val.of_optbool (Val.cmpu_bool (Mem.valid_pointer m) Cle trs # reg0 v')) = Vtrue \/
                                       Val.and (Val.of_optbool (Val.cmpu_bool (Mem.valid_pointer m) Cle v trs # reg0))
                                               (Val.of_optbool (Val.cmpu_bool (Mem.valid_pointer m) Cle trs # reg0 v')) = Vfalse
                       end.
Proof.
    induction 1; intros.
    - inv H1.
    - destruct H3.
      + subst b1. destruct v.
        * generalize (H1 _ (in_eq _ _)). intros [b [ofs A]]. subst v.
          generalize (H2 _ (in_eq _ _)). unfold match_reg_val' in H.
          destruct a1.
          { unfold eval_condition. unfold eval_condition in H. intros.
            destruct H3; rewrite H3 in H.
            - left. destruct (Val.cmpu_bool (Mem.valid_pointer m) Ceq (Vptr b ofs) trs # reg0); simpl in H.
              + destruct b0; inv H; auto.
              + inv H.
            - right. destruct (Val.cmpu_bool (Mem.valid_pointer m) Ceq (Vptr b ofs) trs # reg0); simpl in H.
              + destruct b0; inv H; auto.
              + inv H. }
          { destruct p; inv H. }
        * destruct p. generalize (H1 _ (in_eq _ _)). intros [b [ofs [ofs' [A B]]]]. subst v. subst v0.
          generalize (H2 _ (in_eq _ _)). unfold match_reg_val' in H.
          destruct a1.
          { inv H. }
          { destruct p. rewrite <- ! H. auto. }
      + eapply IHlist_forall2; eauto.
        * intros. eapply H1; right; auto.
        * intros. eapply H2; right; auto.
  Qed.

  Lemma eval_condition_are_false:
    forall regs vals b ofs trs m,
      list_forall2 (fun reg val => trs#reg = Val.of_optbool (eval_condition (Ccompu Ceq) ((Vptr b ofs)::val::nil) m)) regs vals ->
      (forall v, In v vals -> exists b ofs, v = Vptr b ofs) ->
      (forall r, In r regs -> trs#r = Vtrue \/ trs#r = Vfalse) ->
      ~ In (Vptr b ofs) vals ->
      forall r, In r regs -> trs#r = Vfalse.
Proof.
    induction regs; intros.
    - inv H3.
    - inv H; simpl in H3; destruct H3 as [H3 | H3].
      + subst a. generalize (H1 r (in_eq _ _)); intros [A | A]; auto.
        rewrite A in H6.
        generalize (H0 b1 (in_eq _ _)). intros [b' [ofs' B]]. rewrite B in H6.
        simpl in H6. rewrite not_in_cons in H2. destruct H2 as [XX YY].
        rewrite B in XX. destruct (eq_block b b').
        * destruct ((Mem.valid_pointer m b (Int.unsigned ofs) || Mem.valid_pointer m b (Int.unsigned ofs - 1)) && (Mem.valid_pointer m b' (Int.unsigned ofs') || Mem.valid_pointer m b' (Int.unsigned ofs' - 1))).
          { simpl in H6. generalize (Int.eq_spec ofs ofs'); intros.
            destruct (Int.eq ofs ofs').
            - subst. congruence.
            - inv H6. }
          { simpl in H6; inv H6. }
        * destruct (Mem.valid_pointer m b (Int.unsigned ofs) && Mem.valid_pointer m b' (Int.unsigned ofs')); simpl in H6; inv H6.
      + eapply IHregs; eauto.
        * intros; eapply H0; eauto. eapply in_cons; eauto.
        * intros; eapply H1; eauto. eapply in_cons; eauto.
        * rewrite not_in_cons in H2; destruct H2; auto.
  Qed.

  Lemma tr_or_regs_false:
    forall ts tf m regs pc1 reg0 pc2 pcs sp trs,
      tr_or_regs (fn_code tf) pc1 reg0 regs pc2 pcs ->
      ~ In reg0 regs ->
      (forall r, In r regs -> trs#r = Vfalse) ->
      trs#reg0 = Vfalse ->
      exists trs', star step tge (State ts tf (Vptr sp Int.zero) pc1 trs m) E0 (State ts tf (Vptr sp Int.zero) pc2 trs' m) /\ trs'#reg0 = Vfalse /\ forall r, r <> reg0 -> trs'#r = trs#r.
Proof.
    induction regs; intros.
    - inv H. exists trs; split; auto.
      eapply star_refl.
    - inv H. rewrite not_in_cons in H0. destruct H0.
      exploit (IHregs (Psucc pc1) reg0 pc2 pcs0 sp (trs#reg0 <- Vfalse) H11 H0).
      + intros. destruct (peq r reg0); try congruence.
        rewrite PMap.gso; eauto. eapply (H1 r (in_cons _ _ _ H3)).
      + rewrite PMap.gss; eauto.
      + intros [trs' [A [B C]]].
        exists trs'; repeat split; eauto.
        * eapply star_left; eauto.
          { eapply exec_Iop; eauto.
            simpl. rewrite H2. rewrite (H1 a (in_eq _ _)). simpl. reflexivity. }
          { auto. }
        * intros. rewrite C; auto.
          rewrite PMap.gso; eauto.
  Qed.

  Lemma regs_are_unknown:
    forall m kappa a v trs regs vals,
      Mem.loadv kappa m a = Some v ->
      list_forall2 (fun reg val => trs # reg = Val.of_optbool (eval_condition (Ccompu Ceq) (a::val::nil) m)) regs vals ->
      (forall v, In v vals -> exists b ofs, v = Vptr b ofs) ->
      forall r, In r regs -> trs#r = Vtrue \/ trs#r = Vfalse \/ trs#r = Vundef.
Proof.
    induction regs; intros.
    - inv H0. inv H2.
    - destruct a; simpl in H; inv H.
      generalize (load_valid_pointer _ _ _ _ _ H4); intros.
      inv H0. simpl in H2. destruct H2.
      + inv H0. rewrite H6.
        destruct (eval_condition (Ccompu Ceq) (Vptr b i :: b1 :: nil) m); eauto.
        destruct b0; eauto.
      + eapply IHregs; eauto.
        intros. eapply H1; eauto. eapply in_cons; eauto.
  Qed.

  Lemma regs_are_unknown_2:
    forall m trs trs' r0 regs vals,
      list_forall2 (match_reg_val' m trs trs' r0) regs vals ->
      forall r, In r (map (fun r => match r with inl r => r | inr r => fst r end) regs) -> trs'#r = Vtrue \/ trs'#r = Vfalse \/ trs'#r = Vundef.
Proof.
    induction regs; intros.
    - simpl in H0. inv H0.
    - destruct a.
      + simpl in H0. destruct H0.
        * subst r1. inv H.
          simpl in H2. destruct b1; auto.
          { rewrite ! H2. destruct (Val.cmpu_bool (Mem.valid_pointer m) Ceq v trs#r0); simpl; auto.
            destruct b; simpl; auto. }
          { inv H2. }
        * inv H. eapply IHregs; eauto.
      + destruct p. simpl in H0. destruct H0.
        * subst r1. inv H.
          simpl in H2. destruct b1; auto.
          { inv H2. }
          { destruct p. rewrite ! H2. destruct (Val.cmpu_bool (Mem.valid_pointer m) Cle v trs#r0); simpl; auto.
            destruct (Val.cmpu_bool (Mem.valid_pointer m) Cle trs#r0 v0); simpl; auto.
            - destruct b; destruct b0; simpl; auto.
            - destruct b; simpl; auto. }
        * inv H. eapply IHregs; eauto.
  Qed.

  Lemma regs_are_unknown':
    forall m kappa a v m' trs regs vals,
      Mem.storev kappa m a v = Some m' ->
      list_forall2 (fun reg val => trs # reg = Val.of_optbool (eval_condition (Ccompu Ceq) (a::val::nil) m)) regs vals ->
      (forall v, In v vals -> exists b ofs, v = Vptr b ofs) ->
      forall r, In r regs -> trs#r = Vtrue \/ trs#r = Vfalse \/ trs#r = Vundef.
Proof.
    induction regs; intros.
    - inv H0. inv H2.
    - destruct a; simpl in H; inv H.
      generalize (store_valid_pointer _ _ _ _ _ _ H4); intros.
      inv H0. simpl in H2. destruct H2.
      + inv H0. rewrite H6.
        destruct (eval_condition (Ccompu Ceq) (Vptr b i :: b1 :: nil) m); eauto.
        destruct b0; eauto.
      + eapply IHregs; eauto.
        intros. eapply H1; eauto. eapply in_cons; eauto.
  Qed.

  Lemma list_forall2_in_1:
    forall A B P l1 l2 (x: A),
      list_forall2 P l1 l2 ->
      In x l1 ->
      exists (y: B), In y l2 /\ P x y.
Proof.
    induction 1; intros.
    - inv H.
    - destruct H1 as [H1 | H1].
      + subst a1.
        exists b1; split; eauto. eapply in_eq.
      + eapply IHlist_forall2 in H1; destruct H1 as [y [HA HB]].
        exists y; split; eauto. eapply in_cons; eauto.
  Qed.

  Lemma list_forall2_in_2:
    forall A B P l1 l2 (y: B),
      list_forall2 P l1 l2 ->
      In y l2 ->
      exists (x: A), In x l1 /\ P x y.
Proof.
    induction 1; intros.
    - inv H.
    - destruct H1 as [H1 | H1].
      + subst b1.
        exists a1; split; eauto. eapply in_eq.
      + eapply IHlist_forall2 in H1; destruct H1 as [x [HA HB]].
        exists x; split; eauto. eapply in_cons; eauto.
  Qed.

  Lemma is_singleton_implies:
    forall alpha,
      is_singleton alpha = true ->
      (exists d id, forall a, In a alpha -> exists ofs, a = ABlocal d id ofs) \/
      (exists id, forall a, In a alpha -> exists ofs, a = ABglobal id ofs).
Proof.
    destruct alpha; intros.
    - simpl in H; inv H.
    - simpl in H. destruct a.
      + destruct alpha.
        * left. simpl. eexists. eexists. intros.
          destruct H0 as [A | A]; eauto. inv A.
        * assert (HA: fold_left (fun (acc : bool) (x : ablock) => match x with | ABlocal d' id' _ => eq_nat_dec depth d' && ident_eq varname id' && acc | ABglobal _ _ => false end) alpha false = false).
          { clear H; induction alpha; simpl; eauto. destruct a0; auto.
            repeat (rewrite andb_false_r); auto. }
          left. simpl in H. destruct a.
          { exists depth, varname. intros. simpl in H0.
            destruct H0 as [A | [A | A]]; eauto.
            - rewrite <- A. destruct (eq_nat_dec depth depth0).
              + subst depth0. destruct (ident_eq varname varname0).
                * subst varname0. eauto.
                * simpl in H. rewrite HA in H; inv H.
              + simpl in H. rewrite HA in H; inv H.
            - destruct (eq_nat_dec depth depth0); destruct (ident_eq varname varname0); simpl in H; try (rewrite HA in H; inv H; fail).
              subst varname0; subst depth0. induction alpha.
              + inv A.
              + destruct A.
                * simpl in H. subst a0. destruct a; simpl in H.
                  { simpl in HA. destruct (eq_nat_dec depth depth0); destruct (ident_eq varname varname0); simpl in H; simpl in HA.
                    - subst; eauto.
                    - rewrite HA in H; inv H.
                    - rewrite HA in H; inv H.
                    - rewrite HA in H; inv H. }
                  { simpl in HA; rewrite HA in H; inv H. }
                * eapply IHalpha; eauto.
                  { destruct a0; simpl in H; simpl in HA.
                    - destruct (eq_nat_dec depth depth0); destruct (ident_eq varname varname0); simpl in H; simpl in HA.
                      + subst; eauto.
                      + rewrite HA in H; inv H.
                      + rewrite HA in H; inv H.
                      + rewrite HA in H; inv H.
                    - rewrite HA in H; inv H. }
                  { destruct a0; simpl in H; simpl in HA.
                    - destruct (eq_nat_dec depth depth0); destruct (ident_eq varname varname0); simpl in H; simpl in HA.
                      + subst; eauto.
                      + rewrite HA in H; inv H.
                      + rewrite HA in H; inv H.
                      + rewrite HA in H; inv H.
                    - rewrite HA in H; inv H. } }
          { rewrite HA in H; inv H. }
      + destruct alpha.
        * right. simpl. eexists. intros.
          destruct H0 as [A | A]; eauto. inv A.
        * assert (HA: fold_left (fun (acc : bool) (x : ablock) => match x with | ABlocal _ _ _ => false | ABglobal id' _ => ident_eq b id' && acc end) alpha false = false).
          { clear H; induction alpha; simpl; eauto. destruct a0; auto.
            repeat (rewrite andb_false_r); auto. }
          right; simpl in H. destruct a.
          { rewrite HA in H; inv H. }
          { exists b. intros; simpl in H0. destruct H0 as [A | [A | A]]; eauto.
            - destruct (ident_eq b b0); subst; eauto.
              simpl in H; rewrite HA in H; inv H.
            - destruct (ident_eq b b0); subst; simpl in H; try (rewrite HA in H; inv H; fail).
              induction alpha.
              + inv A.
              + destruct A.
                * simpl in H. subst a0. destruct a; simpl in H.
                  { simpl in HA. rewrite HA in H; inv H. }
                  { simpl in HA. destruct (ident_eq b0 b); simpl in H; simpl in HA.
                    - subst; eauto.
                    - rewrite HA in H; inv H. }
                * eapply IHalpha; eauto.
                  { destruct a0; simpl in H; simpl in HA.
                    - rewrite HA in H; inv H.
                    - destruct (ident_eq b0 b); simpl in H; simpl in HA.
                      + subst; eauto.
                      + rewrite HA in H; inv H. }
                  { destruct a0; simpl in H; simpl in HA.
                    - rewrite HA in H; inv H.
                    - destruct (ident_eq b0 b); simpl in H; simpl in HA.
                      + subst; eauto.
                      + rewrite HA in H; inv H. } }
  Qed.

  Lemma addr_of_local_are_ptrs':
    forall kappa sp o n ofs vals,
      addr_of_local kappa (Vptr sp o) ofs n vals ->
      forall v, In v vals -> exists ofs, v = Vptr sp ofs.
Proof.
    induction n; intros.
    - inv H; inv H0.
    - inv H. destruct (ArithLib.Zdivides_dec (align_chunk kappa) (Int.unsigned ofs)).
      { simpl in H0; destruct H0.
        + inv H; eauto.
        + eapply IHn; eauto. }
      { eapply IHn; eauto. }
  Qed.

  Lemma addr_of_global_are_ptrs':
    forall kappa b n ofs vals,
      addr_of_global kappa b ofs n vals ->
      forall v, In v vals -> exists ofs, v = Vptr b ofs.
Proof.
    induction n; intros.
    - inv H; inv H0.
    - inv H. destruct (ArithLib.Zdivides_dec (align_chunk kappa) (Int.unsigned ofs)).
      { simpl in H0; destruct H0.
        + inv H; eauto.
        + eapply IHn; eauto. }
      { eapply IHn; eauto. }
  Qed.

  Lemma addr_of_local_exists':
    forall kappa sp o n ofs vals,
      check_annotations_divides' kappa ofs n = OK tt ->
      addr_of_local kappa (Vptr sp o) ofs n vals ->
      exists v, In v vals.
Proof.
    induction n; intros.
    - simpl in H. inv H.
    - simpl in H. inv H0.
      destruct (ArithLib.Zdivides_dec (align_chunk kappa) (Int.unsigned ofs)); eauto.
      eexists. eapply in_eq.
  Qed.

  Lemma addr_of_global_exists':
    forall kappa b n ofs vals,
      check_annotations_divides' kappa ofs n = OK tt ->
      addr_of_global kappa b ofs n vals ->
      exists v, In v vals.
Proof.
    induction n; intros.
    - simpl in H. inv H.
    - simpl in H. inv H0.
      destruct (ArithLib.Zdivides_dec (align_chunk kappa) (Int.unsigned ofs)); eauto.
      eexists. eapply in_eq.
  Qed.

  Lemma addr_of_annotations_singleton':
    forall kappa ge sps alpha vals (Hdivides: check_annotations_divides kappa alpha = OK tt),
      (forall sp, In sp sps -> exists b, sp = Vptr b Int.zero) ->
      addr_of_annotations kappa ge sps alpha vals ->
      is_singleton alpha = true ->
      exists b, forall v, In v vals -> exists ofs, v = Vptr b ofs.
Proof.
    intros. generalize (is_singleton_implies _ H1). intros [HA | HA].
    - destruct HA as [d [id HA]].
      clear H1. induction H0.
      + exploit IHaddr_of_annotations.
        * monadInv Hdivides. destruct x; auto.
        * intros; eapply HA. right; auto.
        * intros [b HB]. destruct alpha.
          { inv H3. rewrite app_nil_r.
            generalize (pop_is_in _ _ _ H1); intros HC. eapply H in HC. destruct HC as [b' HC].
            exists b'. subst sp. eapply addr_of_local_are_ptrs'; eauto. }
          { generalize (HA a (in_cons _ _ _ (in_eq _ _))). intros [o HD]. subst a.
            exists b. intros. eapply in_app in H4. destruct H4.
            - generalize (pop_is_in _ _ _ H1); intros HC. eapply H in HC. destruct HC as [b' HC].
              subst sp. generalize (HA _ (in_eq _ _)). intros [o' HD]. inv HD.
              inv H3. rewrite H11 in H1; inv H1. generalize (addr_of_local_are_ptrs' _ _ _ _ _ _ H2). intros HD.
              generalize (addr_of_local_are_ptrs' _ _ _ _ _ _ H12). intros HE.
              simpl in Hdivides. rewrite H9 in Hdivides. rewrite H0 in Hdivides. monadInv Hdivides. monadInv EQ.
              destruct x. generalize (addr_of_local_exists' _ _ _ _ _ _ EQ2 H12).
              intros [v0 Hv0]. generalize (HE v0 Hv0). generalize (HB v0 (in_or_app _ _ _ (or_introl Hv0))).
              intros [ofs1 ZA]. intros [ofs2 ZB]. rewrite ZB in ZA; inv ZA. eapply HD; eauto.
            - eapply HB; eauto. }
      + generalize (HA _ (in_eq _ _)). intros [ofs OO]. inv OO.
      + exists xH. intros. inv H0.
    - destruct HA as [id HA].
      clear H1. induction H0.
      + generalize (HA _ (in_eq _ _)). intros [ofs OO]. inv OO.
      + exploit IHaddr_of_annotations.
        * monadInv Hdivides. destruct x; auto.
        * intros; eapply HA. right; auto.
        * intros [b' HB]. destruct alpha.
          { inv H3. rewrite app_nil_r.
            exists id0. eapply addr_of_global_are_ptrs'; eauto. }
          { generalize (HA a (in_cons _ _ _ (in_eq _ _))). intros [o HD]. subst a.
            exists b'. intros. eapply in_app in H4. destruct H4.
            - generalize (HA _ (in_eq _ _)). intros [o' HD]. inv HD.
              inv H3. rewrite H8 in H0; inv H0. generalize (addr_of_global_are_ptrs' _ _ _ _ _ H2). intros HD.
              generalize (addr_of_global_are_ptrs' _ _ _ _ _ H11). intros HE.
              simpl in Hdivides. rewrite H9 in Hdivides. rewrite H1 in Hdivides. monadInv Hdivides. monadInv EQ.
              destruct x. generalize (addr_of_global_exists' _ _ _ _ _ EQ2 H11).
              intros [v0 Hv0]. generalize (HE v0 Hv0). generalize (HB v0 (in_or_app _ _ _ (or_introl Hv0))).
              intros [ofs1 ZA]. intros [ofs2 ZB]. rewrite ZB in ZA; inv ZA. eapply HD; eauto.
            - eapply HB; eauto. }
      + exists xH. intros. inv H0.
  Qed.

  Lemma addr_of_annotations_implies_singleton:
    forall kappa ge sps alpha vals (Hsps: forall sp, In sp sps -> exists b, sp = Vptr b Int.zero),
      check_annotations_range alpha = OK tt ->
      addr_of_annotations kappa ge sps alpha vals ->
      exists vals', addr_of_annotations_singleton ge sps alpha vals' /\
               forall b ofs, In (Vptr b ofs) vals -> In (inl (Vptr b ofs)) vals' \/
                                               exists ofs1 ofs2, In (inr (Vptr b ofs1, Vptr b ofs2)) vals' /\ (Int.unsigned ofs1 <= Int.unsigned ofs <= Int.unsigned ofs2).
Proof.
    induction 3; intros.
    - simpl in H. destruct (zle (Int.unsigned base) (Int.unsigned bound)); destruct (zlt (Int.unsigned bound) (Int.modulus - 1)); try monadInv H.
      destruct (IHaddr_of_annotations H) as [vals2 [A B]].
      eexists; split.
      + econstructor; eauto.
      + intros. eapply in_app_or in H4; destruct H4.
        * destruct (Int.eq_dec base bound).
          { subst base. left. rewrite Int.sub_idem in H0. rewrite Int.unsigned_zero in H0.
            simpl in H0. assert (size = xH) by Psatz.lia. subst size.
            inv H2. inv H7. destruct (ArithLib.Zdivides_dec (align_chunk kappa) (Int.unsigned bound)); inv H4.
            - inv H2. left; auto.
            - inv H2. }
          { right. eapply addr_of_local_in in H4; eauto.
            - rewrite positive_nat_Z in H4. rewrite <- H0 in H4. destruct H4 as [i [X [Y Z]]].
              destruct sp; simpl in X; inv X. simpl. eexists. eexists. split.
              + left; eauto.
              + rewrite Int.unsigned_sub_borrow in Y. unfold Int.sub_borrow in Y.
                rewrite Int.unsigned_zero in Y. destruct (zlt (Int.unsigned bound - Int.unsigned base - 0) 0); try Psatz.lia.
                rewrite Int.unsigned_zero in Y. assert (Int.unsigned base + (Int.unsigned bound - Int.unsigned base + 0 * Int.modulus + 1) = Int.unsigned bound + 1) by Psatz.lia. rewrite H4 in Y.
                eapply pop_is_in in H1. eapply Hsps in H1. destruct H1 as [b' H1]. inv H1.
                rewrite ! Int.add_zero_l; auto. Psatz.lia.
            - rewrite positive_nat_Z. rewrite <- H0. eapply int_add_sub. Psatz.lia. }
        * eapply B in H4. destruct H4.
          { left. right; auto. }
          { right. destruct H4 as [ofs1 [ofs2 [AA AB]]]. exists ofs1, ofs2. split; auto.
            right; auto. }
    - simpl in H. destruct (zle (Int.unsigned base) (Int.unsigned bound)); destruct (zlt (Int.unsigned bound) (Int.modulus - 1)); try monadInv H.
      destruct (IHaddr_of_annotations H) as [vals2 [A B]].
      eexists; split.
      + econstructor; eauto.
      + intros. eapply in_app_or in H4; destruct H4.
        * destruct (Int.eq_dec base bound).
          { subst base. left. rewrite Int.sub_idem in H1. rewrite Int.unsigned_zero in H1.
            simpl in H1. assert (size = xH) by Psatz.lia. subst size.
            inv H2. inv H7. destruct (ArithLib.Zdivides_dec (align_chunk kappa) (Int.unsigned bound)); inv H4.
            - inv H2. left; auto.
            - inv H2. }
          { right. eapply addr_of_global_in in H4; eauto.
            - rewrite positive_nat_Z in H4. rewrite <- H1 in H4. destruct H4 as [i [X [Y Z]]].
              inv X. simpl. eexists. eexists. split.
              + left; eauto.
              + rewrite Int.unsigned_sub_borrow in Y. unfold Int.sub_borrow in Y.
                rewrite Int.unsigned_zero in Y. destruct (zlt (Int.unsigned bound - Int.unsigned base - 0) 0); try Psatz.lia.
                rewrite Int.unsigned_zero in Y. assert (Int.unsigned base + (Int.unsigned bound - Int.unsigned base + 0 * Int.modulus + 1) = Int.unsigned bound + 1) by Psatz.lia. rewrite H4 in Y.
                Psatz.lia.
            - rewrite positive_nat_Z. rewrite <- H1. eapply int_add_sub. Psatz.lia. }
        * eapply B in H4. destruct H4.
          { left. right; auto. }
          { right. destruct H4 as [ofs1 [ofs2 [AA AB]]]. exists ofs1, ofs2. split; auto.
            right; auto. }
    - exists nil. split.
      + econstructor.
      + intros. inv H0.
  Qed.

  Lemma check_annotations_range_inv:
    forall alpha
      (Hlocrange : forall (depth : nat) (varname : ident) (base bound : int),
          In (ABlocal depth varname (base, bound)) alpha -> Int.unsigned base <= Int.unsigned bound < Int.modulus - 1)
      (Hglobrange : forall (id : ident) (base bound : int),
          In (ABglobal id (base, bound)) alpha -> Int.unsigned base <= Int.unsigned bound < Int.modulus - 1),
      check_annotations_range alpha = OK tt.
Proof.
    induction alpha; intros.
    - reflexivity.
    - destruct a.
      + destruct range. generalize (Hlocrange _ _ _ _ (in_eq _ _)). intros.
        simpl. destruct (zle (Int.unsigned i) (Int.unsigned i0)); destruct (zlt (Int.unsigned i0) (Int.modulus - 1)); try Psatz.lia.
        eapply IHalpha; eauto.
        * intros; eapply Hlocrange; right; eauto.
        * intros; eapply Hglobrange; right; eauto.
      + destruct range. generalize (Hglobrange _ _ _ (in_eq _ _)). intros.
        simpl. destruct (zle (Int.unsigned i) (Int.unsigned i0)); destruct (zlt (Int.unsigned i0) (Int.modulus - 1)); try Psatz.lia.
        eapply IHalpha; eauto.
        * intros; eapply Hlocrange; right; eauto.
        * intros; eapply Hglobrange; right; eauto.
  Qed.

  Lemma tr_regs_annot_regs_singleton_plt:
    forall f c alpha pc1 regs regs' pc2 pcs,
      tr_regs_annot' prog STK f c pc1 alpha regs regs' pc2 pcs ->
      forall r, In r regs -> match r with | inl r => Plt (max_reg_function f) r | inr (r, r') => Plt (max_reg_function f) r /\ Plt (max_reg_function f) r' end.
Proof.
    induction alpha; intros.
    - inv H; inv H0.
    - inv H.
      + inv H4.
        * destruct H0. subst r; auto.
          eapply IHalpha; eauto.
        * destruct H0. subst r; auto. split; auto. xomega.
          eapply IHalpha; eauto.
      + inv H5.
        * destruct H0. subst r; auto.
          eapply IHalpha; eauto.
        * destruct H0. subst r; auto. split; auto. xomega.
          eapply IHalpha; eauto.
  Qed.

  Lemma tr_regs_annot_regs'_singleton_plt:
    forall f c alpha pc1 regs regs' pc2 pcs,
      tr_regs_annot' prog STK f c pc1 alpha regs regs' pc2 pcs ->
      forall r, In r regs' -> Plt (max_reg_function f) r.
Proof.
    induction alpha; intros.
    - inv H; inv H0.
    - inv H.
      + eapply in_app_or in H0. destruct H0.
        * inv H4; destruct H as [H | [H | H]]; try (subst r; xomega); inv H.
        * eapply IHalpha; eauto.
      + eapply IHalpha; eauto.
  Qed.

  Lemma tr_regs_annot_regs_singleton_norepet:
    forall f c alpha pc1 regs regs' pc2 pcs,
      tr_regs_annot' prog STK f c pc1 alpha regs regs' pc2 pcs ->
      list_norepet (fold_right (fun x acc => match x with | inl r => r::acc | inr (r, r') => r::r'::acc end) nil regs).
Proof.
    intros; inv H; auto. econstructor.
  Qed.

  Lemma alloc_store_zeros_cannot_fail_invariant:
    forall m n sz p m' b,
      Mem.alloc m 0 sz = (m', b) ->
      0 <= n + p <= sz ->
      0 <= p ->
      exists m'', store_zeros m' b p n = Some m''.
Proof.
    intros; generalize (Mem.perm_alloc_2 m _ _ _ _ H); intros.
    clear H.
    functional induction (store_zeros m' b p n).
    - eauto.
    - eapply IHo; intros.
      + Psatz.lia.
      + Psatz.lia.
      + eapply Mem.perm_store_1; eauto.
    - generalize (Mem.valid_access_store m0 Mint8unsigned b p Vzero).
      intros A; destruct A.
      red. split; red. simpl.
      + intros. eapply Mem.perm_implies.
        * eapply H2. split; try omega.
        * econstructor.
      + simpl. exists p; omega.
      + congruence.
  Qed.

  Corollary alloc_store_zeros_cannot_fail:
    forall m sz m' b,
      Mem.alloc m 0 sz = (m', b) ->
      sz >= 0 ->
      exists m'', store_zeros m' b 0 sz = Some m''.
Proof.
    intros; eapply alloc_store_zeros_cannot_fail_invariant; eauto; try omega.
  Qed.

  Lemma alloc_global_STK_cannot_fail:
    forall m,
      exists m', Genv.alloc_global tge m (STK, Gvar STK_globvar) = Some m'.
Proof.
    intros. simpl. assert (Z.max 512 0 = 512) by (eapply Z.max_l; omega). rewrite H.
    case_eq (Mem.alloc m 0 512); intros. assert (512 >= 0) by omega.
    generalize (alloc_store_zeros_cannot_fail _ _ _ _ H0 H1). intros [m1 A]. rewrite A.
    unfold Mem.drop_perm. generalize (Mem.perm_alloc_2 _ _ _ _ _ H0). intros B.
    destruct (Mem.range_perm_dec m1 b 0 512 Cur Freeable); eauto.
    exfalso. eapply n. unfold Mem.range_perm. intros.
    eapply Mem.perm_implies; eauto.
    - rewrite <- Genv.store_zeros_perm; eauto.
    - econstructor.
  Qed.
  
  Lemma alloc_global_SIZE_cannot_fail:
    forall m,
      exists m', Genv.alloc_global tge m (SIZE, Gvar SIZE_globvar) = Some m'.
Proof.
    intros. simpl. case_eq (Mem.alloc m 0 4); intros. assert (4 >= 0) by omega.
    generalize (alloc_store_zeros_cannot_fail _ _ _ _ H H0). intros [m1 A]. rewrite A.
    generalize (Mem.valid_access_store m1 Mint32 b 0 (Vint (Int.repr (-4)))). intros B; destruct B.
    - red; split; red; simpl.
      + intros. erewrite <- Genv.store_zeros_perm; eauto.
        eapply Mem.perm_implies. eapply Mem.perm_alloc_2; eauto.
        econstructor.
      + exists 0; omega.
    - rewrite e. unfold Mem.drop_perm. generalize (Mem.perm_alloc_2 _ _ _ _ _ H). intros B.
      destruct (Mem.range_perm_dec x b 0 4 Cur Freeable); simpl; eauto.
      exfalso. eapply n. unfold Mem.range_perm. intros.
      eapply Mem.perm_implies; eauto.
      + eapply Mem.perm_store_1; eauto.
        rewrite <- Genv.store_zeros_perm; eauto.
      + econstructor.
  Qed.

  Lemma epilogue_decrease_aux:
    forall n, 4 * Z.of_nat (S n) - 4 = 4 * Z.of_nat n.
Proof.
    induction n; intros.
    - reflexivity.
    - symmetry. rewrite Nat2Z.inj_succ.
      rewrite <- Z.add_1_l. rewrite Z.mul_add_distr_l.
      rewrite <- IHn. symmetry. rewrite Nat2Z.inj_succ.
      rewrite <- Z.add_1_l. rewrite Z.mul_add_distr_l. Psatz.lia.
  Qed.
  
  Lemma epilogue_decrease:
    forall n, Int.sub (Int.repr (4 * Z.of_nat (S n))) (Int.repr 4) = Int.repr (4 * Z.of_nat n).
Proof.
    intros. unfold Int.sub. eapply Int.eqm_samerepr.
    repeat rewrite Int.unsigned_repr_eq.
    red. eapply Int.eqmod_trans. apply Int.eqmod_mod. apply Int.modulus_pos.
    eapply Int.eqmod_trans.
    erewrite <- Zminus_mod. apply Int.eqmod_sym. apply Int.eqmod_mod. apply Int.modulus_pos.
    rewrite epilogue_decrease_aux. apply Int.eqmod_refl.
  Qed.

  Lemma repr_add:
   forall a b,
     Int.add (Int.repr a) (Int.repr b) =
     Int.repr (a + b).
Proof.
    intros.
    rewrite Int.add_unsigned.
    rewrite ! Int.unsigned_repr_eq.
    apply Int.eqm_samerepr.
    red.
    eapply Int.eqmod_trans.
    apply Int.eqmod_mod. apply Int.modulus_pos.
    eapply Int.eqmod_trans.
    rewrite <- Zplus_mod. apply Int.eqmod_sym. apply Int.eqmod_mod.
    apply Int.modulus_pos.
    apply Int.eqmod_refl.
  Qed.

  Lemma repr_sub:
    forall a b,
      Int.sub (Int.repr a) (Int.repr b) =
      Int.repr (a - b).
Proof.
    intros. rewrite Int.sub_signed.
    rewrite ! Int.signed_repr_eq.
    apply Int.eqm_samerepr.
    red. eapply Int.eqmod_trans.
    apply Int.eqmod_mod. apply Int.modulus_pos.
    destruct (zlt (a mod Int.modulus) Int.half_modulus).
    - destruct (zlt (b mod Int.modulus) Int.half_modulus).
      + rewrite <- Zminus_mod. apply Int.eqmod_sym.
        apply Int.eqmod_mod. eapply Int.modulus_pos.
      + replace ((a mod Int.modulus - (b mod Int.modulus - Int.modulus)) mod Int.modulus) with (((a mod Int.modulus - b mod Int.modulus) + Int.modulus) mod Int.modulus); try (f_equal; Psatz.lia).
        rewrite Zplus_mod. rewrite Z_mod_same_full.
        rewrite <- Zplus_0_r_reverse. rewrite Zmod_mod.
        rewrite <- Zminus_mod. apply Int.eqmod_sym.
        apply Int.eqmod_mod. eapply Int.modulus_pos.
    - destruct (zlt (b mod Int.modulus) Int.half_modulus).
      + replace ((a mod Int.modulus - Int.modulus - b mod Int.modulus) mod Int.modulus) with (((a mod Int.modulus - b mod Int.modulus) - Int.modulus) mod Int.modulus); try (f_equal; Psatz.lia).
        rewrite Zminus_mod. rewrite Z_mod_same_full.
        rewrite <- Zminus_0_l_reverse. rewrite Zmod_mod.
        rewrite <- Zminus_mod. apply Int.eqmod_sym.
        apply Int.eqmod_mod. eapply Int.modulus_pos.
      + replace (a mod Int.modulus - Int.modulus - (b mod Int.modulus - Int.modulus)) with (a mod Int.modulus - b mod Int.modulus); try Psatz.lia.
        rewrite <- Zminus_mod. apply Int.eqmod_sym.
        apply Int.eqmod_mod. eapply Int.modulus_pos.
  Qed.
    
  Lemma eval_builtin_arg_inject:
    forall n rs sp m j trs tsp tm a v,
      eval_builtin_arg ge (fun r => rs#r) (Vptr sp Int.zero) m a v ->
      j sp = Some (tsp, 0) ->
      regs_agree j n rs trs ->
      Mem.inject j m tm ->
      (forall id, In id (globals_of_builtin_arg a) -> ~ In id (STK::SIZE::nil)) ->
      (forall r, In r (params_of_builtin_arg a) -> Ple r n) ->
      (forall b, Plt b ge.(Genv.genv_next) -> j b = Some (b, 0)) ->
      exists tv, eval_builtin_arg tge (fun r => trs#r) (Vptr tsp Int.zero) tm a tv /\
            Val.inject j v tv.
Proof.
    induction 1; intros; try (eauto with barg; fail).
    - exists (trs#x); split; auto.
      + constructor.
      + simpl in H3. generalize (H3 x (or_introl eq_refl)). intro A.
        destruct (H0 x) as [[HA HB] | [HA HB]]; try xomega; auto.
    - simpl in H. exploit Mem.load_inject; eauto. rewrite Zplus_0_r.
      intros [tv [A B]]. eauto with barg.
    - exists (Val.add (Vptr tsp Int.zero) (Vint ofs)). split.
      + econstructor.
      + simpl. econstructor; eauto. repeat (rewrite Int.add_zero). reflexivity.
    - unfold Senv.symbol_address in H; simpl in H. case_eq (Genv.find_symbol ge id); intros; rewrite H6 in H; inv H.
      generalize (H5 b (ge.(Genv.genv_symb_range) id H6)). intros X.
      exploit Mem.load_inject; eauto. rewrite Zplus_0_r. intros [tv [B C]].
      exploit symbols_preserved; eauto.
      + eapply H3; simpl; eauto.
      + intros HA; rewrite <- HA in H6.
        eexists; split; eauto with barg.
        econstructor. unfold Senv.symbol_address; simpl; unfold Genv.symbol_address.
        rewrite H6. simpl. auto.
    - exists (Senv.symbol_address tge id ofs). split; eauto with barg.
      unfold Senv.symbol_address; simpl; unfold Genv.symbol_address.
      destruct (Genv.find_symbol ge id) as [b|] eqn:FS; auto.
      exploit symbols_preserved; eauto.
      + eapply H2; simpl; eauto.
      + intros A. rewrite A; rewrite FS. econstructor; eauto.
        * eapply H4. eapply ge.(Genv.genv_symb_range); eauto.
        * rewrite Int.add_zero; reflexivity.
    - destruct IHeval_builtin_arg1 as (v1' & A1 & B1); eauto using in_or_app.
      destruct IHeval_builtin_arg2 as (v2' & A2 & B2); eauto using in_or_app.
      exists (Val.longofwords v1' v2'); split; auto with barg.
      apply Val.longofwords_inject; auto.
  Qed.
      
  Lemma eval_builtin_args_inject:
    forall n rs sp m j trs tsp tm al vl,
      eval_builtin_args ge (fun r => rs#r) (Vptr sp Int.zero) m al vl ->
      j sp = Some (tsp, 0) ->
      regs_agree j n rs trs ->
      Mem.inject j m tm ->
      (forall id, In id (globals_of_builtin_args al) -> ~ In id (STK::SIZE::nil)) ->
      (forall r, In r (params_of_builtin_args al) -> Ple r n) ->
      (forall b, Plt b ge.(Genv.genv_next) -> j b = Some (b, 0)) ->
      exists tvl, eval_builtin_args tge (fun r => trs#r) (Vptr tsp Int.zero) tm al tvl /\
            Val.inject_list j vl tvl.
Proof.
    induction 1; intros.
    - exists (@nil val); split; constructor.
    - exploit eval_builtin_arg_inject; eauto using in_or_app. intros (v1' & A & B).
      destruct IHlist_forall2 as (vl' & C & D); eauto using in_or_app.
      exists (v1' :: vl'); split; constructor; auto.
  Qed.

  Lemma symbols_preserved':
    forall s b,
      Genv.find_symbol ge s = Some b ->
      Genv.find_symbol tge s = Some b.
Proof.
    intros. erewrite symbols_preserved; eauto.
    intro. destruct H0 as [H0 | [H0 | H0]]; auto.
    - subst s. eapply STK_is_new. eapply Genv.find_symbol_inversion; eauto.
    - subst s. eapply SIZE_is_new. eapply Genv.find_symbol_inversion; eauto.
  Qed.

  Lemma public_preserved':
    forall s,
      Genv.public_symbol ge s = Genv.public_symbol tge s.
Proof.
    intros; unfold Genv.public_symbol, ge, tge.
    rewrite ! Genv.globalenv_public.
    case_eq (Genv.find_symbol ge s); intros.
    - exploit symbols_preserved'; eauto. intros H'.
      unfold ge in H; rewrite H. unfold tge in H'; rewrite H'.
      unfold transf_program in TRANSF. generalize TRANSF'. intros TRANSF'.
      unfold transform_partial_augment_program in TRANSF'. monadInv TRANSF'. simpl. auto.
    - unfold ge in H; rewrite H.
      case_eq (Genv.find_symbol (Genv.globalenv tprog) s); intros; auto.
      assert (In s (STK::SIZE::nil)).
      + destruct (In_dec peq s (STK::SIZE::nil)); eauto.
        eapply symbols_preserved in n. unfold tge, ge in n; try congruence.
      + generalize STK_not_public; intros.
        generalize SIZE_not_public; intros.
        generalize TRANSF'; intros TRANSF'.
        unfold transform_partial_augment_program in TRANSF'. monadInv TRANSF'. simpl in *.
        destruct (In_dec ident_eq s (prog_public prog)); simpl; auto.
         destruct H1 as [H1 | [H1 | H1]]; try subst s; auto.
  Qed.

  Lemma match_stackframes_inject_incr:
    forall j j' stk tstk,
      match_stackframes j stk tstk ->
      inject_incr j j' ->
      match_stackframes j' stk tstk.
Proof.
    intros; inv H. econstructor; eauto.
    eapply regs_agree_inject_incr; eauto.
  Qed.

  Lemma forall_match_stackframes_inject_incr:
    forall j j' s ts,
      list_forall2 (match_stackframes j) s ts ->
      inject_incr j j' ->
      list_forall2 (match_stackframes j') s ts.
Proof.
    induction 1; intros.
    - econstructor.
    - econstructor; eauto.
      eapply match_stackframes_inject_incr; eauto.
  Qed.

  Lemma fold_left_transf_instr_unchanged:
    forall opt l s s',
      fold_left (fun a p => transf_instr prog ge STK SIZE opt a (fst p) (snd p)) l (OK s) = OK s' ->
      forall pc i, ~ In pc (map fst l) -> (st_code s)!pc = Some i -> Plt pc (st_nextnode s) -> (st_code s')!pc = Some i.
Proof.
    induction l; intros.
    - inv H. auto.
    - simpl in H. case_eq (transf_instr prog ge STK SIZE opt (OK s) (fst a) (snd a)); intros.
      + rewrite H3 in H. eapply IHl; eauto.
        * simpl in H0. eapply not_in_cons in H0. destruct H0; auto.
        * erewrite <- transf_instr_unchanged; eauto.
          eapply not_in_cons in H0. destruct H0; split; auto.
        * exploit transf_instr_sincr; eauto. intro X; inv X; try xomega.
      + rewrite H3 in H. generalize (fold_transf_instr_error prog STK l e opt).
        intros [e' LALA]. unfold SIZE in H. unfold ge in H. rewrite LALA in H; inv H.
  Qed.

  Lemma elements_complete:
    forall f pc,
      In pc (map fst (PTree.elements (fn_code f))) ->
      Ple pc (max_pc_function f).
Proof.
    intros. eapply in_map_iff in H.
    destruct H as [x [A B]]. destruct x; simpl in A. subst p.
    eapply PTree.elements_complete in B. eapply max_pc_function_sound; eauto.
  Qed.
      
  Lemma transf_function_new_entrypoint:
    forall f tf,
      transf_function prog ge STK SIZE f = OK tf ->
      exists r r' r'' pc1 pc2 pc3 pc4 pc5 pc6,
        Plt (max_reg_function f) r /\
        Plt r r' /\
        Plt r' r'' /\
        (fn_code tf)!(fn_entrypoint tf) = Some (Iload (xH, nil) Mint32 (Aglobal SIZE Int.zero) nil r pc1) /\
        (fn_code tf)!pc1 = Some (Iop (Oaddimm (Int.repr 4)) (r::nil) r pc2) /\
        (fn_code tf)!pc2 = Some (Istore (xH, nil) Mint32 (Aglobal SIZE Int.zero) nil r pc3) /\
        (fn_code tf)!pc3 = Some (Iload (xH, nil) Mint32 (Aglobal SIZE Int.zero) nil r' pc4) /\
        (fn_code tf)!pc4 = Some (Iop (Olea (Ainstack Int.zero)) nil r'' pc5) /\
        (fn_code tf)!pc5 = Some (Istore (xH, nil) Mint32 (Abased STK Int.zero) (r'::nil) r'' pc6) /\
        (fn_code tf)!pc6 = Some (Inop (fn_entrypoint f)).
Proof.
    intros. monadInv H; simpl. rewrite PTree.fold_spec in EQ.
    generalize (fold_left_transf_instr_unchanged _ _ _ _ EQ). intro X.
    exists (st_nextreg (init_state f)). exists (Psucc (st_nextreg (init_state f))). exists (Psucc (Psucc (st_nextreg (init_state f)))).
    exists (Psucc (Psucc (max_pc_function f))). exists (Psucc (Psucc (Psucc (max_pc_function f)))). exists (Psucc (Psucc (Psucc (Psucc (max_pc_function f))))). exists (Psucc (Psucc (Psucc (Psucc (Psucc (max_pc_function f)))))). exists (Psucc (Psucc (Psucc (Psucc (Psucc (Psucc (max_pc_function f))))))). exists (Psucc (Psucc (Psucc (Psucc (Psucc (Psucc (Psucc (max_pc_function f)))))))).
    repeat split; simpl; try xomega.
    - eapply X.
      + intro Y. eapply elements_complete in Y. xomega.
      + simpl. rewrite PTree.gso; try xomega.
        rewrite PTree.gso; try xomega.
        rewrite PTree.gso; try xomega.
        rewrite PTree.gso; try xomega.
        rewrite PTree.gso; try xomega.
        rewrite PTree.gso; try xomega.
        rewrite PTree.gss; eauto.
      + simpl; xomega.
    - eapply X.
      + intro Y. eapply elements_complete in Y. xomega.
      + simpl. rewrite PTree.gso; try xomega.
        rewrite PTree.gso; try xomega.
        rewrite PTree.gso; try xomega.
        rewrite PTree.gso; try xomega.
        rewrite PTree.gso; try xomega.
        rewrite PTree.gss; eauto.
      + simpl; xomega.
    - eapply X.
      + intro Y. eapply elements_complete in Y. xomega.
      + simpl. rewrite PTree.gso; try xomega.
        rewrite PTree.gso; try xomega.
        rewrite PTree.gso; try xomega.
        rewrite PTree.gso; try xomega.
        rewrite PTree.gss; eauto.
      + simpl; xomega.
    - eapply X.
      + intro Y. eapply elements_complete in Y. xomega.
      + simpl. rewrite PTree.gso; try xomega.
        rewrite PTree.gso; try xomega.
        rewrite PTree.gso; try xomega.
        rewrite PTree.gss; eauto.
      + simpl; xomega.
    - eapply X.
      + intro Y. eapply elements_complete in Y. xomega.
      + simpl. rewrite PTree.gso; try xomega.
        rewrite PTree.gso; try xomega.
        rewrite PTree.gss; eauto.
      + simpl; xomega.
    - eapply X.
      + intro Y. eapply elements_complete in Y. xomega.
      + simpl. rewrite PTree.gso; try xomega.
        rewrite PTree.gss; eauto.
      + simpl; xomega.
    - eapply X.
      + intro Y. eapply elements_complete in Y. xomega.
      + simpl. rewrite PTree.gss; eauto.
      + simpl; xomega.
  Qed.
  
  Lemma init_regs_inject:
    forall j args targs,
      Val.inject_list j args targs ->
      forall params r, Val.inject j (init_regs args params)#r (init_regs targs params)#r.
Proof.
    induction 1; intros.
    - destruct params; simpl.
      + rewrite ! PMap.gi. eauto.
      + rewrite ! PMap.gi. eauto.
    - destruct params; simpl.
      + rewrite ! PMap.gi; eauto.
      + destruct (peq r r0).
        * subst r0. rewrite ! PMap.gss; auto.
        * rewrite ! PMap.gso; auto.
  Qed.

  Lemma pop_length:
    forall l n x,
      pop n l = Some x ->
      (n < length l)%nat.
Proof.
    induction l; intros.
    - destruct n; simpl in H; inv H.
    - destruct n; simpl in H.
      + simpl; omega.
      + eapply IHl in H. simpl. omega.
  Qed.

  Lemma pop_implies:
    forall l n x,
      pop n l = Some x ->
      exists y, pop 0 l = Some y.
Proof.
    induction l; intros.
    - destruct n; simpl in H; inv H.
    - simpl; eauto.
  Qed.

  Lemma STK_not_SIZE:
    forall bSTK bSIZE,
      Genv.find_symbol tge STK = Some bSTK ->
      Genv.find_symbol tge SIZE = Some bSIZE ->
      bSTK <> bSIZE.
Proof.
    unfold not; intros. subst bSIZE.
    generalize (Genv.genv_vars_inj tge _ _ H H0).
    intros; unfold STK in H1; unfold SIZE in H1; eapply Psucc_discr; eauto.
  Qed.
  
  Lemma FSIM_implies:
    forall s1 s2 t,
      initial_state prog s1 ->
      star step_block' ge s1 t s2 ->
      star step ge s1 t s2.
Proof.
    intros. generalize (fsim_match_initial_states (FSIM prog) s1 H). intros [i [s1' [A B]]].
    generalize (simulation_star (FSIM prog) H0 _ _ B). intros [i' [s2' [C D]]].
    generalize (semantics_determinate prog); intros E.
    generalize (sd_initial_determ E _ _ H A). intros; subst s1'.
    inv D. eapply C.
  Qed.
    
  Lemma initial_states_exist:
    forall s1,
      initial_state tprog s1 -> exists s2, initial_state prog s2.
Proof.
    intros. generalize init_state_exists. intros [s A]. inv A.
    econstructor; econstructor; eauto.
  Qed.

  Lemma not_fresh_find_symbol_ind:
    forall (F V: Type) gl (ge0: Genv.t F V),
      (forall b, Plt b (Genv.genv_next ge0) -> exists id, Genv.find_symbol ge0 id = Some b /\ ~ In id (map fst gl)) ->
      list_norepet (map fst gl) ->
      (forall ge id g gl1 gl2 , In (id, g) gl ->
                           map fst gl = gl1 ++ (id::gl2) ->
                           (forall b, Plt b (Genv.genv_next ge) -> exists id', Genv.find_symbol ge id' = Some b /\ ~ In id' (id::gl2)) ->
                           (forall b, Plt b (Genv.genv_next (Genv.add_global ge (id, g))) -> exists id', Genv.find_symbol (Genv.add_global ge (id, g)) id' = Some b /\ ~ In id' gl2)) ->
      forall b, Plt b (Genv.genv_next (Genv.add_globals ge0 gl)) -> exists id, Genv.find_symbol (Genv.add_globals ge0 gl) id = Some b.
Proof.
    induction gl; intros.
    - simpl in H2. eapply H in H2. destruct H2 as [id [HA HB]]. eauto.
    - simpl. simpl in H2. destruct a. eapply IHgl; eauto.
      + intros. eapply H1; intros.
        * eapply in_eq.
        * simpl. instantiate (1 := nil). simpl. eauto.
        * eapply H. eauto.
        * eauto.
      + simpl in H0. inv H0; eauto.
      + intros. eapply H1.
        * eapply in_cons; eauto.
        * simpl. rewrite H4. instantiate (1 := i :: gl1). eauto.
        * intros. eapply H5; eauto.
        * eauto.
  Qed.
  
  Lemma not_fresh_find_symbol:
    forall (F V: Type) (p: AST.program F V) (b: block),
      list_norepet (map fst (prog_defs p)) ->
      Plt b (Genv.genv_next (Genv.globalenv p)) ->
      exists id, Genv.find_symbol (Genv.globalenv p) id = Some b.
Proof.
    intros; eapply not_fresh_find_symbol_ind; eauto.
    - intros. simpl in H1. xomega.
    - intros. simpl in H4. eapply Plt_succ_inv in H4. destruct H4.
      + generalize (H3 _ H4). intros [id' [HA HB]].
        eapply not_in_cons in HB. destruct HB as [HB HC].
        unfold Genv.find_symbol, Genv.add_global; simpl. exists id'.
        rewrite PTree.gso; auto.
      + exists id. unfold Genv.find_symbol, Genv.add_global; simpl. rewrite PTree.gss.
        subst b0; split; try reflexivity.
        rewrite H2 in H. eapply list_norepet_app in H.
        destruct H as [A [B C]]. inv B; eauto.
  Qed.
  
  Lemma initial_states_match:
    forall s1 s2,
      initial_state tprog s1 ->
      initial_state prog s2 ->
      exists s1', initial_state tprog s1' /\ match_states s2 s1'.
Proof.
    intros. exists s1. split; auto. generalize H; intros INIT1. generalize H0; intros INIT2.
    inv H; inv H0.
    exploit (Genv.init_mem_inject_transf_augment _ _ _ _ _ TRANSF'); eauto.
    - simpl; intros. destruct H8 as [H8 | [H8 | H8]]; auto.
      + eapply STK_is_new; unfold STK; subst s; eauto.
      + eapply SIZE_is_new; unfold SIZE; unfold STK; subst s; eauto.
    - intros MINJ.
      exploit (Genv.init_mem_transf_augment _ _ _ _ _ TRANSF').
      + intros. simpl in H8.
        fold STK in H8. fold SIZE in H8. destruct H8 as [H8 | [H8 | H8]]; auto.
        * subst s. eapply STK_is_new; eauto.
        * subst s; eapply SIZE_is_new; eauto.
      + eauto.
      + intros Hinit_mem.
        unfold ge0 in *. erewrite (Genv.find_symbol_transf_augment _ _ _ _ _ TRANSF')in H2; eauto.
        * exploit (Genv.find_funct_ptr_transf_augment _ _ _ _ _ TRANSF'); eauto. intros [f' [A B]].
          erewrite (AST.transform_partial_augment_program_main _ _ _ _ _ TRANSF') in H2; eauto.
          unfold ge1 in *. rewrite H2 in H5; inv H5. rewrite A in H3. inv H3.
          econstructor; eauto.
          { econstructor. }
          { intros. destruct (semantics_determinate prog).
            assert (s0 = Callstate nil f0 nil m1) by (eapply sd_initial_determ; eauto).
            subst s0. exists E0. eapply star_refl. }
          { intros. destruct (semantics_determinate tprog).
            assert (s0 = Callstate nil f nil m0) by (eapply sd_initial_determ; eauto).
            subst s0. exists E0. eapply star_refl. }
          { intros. exploit Genv.init_mem_genv_next; eauto. intros.
            rewrite <- H3. unfold ge in H0. unfold Mem.flat_inj.
            destruct (plt b (Genv.genv_next (Genv.globalenv prog))); auto; try xomega. }
          { intros. exploit Genv.init_mem_genv_next; eauto. intros.
            unfold Mem.flat_inj in H3. destruct (plt b (Mem.nextblock m1)); inv H3.
            fold STK in H1. fold SIZE in H1. unfold Genv.symbol_address in H0.
            case_eq (Genv.find_symbol tge STK); intros; rewrite H3 in H0; inv H0.
            rewrite <- H5 in p. generalize norepet_prog_defs; intros Hnorepet.
            exploit not_fresh_find_symbol; eauto.
            intros [id Hid]. exploit symbols_preserved'; eauto.
            intros Hid'. red; intros; subst b'.
            generalize (Genv.genv_vars_inj tge _ _ H3 Hid').
            intros; subst id. generalize (Genv.find_symbol_inversion _ _ Hid).
            intros. eapply STK_is_new; eauto. }
          { intros. exploit Genv.init_mem_genv_next; eauto. intros.
            unfold Mem.flat_inj in H3. destruct (plt b (Mem.nextblock m1)); inv H3.
            fold STK in H1. fold SIZE in H1. unfold Genv.symbol_address in H0.
            case_eq (Genv.find_symbol tge SIZE); intros; rewrite H3 in H0; inv H0.
            rewrite <- H5 in p. generalize norepet_prog_defs; intros Hnorepet.
            exploit not_fresh_find_symbol; eauto.
            intros [id Hid]. exploit symbols_preserved'; eauto.
            intros Hid'. red; intros; subst b'.
            generalize (Genv.genv_vars_inj tge _ _ H3 Hid').
            intros; subst id. generalize (Genv.find_symbol_inversion _ _ Hid).
            intros. eapply SIZE_is_new; eauto. }
          { intros. eapply Genv.find_symbol_not_fresh; eauto. }
          { intros. eapply Genv.find_symbol_not_fresh; eauto. }
          { intros. destruct STK_exists as [bSTK' [HA HB]]. rewrite HA in H0; inv H0.
            unfold tge in HB. exploit Genv.init_mem_characterization; eauto.
            intros [X [Y Z]]. unfold STK_globvar in X; simpl in X.
            rewrite Zmax_left in X; try omega.
            eapply X. }
          { intros. destruct SIZE_exists as [bSIZE' [HA HB]]. rewrite HA in H0; inv H0.
            unfold tge in HB. exploit Genv.init_mem_characterization; eauto.
            intros [X [Y Z]]. unfold SIZE_globvar in X; simpl in X.
            eapply X. }
          { intros; split; intros.
            - destruct STK_exists as [bSTK' [HA HB]]. rewrite HA in H0; inv H0.
              unfold tge in HB. exploit Genv.init_mem_characterization; eauto.
              intros [X [Y Z]]. unfold STK_globvar in X; simpl in X.
              rewrite Zmax_left in X; try omega.
              eapply Y. eauto.
            - destruct STK_exists as [bSTK' [HA HB]]. rewrite HA in H0; inv H0.
              unfold tge in HB. exploit Genv.init_mem_characterization; eauto.
              intros [X [Y Z]]. unfold STK_globvar in X; simpl in X.
              rewrite Zmax_left in X; try omega.
              red in X. eapply Mem.perm_implies. eapply X; eauto.
              constructor. }
          { intros; split; intros.
            - destruct SIZE_exists as [bSIZE' [HA HB]]. rewrite HA in H0; inv H0.
              unfold tge in HB. exploit Genv.init_mem_characterization; eauto.
              intros [X [Y Z]]. unfold SIZE_globvar in X; simpl in X.
              eapply Y; eauto.
            - destruct SIZE_exists as [bSIZE' [HA HB]]. rewrite HA in H0; inv H0.
              unfold tge in HB. exploit Genv.init_mem_characterization; eauto.
              intros [X [Y Z]]. unfold SIZE_globvar in X; simpl in X.
              red in X. eapply Mem.perm_implies. eapply X; eauto.
              constructor. }
          { intros. unfold Mem.flat_inj in H3.
            destruct (plt b' (Mem.nextblock m1)); inv H3; auto. }
          { exploit Genv.init_mem_genv_next; eauto. unfold ge; intros.
            rewrite H0. xomega. }
          { exploit Genv.init_mem_genv_next; eauto. unfold ge; intros.
            rewrite H0. rewrite Hinit_mem in H1. exploit Genv.alloc_globals_nextblock; eauto.
            intros. rewrite H3. simpl. xomega. }
          { econstructor. simpl. split.
            - destruct SIZE_exists as [bSIZE [HA HB]].
              generalize (Genv.init_mem_characterization _ _ HB H1). intros [X [Y Z]].
              unfold SIZE_globvar in Z. simpl in Z. unfold Genv.symbol_address; rewrite HA; simpl.
              destruct (Z eq_refl) as [Z1 Z2].
              rewrite Int.unsigned_zero. rewrite Z1. reflexivity.
            - intros; split; intros.
              + destruct depth; simpl in H0; inv H0.
              + destruct H0. omega. }
          { simpl. omega. }
          { intros. unfold Mem.flat_inj in H0.
            destruct (plt b (Mem.nextblock m1)); inv H0; eauto. }
          { unfold Mem.flat_inj; intros. destruct (plt b1 (Mem.nextblock m1)); destruct (plt b2 (Mem.nextblock m1)); inv H0; inv H3; eauto. }
          { intros; split; intros.
            - unfold Mem.flat_inj in H0; destruct (plt b (Mem.nextblock m1)); inv H0.
              rewrite Hinit_mem in H1. exploit Genv.alloc_globals_perm; eauto; intros.
              eapply H0; eauto.
            - unfold Mem.flat_inj in H0; destruct (plt b (Mem.nextblock m1)); inv H0.
              rewrite Hinit_mem in H1. exploit Genv.alloc_globals_perm; eauto; intros.
              eapply H0; eauto. }
        * generalize TRANSF'; intros TRANSF'.
          unfold transform_partial_augment_program in TRANSF'; monadInv TRANSF'. simpl.
          generalize (Genv.find_symbol_inversion _ _ H5). unfold prog_defs_names. intros.
          generalize STK_is_new. generalize SIZE_is_new. intros.
          unfold not; intros [U | [U | U]]; eauto.
          { eapply H9. rewrite U; eapply H0. }
          { eapply H8. rewrite U; eapply H0. }
  Qed.

  Lemma transf_function_inv_aux:
    forall opt l s s' pc i,
      fold_left (fun acc pc_i => transf_instr prog ge STK SIZE opt acc (fst pc_i) (snd pc_i)) l (OK s) = OK s' ->
      In (pc, i) l ->
      exists s1 s2, transf_instr prog ge STK SIZE opt (OK s1) pc i = OK s2.
Proof.
    induction l; intros.
    - inv H0.
    - simpl in H0. destruct H0.
      + inv H0. simpl in H.
        exists s. case_eq (transf_instr prog ge STK SIZE opt (OK s) pc i).
        * intros; eauto.
        * intros. rewrite H0 in H.
          generalize (fold_transf_instr_error prog STK l e opt). intros [e' LALA].
          unfold SIZE in H.
          unfold ge in H. rewrite LALA in H. inv H.
      + simpl in H. case_eq (transf_instr prog ge STK SIZE opt (OK s) (fst a) (snd a)).
        * intros. rewrite H1 in H. eapply IHl; eauto.
        * intros. rewrite H1 in H.
          generalize (fold_transf_instr_error prog STK l e opt). intros [e' LALA].
          unfold SIZE in H.
          unfold ge in H; rewrite LALA in H. inv H.
  Qed.

  Lemma transf_function_inv:
    forall f tf pc i,
      transf_function prog ge STK SIZE f = OK tf ->
      (fn_code f)!pc = Some i ->
      exists s s', transf_instr prog ge STK SIZE (sig_res (fn_sig f)) (OK s) pc i = OK s'.
Proof.
    intros. monadInv H.
    rewrite PTree.fold_spec in EQ.
    eapply transf_function_inv_aux; eauto.
    eapply PTree.elements_correct; eauto.
  Qed.

  Lemma addr_of_local_exists:
    forall n kappa ofs sp,
    exists vptrs, addr_of_local kappa sp ofs n vptrs.
Proof.
    induction n; intros.
    - exists nil. econstructor.
    - generalize (IHn kappa (Int.add ofs Int.one) sp). intros [vptrs A].
      eexists. econstructor; eauto.
  Qed.

  Lemma addr_of_global_exists:
    forall b kappa n ofs,
    exists vptrs, addr_of_global kappa b ofs n vptrs.
Proof.
    induction n; intros.
    - exists nil; econstructor.
    - generalize (IHn (Int.add ofs Int.one)). intros [vptrs A].
      eexists. econstructor; eauto.
  Qed.

  Lemma addr_of_local_translated':
    forall kappa j sp tsp n ofs tvals,
      j sp = Some (tsp, 0) ->
      addr_of_local kappa (Vptr tsp Int.zero) ofs n tvals ->
      exists vals, addr_of_local kappa (Vptr sp Int.zero) ofs n vals /\ list_forall2 (Val.inject j) vals tvals.
Proof.
    induction n; intros.
    - inv H0; exists nil; split; try econstructor; eauto.
    - inv H0. eapply IHn in H3; eauto. destruct H3 as [vals' [A B]].
      eexists; split; try econstructor; eauto.
      destruct (ArithLib.Zdivides_dec (align_chunk kappa) (Int.unsigned ofs)); eauto.
      econstructor; eauto.
      simpl. econstructor; eauto. rewrite ! Int.add_zero. auto.
  Qed.

  Lemma addr_of_global_translated':
    forall kappa j b n ofs tvals,
      j b = Some (b, 0) ->
      addr_of_global kappa b ofs n tvals ->
      exists vals, addr_of_global kappa b ofs n vals /\ list_forall2 (Val.inject j) vals tvals.
Proof.
    induction n; intros.
    - inv H0; exists nil; split; try econstructor; eauto.
    - inv H0. eapply IHn in H3; eauto. destruct H3 as [vals' [A B]].
      eexists; split; try econstructor; eauto.
      destruct (ArithLib.Zdivides_dec (align_chunk kappa) (Int.unsigned ofs)); eauto.
      econstructor; eauto.
      simpl. econstructor; eauto. rewrite ! Int.add_zero. auto.
  Qed.

  Lemma pop_inject':
    forall P sps tsps,
      list_forall2 P sps tsps ->
      forall tsp n, pop n tsps = Some tsp ->
               exists sp, pop n sps = Some sp /\
                     P sp tsp.
Proof.
    induction 1; intros.
    - destruct n; simpl in H; inv H.
    - destruct n; simpl in H1.
      + inv H1. exists a1; split; simpl; eauto.
      + generalize (pop_is_in _ _ _ H1). intros Hin.
        eapply IHlist_forall2 in H1. destruct H1 as [sp [A B]].
        exists sp. split; auto.
  Qed.

  Lemma addr_of_annotations_translated':
    forall kappa j sps tsps alpha tvals,
      list_forall2 (fun sp tsp => exists bsp btsp, sp = Vptr bsp Int.zero /\ tsp = Vptr btsp Int.zero /\ j bsp = Some (btsp, 0)) sps tsps ->
      (forall b id, Genv.find_symbol ge id = Some b -> j b = Some (b, 0)) ->
      (forall id range, In (ABglobal id range) alpha -> id <> STK /\ id <> SIZE) ->
      addr_of_annotations kappa tge tsps alpha tvals ->
      exists vals, addr_of_annotations kappa ge sps alpha vals /\ list_forall2 (Val.inject j) vals tvals.
Proof.
    induction alpha; intros.
    - inv H2. exists nil; split; econstructor; eauto.
    - inv H2.
      + generalize (pop_inject' _ _ _ H _ _ H6). intros [sp' [A B]].
        destruct B as [bsp [tbsp [B [C D]]]]. subst sp'; subst sp.
        exploit addr_of_local_translated'; eauto.
        intros [vals1 [F G]].
        exploit IHalpha; eauto.
        { intros; eapply H1; eapply in_cons; eauto. }
        intros [vals2 [I J]].
        eexists; split.
        * econstructor; eauto.
        * eapply list_forall2_app; eauto.
      + generalize (H1 _ _ (in_eq _ _)). intros [A B].
        rewrite symbols_preserved in H5; eauto.
        * generalize (H0 _ _ H5). intros C.
          exploit addr_of_global_translated'; eauto. intros [vals1 [HA HB]].
          exploit IHalpha; eauto.
          { intros; eapply H1; eapply in_cons; eauto. }
          intros [vals2 [HC HD]].
          eexists; split.
          { econstructor; eauto. }
          { eapply list_forall2_app; eauto. }
        * unfold not; intros. destruct H2 as [H2 | [H2 | H2]]; try (inv H2; fail).
          { eapply (proj1 (H1 _ _ (in_eq _ _))). eauto. }
          { eapply (proj2 (H1 _ _ (in_eq _ _))). eauto. }
  Qed.

  Lemma unsigned_p1:
    forall i, exists p, Int.unsigned i + 1 = Z.pos p.
Proof.
    intros. generalize (Int.unsigned_range i); intros Hrange.
    destruct (Int.unsigned i); try xomega.
    - exists xH. eauto.
    - exists (Psucc p). xomega.
  Qed.

  Lemma tr_local_regs_star:
    forall kappa sp stk f tf n ofs depth pc1 regs regs' pc2 pcs trs m,
      (forall s0, initial_state tprog s0 -> exists t : trace, star step tge s0 t (State stk tf sp pc1 trs m)) ->
      tr_local_regs STK kappa f (fn_code tf) pc1 ofs depth n regs regs' pc2 pcs ->
      exists trs', star step tge (State stk tf sp pc1 trs m) E0 (State stk tf sp pc2 trs' m).
Proof.
    induction n; intros.
    - inv H0; exists trs; eapply star_refl.
    - inv H0. generalize init_state_exists'; intros [s0 Hinit].
      { destruct (Classical_Prop.classic (exists t' s', step tge (State stk tf sp pc1 trs m) t' s')).
        + destruct H0 as [t' [s' Hs']].
          destruct (Classical_Prop.classic (exists t1 s1, step tge s' t1 s1)).
          * destruct H0 as [t1 [s1 Hs1]].
            destruct (Classical_Prop.classic (exists t2 s2, step tge s1 t2 s2)).
            { destruct H0 as [t2 [s2 Hs2]].
              inv Hs'; try congruence. rewrite H17 in H2; inv H2.
              inv Hs1; try congruence. rewrite H16 in H3; inv H3.
              inv Hs2; try congruence. rewrite H14 in H4; inv H4.
              exploit IHn.
              - intros. eapply H in H0. destruct H0 as [t H0].
                econstructor. eapply star_trans; eauto.
                eapply star_step. eapply exec_Iload; eauto.
                eapply star_step. eapply exec_Iload; eauto.
                eapply star_step. eapply exec_Iop; eauto.
                eapply star_refl. eauto. eauto. eauto.
              - eauto.
              - intros [trs' HA].
                exists trs'. eapply star_trans; eauto.
                eapply star_step. eapply exec_Iload; eauto.
                eapply star_step. eapply exec_Iload; eauto.
                eapply star_step. eapply exec_Iop; eauto.
                eapply star_refl. eauto. eauto. eauto.
                repeat rewrite E0_right. eauto. }
            { generalize (H s0 Hinit). intros [t Hstar].
              assert (program_behaves (semantics tprog) (Goes_wrong (t ** t' ** t1 ** E0))).
              - econstructor; eauto.
                econstructor. eapply star_trans; eauto.
                eapply star_step. eapply Hs'. eapply star_step. eapply Hs1.
                eapply star_refl. eauto. eauto.
                intro. unfold not; intros. eapply H0; eauto.
                unfold not; intros. inv Hs'; try congruence.
                inv Hs1; try congruence. inv H1.
              - eapply DEFSAFE in H1. inv H1. }
          * generalize (H s0 Hinit). intros [t Hstar].
            assert (program_behaves (semantics tprog) (Goes_wrong (t ** t' ** E0))).
            { econstructor; eauto.
              econstructor. eapply star_trans; eauto.
              eapply star_step. eapply Hs'. eapply star_refl. eauto.
              intro. unfold not; intros. eapply H0; eauto.
              unfold not; intros. inv Hs'; try congruence.
              inv H1. }
            { eapply DEFSAFE in H1; inv H1. }
        + generalize (H s0 Hinit). intros [t Hstar].
          assert (program_behaves (semantics tprog) (Goes_wrong (t ** E0))).
          * econstructor; eauto.
            econstructor. eapply star_trans; eauto.
            eapply star_refl. eauto.
            intro. unfold not; intros. eapply H0; eauto.
            unfold not; intros. inv H1.
          * eapply DEFSAFE in H1; inv H1. }
      { eapply IHn; eauto. }
  Qed.

  Lemma tr_global_regs_star:
    forall kappa sp stk f tf id n ofs pc1 regs pc2 pcs trs m,
      (forall s0, initial_state tprog s0 -> exists t : trace, star step tge s0 t (State stk tf sp pc1 trs m)) ->
      tr_global_regs kappa f (fn_code tf) pc1 id ofs n regs pc2 pcs ->
      exists trs', star step tge (State stk tf sp pc1 trs m) E0 (State stk tf sp pc2 trs' m).
Proof.
    induction n; intros.
    - inv H0; exists trs; eapply star_refl.
    - inv H0.
      destruct (Classical_Prop.classic (exists t' s', step tge (State stk tf sp pc1 trs m) t' s')).
      + destruct H0 as [t' [s' Hs']]. inv Hs'; try congruence.
        rewrite H12 in H2; inv H2.
        exploit IHn; (try eapply H3).
        * intros. eapply H in H0.
          destruct H0 as [t H0]. exists t. eapply star_trans; eauto.
          eapply star_step. eapply exec_Iop; eauto.
          eapply star_refl. eauto. repeat rewrite E0_right; eauto.
        * intros [trs' HA]. exists trs'. eapply star_trans; eauto.
          eapply star_step. eapply exec_Iop; eauto.
          eapply star_refl. eauto. eauto.
      + generalize init_state_exists'; intros [s0 Hinit].
        generalize (H s0 Hinit). intros [t Hstar].
        assert (program_behaves (semantics tprog) (Goes_wrong t)).
        * econstructor; eauto.
          econstructor. eapply Hstar.
          intro; unfold not; intros. eapply H0; eauto.
          unfold not; intros. inv H1.
        * eapply DEFSAFE in H1; inv H1.
      + eapply IHn; eauto.
  Qed.

  Lemma tr_regs_annot_star:
    forall kappa sp stk f tf alpha pc1 regs regs' pc2 pcs trs m,
      (forall s0, initial_state tprog s0 -> exists t : trace, star step tge s0 t (State stk tf sp pc1 trs m)) ->
      tr_regs_annot prog STK kappa f (fn_code tf) pc1 alpha regs regs' pc2 pcs ->
      exists trs', star step tge (State stk tf sp pc1 trs m) E0 (State stk tf sp pc2 trs' m).
Proof.
    induction alpha; intros.
    - inv H0; exists trs; eapply star_refl.
    - destruct a.
      + inv H0. exploit tr_local_regs_star; eauto. intros [trs' HA].
        exploit IHalpha; try (eapply H5).
        * intros. eapply H in H0. destruct H0 as [t H0].
          exists (t ** E0). eapply star_trans; eauto.
        * intros [trs'' HB].
          exists trs''; eapply star_trans; eauto.
      + inv H0. exploit tr_global_regs_star; eauto. intros [trs' HA].
        exploit IHalpha; try (eapply H5).
        * intros. eapply H in H0. destruct H0 as [t H0].
          exists (t ** E0). eapply star_trans; eauto.
        * intros [trs'' HB].
          exists trs''; eapply star_trans; eauto.
  Qed.

  Lemma mod_neg:
    forall a b,
      b > 0 ->
      -b <= a < 0 ->
      a mod b = a + b.
Proof.
    intros. eapply Zmod_unique.
    - instantiate (1 := -1); omega.
    - omega.
  Qed.

  Lemma tr_local_regs_inv:
    forall kappa f n pc1 base depth regs regs' pc2 pcs stk tf tsp trs m,
      tr_local_regs STK kappa f (fn_code tf) pc1 base depth n regs regs' pc2 pcs ->
      (depth < 128)%nat ->
      shadowstack_is_sound (tsp::map (fun s => match s with | Stackframe _ _ sp _ _ => sp end) stk) m ->
      (exists x, In x (int_ranges n base) /\ ((align_chunk kappa) | x)) ->
      (forall s0, initial_state tprog s0 -> exists t : trace, star step tge s0 t (State stk tf tsp pc1 trs m)) ->
      (forall bSTK, Genv.find_symbol tge STK = Some bSTK -> forall ofs : Z, Mem.perm m bSTK ofs Cur Readable <-> 0 <= ofs < 512) ->
      exists sp, pop depth (tsp::map (fun s => match s with | Stackframe _ _ sp _ _ => sp end) stk) = Some sp.
Proof.
    induction n; intros.
    - simpl in H2. destruct H2. destruct H2. inv H2.
    - destruct H2 as [x [HA HB]]. destruct HA as [HA | HA].
      + subst x. inv H; try congruence. destruct (Classical_Prop.classic (exists t' s', step tge (State stk tf tsp pc1 trs m) t' s')).
        * destruct H as [t' [s' Hs']].
          destruct (Classical_Prop.classic (exists t'' s'', step tge s' t'' s'')).
          { destruct H as [t'' [s'' Hs'']].
            inv Hs'; try congruence. rewrite H20 in H5; inv H5.
            inv Hs''; try congruence. rewrite H19 in H6; inv H6.
            simpl in H21; simpl in H23. unfold Genv.symbol_address in H21. unfold Genv.symbol_address in H23. fold SIZE in H21.
            destruct SIZE_exists as [bSIZE [HSIZE HSIZEvar]].
            destruct STK_exists as [bSTK [HSTK HSTKvar]].
            rewrite HSIZE in H21. rewrite HSTK in H23.
            inv H21. rewrite PMap.gss in H23.
            inv H1. destruct H as [SS1 SS2].
            unfold Genv.symbol_address in SS1; rewrite HSIZE in SS1.
            rewrite SS1 in H22; inv H22. simpl in H23. rewrite repr_add in H23. inv H23.
            simpl in H24. unfold Genv.symbol_address in SS2; rewrite HSTK in SS2.
            rewrite map_length in *. simpl in SS2. rewrite map_length in SS2.
            exploit Mem.load_valid_access; eauto. intro Hperm.
            red in Hperm. destruct Hperm as [Hperm1 Hperm2].
            red in Hperm1. exploit (Hperm1 (Int.unsigned (Int.repr (-4 * Z.of_nat depth + 4 * (Z.pos (Pos.of_succ_nat (length stk)) - 1))))); simpl; try omega.
            intro Hperm. eapply H4 in Hperm; eauto.
            assert (Hdepthbound: (depth < S (length stk))%nat).
            { rewrite Int.unsigned_repr_eq in Hperm.
              replace Int.modulus with 4294967296 in Hperm; try reflexivity.
              destruct (le_dec depth (length stk)); try omega.
              eapply not_le in n0.
              assert (512 < (-4 * Z.of_nat depth + 4 * (Z.pos (Pos.of_succ_nat (length stk)) - 1)) mod 4294967296).
              { assert ((-4 * Z.of_nat depth + 4 * (Z.pos (Pos.of_succ_nat (length stk)) - 1)) < 0) by Psatz.lia.
                assert (-512 < (-4 * Z.of_nat depth + 4 * (Z.pos (Pos.of_succ_nat (length stk)) - 1))) by Psatz.lia.
                rewrite mod_neg. Psatz.lia. Psatz.lia. Psatz.lia. }
              omega. }
            rewrite <- repr_add in H24.
            generalize (proj2 (SS2 _ _) (conj Hdepthbound H24)). intros Hpop.
            eauto. }
          { destruct init_state_exists' as [s0 Hinit].
            generalize (H3 s0 Hinit). intros [t Hstep].
            assert (program_behaves (semantics tprog) (Goes_wrong (t ** E0 ** t' ** E0))).
            - econstructor; eauto.
              econstructor. eapply star_trans; eauto.
              eapply star_step; eauto. eapply star_refl.
              eauto. red; unfold not; intros. eapply H; eauto.
              unfold not; intros. inv Hs'; try congruence; inv H2.
            - eapply DEFSAFE in H2; inv H2. }
        * destruct init_state_exists' as [s0 Hinit].
          generalize (H3 s0 Hinit). intros [t Hstep].
          assert (program_behaves (semantics tprog) (Goes_wrong (t ** E0))).
          { econstructor; eauto.
            econstructor. eapply star_trans; eauto. eapply star_refl.
            red; unfold not; intros. eapply H; eauto.
            unfold not; intros; inv H2. }
          eapply DEFSAFE in H2; inv H2.
      + inv H.
        { destruct (Classical_Prop.classic (exists t' s', step tge (State stk tf tsp pc1 trs m) t' s')).
          * destruct H as [t' [s' Hs']].
            destruct (Classical_Prop.classic (exists t'' s'', step tge s' t'' s'')).
            { destruct H as [t'' [s'' Hs'']].
              inv Hs'; try congruence. rewrite H20 in H5; inv H5.
              inv Hs''; try congruence. rewrite H19 in H6; inv H6.
              simpl in H21; simpl in H23. unfold Genv.symbol_address in H21. unfold Genv.symbol_address in H23. fold SIZE in H21.
              destruct SIZE_exists as [bSIZE [HSIZE HSIZEvar]].
              destruct STK_exists as [bSTK [HSTK HSTKvar]].
              rewrite HSIZE in H21. rewrite HSTK in H23.
              inv H21. rewrite PMap.gss in H23.
              inv H1. destruct H as [SS1 SS2].
              unfold Genv.symbol_address in SS1; rewrite HSIZE in SS1.
              rewrite SS1 in H22; inv H22. simpl in H23. rewrite repr_add in H23. inv H23.
              simpl in H24. unfold Genv.symbol_address in SS2; rewrite HSTK in SS2.
              rewrite map_length in *. simpl in SS2. rewrite map_length in SS2.
              exploit Mem.load_valid_access; eauto. intro Hperm.
              red in Hperm. destruct Hperm as [Hperm1 Hperm2].
              red in Hperm1. exploit (Hperm1 (Int.unsigned (Int.repr (-4 * Z.of_nat depth + 4 * (Z.pos (Pos.of_succ_nat (length stk)) - 1))))); simpl; try omega.
              intro Hperm. eapply H4 in Hperm; eauto.
              assert (Hdepthbound: (depth < S (length stk))%nat).
              { rewrite Int.unsigned_repr_eq in Hperm.
                replace Int.modulus with 4294967296 in Hperm; try reflexivity.
                destruct (le_dec depth (length stk)); try omega.
                eapply not_le in n0.
                assert (512 < (-4 * Z.of_nat depth + 4 * (Z.pos (Pos.of_succ_nat (length stk)) - 1)) mod 4294967296).
                { assert ((-4 * Z.of_nat depth + 4 * (Z.pos (Pos.of_succ_nat (length stk)) - 1)) < 0) by Psatz.lia.
                  assert (-512 < (-4 * Z.of_nat depth + 4 * (Z.pos (Pos.of_succ_nat (length stk)) - 1))) by Psatz.lia.
                  rewrite mod_neg. Psatz.lia. Psatz.lia. Psatz.lia. }
                omega. }
              rewrite <- repr_add in H24.
              generalize (proj2 (SS2 _ _) (conj Hdepthbound H24)). intros Hpop.
              eauto. }
            { destruct init_state_exists' as [s0 Hinit].
              generalize (H3 s0 Hinit). intros [t Hstep].
              assert (program_behaves (semantics tprog) (Goes_wrong (t ** E0 ** t' ** E0))).
              - econstructor; eauto.
                econstructor. eapply star_trans; eauto.
                eapply star_step; eauto. eapply star_refl.
                eauto. red; unfold not; intros. eapply H; eauto.
                unfold not; intros. inv Hs'; try congruence; inv H2.
              - eapply DEFSAFE in H2; inv H2. }
          * destruct init_state_exists' as [s0 Hinit].
            generalize (H3 s0 Hinit). intros [t Hstep].
            assert (program_behaves (semantics tprog) (Goes_wrong (t ** E0))).
            { econstructor; eauto.
              econstructor. eapply star_trans; eauto. eapply star_refl.
              red; unfold not; intros. eapply H; eauto.
              unfold not; intros; inv H2. }
            eapply DEFSAFE in H2; inv H2. }
        { exploit IHn; eauto. }
  Qed.

  Lemma tr_regs_annot_inv:
    forall kappa sp stk f tf alpha pc1 regs regs' pc2 pcs trs m
      (Hex: forall depth varname base bound, In (ABlocal depth varname (base, bound)) alpha ->
                                        forall size, Int.unsigned (Int.sub bound base) + 1 = Z.pos size ->
                                                exists x, In x (int_ranges (Pos.to_nat size) base) /\ ((align_chunk kappa) | x)),
      (forall ptr, In ptr (sp::map (fun s => match s with | Stackframe _ _ sp _ _ => sp end) stk) ->
              exists b, ptr = Vptr b Int.zero) ->
      tr_regs_annot prog STK kappa f (fn_code tf) pc1 alpha regs regs' pc2 pcs ->
      shadowstack_is_sound (sp::map (fun s => match s with | Stackframe _ _ sp _ _ => sp end) stk) m ->
      (forall depth varname range, In (ABlocal depth varname range) alpha -> (depth < 128)%nat) ->
      (forall id range, In (ABglobal id range) alpha -> id <> STK /\ id <> SIZE) ->
      (forall s0, initial_state tprog s0 -> exists t : trace, star step tge s0 t (State stk tf sp pc1 trs m)) ->
      (forall bSTK, Genv.find_symbol tge STK = Some bSTK -> forall ofs : Z, Mem.perm m bSTK ofs Cur Readable <-> 0 <= ofs < 512) ->
      exists vals, addr_of_annotations kappa tge (sp::map (fun s => match s with | Stackframe _ _ sp _ _ => sp end) stk) alpha vals.
Proof.
    induction alpha; intros.
    - exists nil; econstructor.
    - destruct a.
      + inv H0. generalize (unsigned_p1 (Int.sub bound base)). intros [p Hp].
        rewrite Hp in H11. simpl in H11. generalize (Pos2Nat.is_succ p). intros [n Hn].
        rewrite Hn in H11.
        { exploit tr_local_regs_inv; eauto.
          - eapply H2; eapply in_eq; eauto.
          - generalize (Hex _ _ _ _ (in_eq _ _) _ Hp). rewrite Hn; eauto.
          - intros Hsp. destruct Hsp as [sp' Hsp]. exploit tr_local_regs_star; eauto.
            intros [trs' Hstar]. exploit addr_of_local_exists; eauto.
            intros [vptrs Hvptrs]. exploit IHalpha; eauto.
            + intros. eapply Hex. eapply in_cons; eauto. eauto.
            + intros; eapply H2; eapply in_cons; eauto.
            + intros; eapply H3; eapply in_cons; eauto.
            + intros. eapply H4 in H0. destruct H0. eexists.
              eapply star_trans; eauto.
            + intros [vals Hvals]. eexists; econstructor; eauto. }
      + inv H0. exploit symbols_preserved'; eauto. intros Hsymb.
        destruct (unsigned_p1 (Int.sub bound base)) as [p Hp].
        rewrite Hp in H11. exploit tr_global_regs_star; eauto.
        intros [trs' Hstar]. exploit IHalpha; eauto.
        * intros. eapply Hex. eapply in_cons; eauto. eauto.
        * intros; eapply H2; eapply in_cons; eauto.
        * intros; eapply H3; eapply in_cons; eauto.
        * intros. eapply H4 in H0. destruct H0 as [t Hinit].
          eexists; eapply star_trans; eauto.
        * intros [vals' Hvals'].
          generalize (addr_of_global_exists id kappa (Z.to_nat (Z.pos p)) base).
          intros [vals Hvals].
          econstructor. econstructor; eauto.
  Qed.

  Lemma valid_pointer_inject_inv:
    forall j m1 m2,
      Mem.inject j m1 m2 ->
      (forall b b' delta, j b = Some (b', delta) -> delta = 0) ->
      (forall b b' o k p, j b = Some (b', 0) -> (Mem.perm m1 b o k p <-> Mem.perm m2 b' o k p)) ->
      forall b b', j b = Some (b', 0) -> forall ofs, Mem.valid_pointer m2 b' ofs = Mem.valid_pointer m1 b ofs.
Proof.
    intros.
    unfold Mem.valid_pointer.
    destruct (Mem.perm_dec m1 b ofs Cur Nonempty).
    - generalize (proj1 (H1 _ _ _ _ _ H2) p). intros.
      destruct (Mem.perm_dec m2 b' ofs Cur Nonempty); try congruence; eauto.
    - destruct (Mem.perm_dec m2 b' ofs Cur Nonempty); try congruence; eauto.
      generalize (proj2 (H1 _ _ _ _ _ H2) p). intros.
      exfalso; eapply n; eapply H3.
  Qed.
  
  Lemma eval_condition_translated':
    forall j a ta ofsa tofsa m tm tvals vals,
      Val.inject j (Vptr a ofsa) (Vptr ta tofsa) ->
      Mem.inject j m tm ->
      list_forall2 (Val.inject j) vals tvals ->
      (forall v : val, In v tvals -> exists (b : block) (ofs : int), v = Vptr b ofs) ->
      (forall b b' delta, j b = Some (b', delta) -> delta = 0) ->
      (forall b b1 b2, j b1 = Some (b, 0) -> j b2 = Some (b, 0) -> b1 = b2) ->
      (forall b b' o k p, j b = Some (b', 0) -> (Mem.perm m b o k p <-> Mem.perm tm b' o k p)) ->
      (forall (tb : block) (tofs : int),
          In (Vptr tb tofs) tvals ->
          eval_condition (Ccompu Ceq) ((Vptr ta tofsa) :: Vptr tb tofs :: nil) tm = Some true \/
          eval_condition (Ccompu Ceq) ((Vptr ta tofsa) :: Vptr tb tofs :: nil) tm = Some false) ->
      forall (b : block) (ofs : int),
        In (Vptr b ofs) vals ->
        eval_condition (Ccompu Ceq) ((Vptr a ofsa) :: Vptr b ofs :: nil) m = Some true \/
        eval_condition (Ccompu Ceq) ((Vptr a ofsa) :: Vptr b ofs :: nil) m = Some false.
Proof.
    induction tvals; intros.
    - inv H1. inv H7.
    - inv H1. inv H7.
      + generalize (H2 _ (in_eq _ _)). intros [b1 [ofs1 Hptr]]. subst a0.
        generalize (H6 _ _ (in_eq _ _)). intros Ha.
        simpl. simpl in Ha.
        inv H. exploit H3; eauto. intros; subst delta.
        inv H11. exploit H3; eauto. intros; subst delta. repeat rewrite Int.add_zero in Ha.
        exploit valid_pointer_inject_inv; eauto. instantiate (1 := Int.unsigned ofs). intros HA.
        exploit valid_pointer_inject_inv; eauto. instantiate (1 := Int.unsigned ofs - 1). intros HB.
        generalize H9; clear H9; intros H9.
        exploit valid_pointer_inject_inv; eauto. instantiate (1 := Int.unsigned ofsa). intros HC.
        exploit valid_pointer_inject_inv; eauto. instantiate (1 := Int.unsigned ofsa - 1). intros HD.
        rewrite <- ! HA; rewrite <- ! HB; rewrite <- ! HC; rewrite <- ! HD.
        destruct (eq_block a b).
        * destruct (eq_block ta b1); eauto.
          subst a. rewrite H9 in H8; inv H8.
          exfalso; eapply n; eauto.
        * destruct (eq_block ta b1); eauto.
          subst ta. generalize (H4 _ _ _ H9 H8). intros.
          exfalso; eapply n; eauto.
      + eapply IHtvals; eauto.
        * intros; eapply H2; eapply in_cons; eauto.
        * intros; eapply H6; eapply in_cons; eauto.
  Qed.

  Lemma eval_condition_is_true_implies:
    forall a b m,
      Val.of_optbool (eval_condition (Ccompu Ceq) (a :: b :: nil) m) = Vtrue ->
      a = b.
Proof.
    intros. simpl in H. destruct a; destruct b; simpl in H; auto; try (inv H; fail).
    - generalize (Int.eq_spec i i0); intros. destruct (Int.eq i i0); inv H; auto.
    - destruct (Int.eq i Int.zero && (Mem.valid_pointer m b (Int.unsigned i0) || Mem.valid_pointer m b (Int.unsigned i0 - 1))); simpl in H; inv H.
    - destruct (Int.eq i0 Int.zero && (Mem.valid_pointer m b0 (Int.unsigned i) || Mem.valid_pointer m b0 (Int.unsigned i - 1))); simpl in H; inv H.
    - destruct (eq_block b0 b).
      + subst b0. destruct ((Mem.valid_pointer m b (Int.unsigned i) || Mem.valid_pointer m b (Int.unsigned i - 1)) && (Mem.valid_pointer m b (Int.unsigned i0) || Mem.valid_pointer m b (Int.unsigned i0 - 1))); inv H.
        generalize (Int.eq_spec i i0); intros. destruct (Int.eq i i0); try congruence. inv H1.
      + destruct (Mem.valid_pointer m b0 (Int.unsigned i) && Mem.valid_pointer m b (Int.unsigned i0)); simpl in H; inv H.
  Qed.
  
  Lemma valid_access_in_bounds_invariant:
    forall p, list_norepet (prog_defs_names p) ->
         MoreSemantics.invariant (semantics p) (fun x => MoreRTL.valid_access_in_bounds p (MoreRTL.mem_of_state x)).
Proof.
    unfold MoreSemantics.invariant; intros.
    inv H0. destruct H1 as [tr [HA HB]].
    inv HA. eapply MoreRTL.valid_access_in_bounds_invariant; eauto.
    red. eexists; eexists; split; eauto.
    econstructor; eauto.
  Qed.

  Lemma range_leb_spec:
    forall a1 a2 b1 b2,
      range_leb (a1, a2) (b1, b2) = true ->
      Int.unsigned b1 <= Int.unsigned a1 /\ Int.unsigned a2 <= Int.unsigned b2.
Proof.
    intros. simpl in H.
    case_eq (Z.compare (Int.unsigned a1) (Int.unsigned b1)); intros; rewrite H0 in H; try (inv H; fail).
    - case_eq (Z.compare (Int.unsigned a2) (Int.unsigned b2)); intros; rewrite H1 in H; try (inv H; fail).
      + eapply Z.compare_eq_iff in H0; eapply Z.compare_eq_iff in H1. omega.
      + eapply Z.compare_eq_iff in H0. generalize (proj1 (Z.compare_lt_iff _ _) H1); intros.
        omega.
    - case_eq (Z.compare (Int.unsigned a2) (Int.unsigned b2)); intros; rewrite H1 in H; try (inv H; fail).
      + eapply Z.compare_eq_iff in H1. eapply Z.compare_gt_iff in H0. omega.
      + eapply Z.compare_gt_iff in H0. generalize (proj1 (Z.compare_lt_iff _ _) H1); intros.
        omega.
  Qed.

  Opaque range_leb.

  Lemma addr_of_local_determ:
    forall kappa sp n base vals vals',
      addr_of_local kappa sp base n vals ->
      addr_of_local kappa sp base n vals' ->
      vals = vals'.
Proof.
    induction n; intros.
    - inv H; inv H0; eauto.
    - inv H; inv H0.
      generalize (IHn _ _ _ H2 H3); intros; subst. eauto.
  Qed.

  Lemma addr_of_global_determ:
    forall kappa id n ofs vals vals',
      addr_of_global kappa id ofs n vals ->
      addr_of_global kappa id ofs n vals' ->
      vals = vals'.
Proof.
    induction n; intros.
    - inv H; inv H0; eauto.
    - inv H; inv H0.
      generalize (IHn _ _ _ H2 H3); intros; subst; eauto.
  Qed.

  Lemma addr_of_annotations_determ:
    forall kappa ge sps alpha vals vals',
      addr_of_annotations kappa ge sps alpha vals ->
      addr_of_annotations kappa ge sps alpha vals' ->
      vals = vals'.
Proof.
    induction alpha; intros.
    - inv H; inv H0; eauto.
    - inv H; inv H0.
      + generalize (IHalpha _ _ H7 H13). intros; subst. rewrite H10 in H3; inv H3.
        rewrite H11 in H4; inv H4.
        generalize (addr_of_local_determ _ _ _ _ _ _ H5 H12). intros; subst; eauto.
      + generalize (IHalpha _ _ H7 H12). intros; subst. rewrite H10 in H4; inv H4.
        rewrite H8 in H3; inv H3.
        generalize (addr_of_global_determ _ _ _ _ _ _ H5 H11). intros; subst; eauto.
  Qed.

  Lemma load_align_chunk:
    forall kappa m b ofs v,
      Mem.load kappa m b ofs = Some v ->
      (align_chunk kappa | ofs).
Proof.
    intros; exploit Mem.load_valid_access; eauto.
    intros [A B]. assumption.
  Qed.

  Lemma store_align_chunk:
    forall kappa m b ofs v m',
      Mem.store kappa m b ofs v = Some m' ->
      (align_chunk kappa | ofs).
Proof.
    intros; exploit Mem.store_valid_access_3; eauto.
    intros [A B]. assumption.
  Qed.

  Lemma sizeof_prog:
    forall id,
      MoreRTL.sizeof prog id <= Int.max_unsigned.
Proof.
    unfold MoreRTL.sizeof; intros. replace Int.max_unsigned with 4294967295; try reflexivity.
    case_eq (AssocList.assoc id (prog_defs prog)); intros; try Psatz.nia.
    destruct g; try Psatz.nia.
    generalize (AssocList.assoc_in _ _ H). intros.
    eapply prog_defs_init_data_is_bounded.
    eapply in_map_iff. exists (id, Gvar v); eauto.
  Qed.
  
  Lemma is_trivial_annotation_load_correct:
    forall s ts f tf sp tsp pc rs trs m tm alpha kappa addr args dst pc' a v,
      match_states (State s f sp pc rs m) (State ts tf tsp pc trs tm) ->
      MoreRTL.is_trivial_annotation prog alpha kappa addr = true ->
      (fn_code f)!pc = Some (Iload alpha kappa addr args dst pc') ->
      eval_addressing ge sp addr (rs##args) = Some a ->
      Mem.loadv kappa m a = Some v ->
      exists vals, addr_of_annotations kappa ge (sp::map (fun s => match s with | Stackframe _ _ sp _ _ => sp end) s) (snd alpha) vals /\
              (match snd alpha with | nil => True | _ => In a vals end).
Proof.
    intros. destruct alpha; simpl in H0. destruct l.
    - simpl. exists nil. split; auto.
      econstructor.
    - unfold MoreRTL.is_trivial_annotation in H0. destruct l; simpl in H0; inv H0.
      destruct a0.
      + destruct depth; inv H5.
        destruct addr; inv H4. destruct range.
        destruct (unsigned_p1 (Int.sub i2 i1)) as [n Hn].
        destruct (addr_of_local_exists (Pos.to_nat n) kappa i1 sp) as [vptrs Hvptrs].
        simpl. eexists. split.
        * econstructor; eauto.
          { simpl. eauto. }
          { econstructor. }
        * simpl in H2. destruct (rs ## args); inv H2.
          exploit range_leb_spec; eauto. intros.
          inv H. simpl. rewrite Int.add_zero_l.
          simpl in H3. rewrite app_nil_r.
          exploit load_align_chunk; eauto. rewrite Int.add_zero_l. intros.
          exploit transf_function_spec; eauto. intros [pcs HA]. inv HA.
          simpl in Hlocrange. generalize (Hlocrange _ _ _ _ (or_introl eq_refl)). intros XA.
          generalize (int_add_sub _ _ XA). intros XB. rewrite Hn in XB.
          rewrite <- positive_nat_Z in XB.
          eapply (proj2 (addr_of_local_in _ _ _ _ _ Hvptrs XB (Vptr sp0 i0))).
          simpl. exists i0. rewrite Int.add_zero_l. repeat split; auto.
          { Psatz.nia. }
          { rewrite positive_nat_Z. rewrite <- Hn.
            rewrite Int.unsigned_sub_borrow.
            unfold Int.sub_borrow. rewrite Int.unsigned_zero.
            destruct (zlt (Int.unsigned i2 - Int.unsigned i1 - 0) 0); try Psatz.nia.
            rewrite Int.unsigned_zero. Psatz.nia. }
      + destruct addr; inv H5.
        * destruct (ident_eq b i0); inv H4.
          simpl. simpl in H2. destruct (rs ## args); inv H2.
          unfold Genv.symbol_address in *. case_eq (Genv.find_symbol ge i0); intros; rewrite H0 in H3; inv H3.
          destruct range. destruct (unsigned_p1 (Int.sub i3 i2)) as [n Hn].
          destruct (addr_of_global_exists b kappa (Pos.to_nat n) i2) as [vptrs Hvptrs].
          eexists. split.
          { econstructor; eauto. econstructor. }
          { exploit range_leb_spec; eauto. intros.
            inv H. simpl. rewrite app_nil_r.
            exploit load_align_chunk; eauto. intros.
            exploit transf_function_spec; eauto. intros [pcs HA]. inv HA.
            simpl in Hglobrange. generalize (Hglobrange _ _ _ (or_introl eq_refl)). intros XA.
            generalize (int_add_sub _ _ XA). intros XB. rewrite Hn in XB.
            rewrite <- positive_nat_Z in XB.
            eapply (proj2 (addr_of_global_in _ _ _ _ _ Hvptrs XB (Vptr b i1))).
            exists i1; repeat split; eauto.
            - Psatz.nia.
            - rewrite positive_nat_Z. rewrite <- Hn.
              rewrite Int.unsigned_sub_borrow.
              unfold Int.sub_borrow. rewrite Int.unsigned_zero.
              destruct (zlt (Int.unsigned i3 - Int.unsigned i2 - 0) 0); try Psatz.nia.
              rewrite Int.unsigned_zero. Psatz.nia. }
        * destruct (ident_eq b i0); inv H4.
          simpl. simpl in H2. destruct (args); inv H2. destruct args; inv H4.
          destruct range. exploit range_leb_spec; eauto.
          unfold Genv.symbol_address in *. case_eq (Genv.find_symbol ge i0); intros; rewrite H0 in H3; inv H3.
          case_eq (rs # r); intros; rewrite H3 in H6; inv H6.
          generalize norepet_prog_defs. intros Hnorepet.
          generalize (valid_access_in_bounds_invariant prog Hnorepet). intros Hinvariant.
          unfold MoreSemantics.invariant in Hinvariant. unfold MoreSemantics.reachable in Hinvariant.
          inv H. destruct init_state_exists as [s0 Hinit].
          generalize (STEP s0 Hinit). intros Hstep.
          generalize (Mem.load_valid_access _ _ _ _ _ H7). intros Hvalid.
          edestruct Hinvariant.
          { destruct Hstep. eexists. eexists. split; eauto. unfold ge in H.
            eapply FSIM_implies; eauto. }
          { eapply H0. }
          { eapply Hvalid. }
          destruct (unsigned_p1 (Int.sub i3 i2)) as [n Hn].
          destruct (addr_of_global_exists b kappa (Pos.to_nat n) i2) as [vptrs Hvptrs].
          eexists. split.
          { econstructor; eauto. econstructor. }
          { simpl. rewrite app_nil_r.
            exploit load_align_chunk; eauto. intros.
            exploit transf_function_spec; eauto. intros [pcs HA]. inv HA.
            simpl in Hglobrange. generalize (Hglobrange _ _ _ (or_introl eq_refl)). intros XA.
            generalize (int_add_sub _ _ XA). intros XB. rewrite Hn in XB.
            rewrite <- positive_nat_Z in XB.
            eapply (proj2 (addr_of_global_in _ _ _ _ _ Hvptrs XB (Vptr b (Int.add i1 i4)))).
            exists (Int.add i1 i4); repeat split; eauto.
            { destruct H2. rewrite Int.unsigned_zero in H2.
              generalize (Int.unsigned_range i2). intros LO.
              assert (Int.unsigned i2 = 0); try Psatz.nia. }
            { rewrite positive_nat_Z. rewrite <- Hn.
              rewrite Int.unsigned_sub_borrow.
              unfold Int.sub_borrow. rewrite Int.unsigned_zero.
              destruct (zlt (Int.unsigned i3 - Int.unsigned i2 - 0) 0); try Psatz.nia.
              rewrite Int.unsigned_zero. eapply Z.le_lt_trans.
              - eapply H4.
              - eapply Z.le_lt_trans.
                Focus 2. instantiate (1 := Int.unsigned (Int.repr (Z.max 0 (Z.min (MoreRTL.sizeof prog i0 - size_chunk kappa) Int.max_unsigned)))); try Psatz.nia.
                rewrite Int.unsigned_repr; try Psatz.nia.
                rewrite Zmax_spec. destruct (zlt (Z.min (MoreRTL.sizeof prog i0 - size_chunk kappa) Int.max_unsigned) 0); try Psatz.nia.
                rewrite Zmin_spec in l. destruct (zlt (MoreRTL.sizeof prog i0 - size_chunk kappa) Int.max_unsigned); try Psatz.nia.
                change Int.max_unsigned with 4294967295 in l. Psatz.nia.
                rewrite Zmin_spec. destruct (zlt (MoreRTL.sizeof prog i0 - size_chunk kappa) Int.max_unsigned); try Psatz.nia.
                generalize (sizeof_prog i0). generalize (size_chunk_pos kappa). unfold Int.max_unsigned. Psatz.nia.
                rewrite Zmax_spec. destruct (zlt (Z.min (MoreRTL.sizeof prog i0 - size_chunk kappa) Int.max_unsigned) 0); try Psatz.nia. change Int.max_unsigned with 4294967295. Psatz.nia. } }
        * destruct (ident_eq b i1); inv H4.
          simpl. simpl in H2. destruct (args); inv H2. destruct args; inv H4.
          destruct range. exploit range_leb_spec; eauto.
          unfold Genv.symbol_address in *. case_eq (Genv.find_symbol ge i1); intros; rewrite H0 in H3; inv H3.
          case_eq (rs # r); intros; rewrite H3 in H6; inv H6.
          generalize norepet_prog_defs. intros Hnorepet.
          generalize (valid_access_in_bounds_invariant prog Hnorepet). intros Hinvariant.
          unfold MoreSemantics.invariant in Hinvariant. unfold MoreSemantics.reachable in Hinvariant.
          inv H. destruct init_state_exists as [s0 Hinit].
          generalize (STEP s0 Hinit). intros Hstep.
          generalize (Mem.load_valid_access _ _ _ _ _ H7). intros Hvalid.
          edestruct Hinvariant.
          { destruct Hstep. eexists. eexists. split; eauto. unfold ge in H.
            eapply FSIM_implies; eauto. }
          { eapply H0. }
          { eapply Hvalid. }
          destruct (unsigned_p1 (Int.sub i4 i3)) as [n Hn].
          destruct (addr_of_global_exists b kappa (Pos.to_nat n) i3) as [vptrs Hvptrs].
          eexists. split.
          { econstructor; eauto. econstructor. }
          { simpl. rewrite app_nil_r.
            exploit load_align_chunk; eauto. intros.
            exploit transf_function_spec; eauto. intros [pcs HA]. inv HA.
            simpl in Hglobrange. generalize (Hglobrange _ _ _ (or_introl eq_refl)). intros XA.
            generalize (int_add_sub _ _ XA). intros XB. rewrite Hn in XB.
            rewrite <- positive_nat_Z in XB.
            eapply (proj2 (addr_of_global_in _ _ _ _ _ Hvptrs XB (Vptr b (Int.add i2 (Int.mul i5 i0))))).
            eexists; repeat split; eauto.
            { destruct H2. rewrite Int.unsigned_zero in H2.
              generalize (Int.unsigned_range i3). intros LO.
              assert (Int.unsigned i3 = 0); try Psatz.nia. }
            { rewrite positive_nat_Z. rewrite <- Hn.
              rewrite Int.unsigned_sub_borrow.
              unfold Int.sub_borrow. rewrite Int.unsigned_zero.
              destruct (zlt (Int.unsigned i4 - Int.unsigned i3 - 0) 0); try Psatz.nia.
              rewrite Int.unsigned_zero. eapply Z.le_lt_trans.
              - eapply H4.
              - eapply Z.le_lt_trans.
                Focus 2. instantiate (1 := Int.unsigned (Int.repr (Z.max 0 (Z.min (MoreRTL.sizeof prog i1 - size_chunk kappa) Int.max_unsigned)))); try Psatz.nia.
                rewrite Int.unsigned_repr; try Psatz.nia.
                rewrite Zmax_spec. destruct (zlt (Z.min (MoreRTL.sizeof prog i1 - size_chunk kappa) Int.max_unsigned) 0); try Psatz.nia.
                rewrite Zmin_spec in l. destruct (zlt (MoreRTL.sizeof prog i1 - size_chunk kappa) Int.max_unsigned); try Psatz.nia.
                change Int.max_unsigned with 4294967295 in l. Psatz.nia.
                rewrite Zmin_spec. destruct (zlt (MoreRTL.sizeof prog i1 - size_chunk kappa) Int.max_unsigned); try Psatz.nia.
                generalize (sizeof_prog i1). generalize (size_chunk_pos kappa). unfold Int.max_unsigned. Psatz.nia.
                rewrite Zmax_spec. destruct (zlt (Z.min (MoreRTL.sizeof prog i1 - size_chunk kappa) Int.max_unsigned) 0); try Psatz.nia. change Int.max_unsigned with 4294967295. Psatz.nia. } }
  Qed.

  Lemma is_trivial_annotation_store_correct:
    forall s ts f tf sp tsp pc rs trs m tm alpha kappa addr args src pc' a m',
      match_states (State s f sp pc rs m) (State ts tf tsp pc trs tm) ->
      MoreRTL.is_trivial_annotation prog alpha kappa addr = true ->
      (fn_code f)!pc = Some (Istore alpha kappa addr args src pc') ->
      eval_addressing ge sp addr (rs##args) = Some a ->
      Mem.storev kappa m a (rs#src) = Some m' ->
      exists vals, addr_of_annotations kappa ge (sp::map (fun s => match s with | Stackframe _ _ sp _ _ => sp end) s) (snd alpha) vals /\
              (match snd alpha with | nil => True | _ => In a vals end).
Proof.
    intros. destruct alpha; simpl in H0. destruct l.
    - simpl. exists nil. split; auto.
      econstructor.
    - unfold MoreRTL.is_trivial_annotation in H0. destruct l; simpl in H0; inv H0.
      destruct a0.
      + destruct depth; inv H5.
        destruct addr; inv H4. destruct range.
        destruct (unsigned_p1 (Int.sub i2 i1)) as [n Hn].
        destruct (addr_of_local_exists (Pos.to_nat n) kappa i1 sp) as [vptrs Hvptrs].
        simpl. eexists. split.
        * econstructor; eauto.
          { simpl. eauto. }
          { econstructor. }
        * simpl in H2. destruct (rs ## args); inv H2.
          exploit range_leb_spec; eauto. intros.
          inv H. simpl. rewrite Int.add_zero_l.
          simpl in H3. rewrite app_nil_r.
          exploit store_align_chunk; eauto. rewrite Int.add_zero_l. intros.
          exploit transf_function_spec; eauto. intros [pcs HA]. inv HA.
          simpl in Hlocrange. generalize (Hlocrange _ _ _ _ (or_introl eq_refl)). intros XA.
          generalize (int_add_sub _ _ XA). intros XB. rewrite Hn in XB.
          rewrite <- positive_nat_Z in XB.
          eapply (proj2 (addr_of_local_in _ _ _ _ _ Hvptrs XB (Vptr sp0 i0))).
          simpl. exists i0. rewrite Int.add_zero_l. repeat split; auto.
          { Psatz.nia. }
          { rewrite positive_nat_Z. rewrite <- Hn.
            rewrite Int.unsigned_sub_borrow.
            unfold Int.sub_borrow. rewrite Int.unsigned_zero.
            destruct (zlt (Int.unsigned i2 - Int.unsigned i1 - 0) 0); try Psatz.nia.
            rewrite Int.unsigned_zero. Psatz.nia. }
      + destruct addr; inv H5.
        * destruct (ident_eq b i0); inv H4.
          simpl. simpl in H2. destruct (rs ## args); inv H2.
          unfold Genv.symbol_address in *. case_eq (Genv.find_symbol ge i0); intros; rewrite H0 in H3; inv H3.
          destruct range. destruct (unsigned_p1 (Int.sub i3 i2)) as [n Hn].
          destruct (addr_of_global_exists b kappa (Pos.to_nat n) i2) as [vptrs Hvptrs].
          eexists. split.
          { econstructor; eauto. econstructor. }
          { exploit range_leb_spec; eauto. intros.
            inv H. simpl. rewrite app_nil_r.
            exploit store_align_chunk; eauto. intros.
            exploit transf_function_spec; eauto. intros [pcs HA]. inv HA.
            simpl in Hglobrange. generalize (Hglobrange _ _ _ (or_introl eq_refl)). intros XA.
            generalize (int_add_sub _ _ XA). intros XB. rewrite Hn in XB.
            rewrite <- positive_nat_Z in XB.
            eapply (proj2 (addr_of_global_in _ _ _ _ _ Hvptrs XB (Vptr b i1))).
            exists i1; repeat split; eauto.
            - Psatz.nia.
            - rewrite positive_nat_Z. rewrite <- Hn.
              rewrite Int.unsigned_sub_borrow.
              unfold Int.sub_borrow. rewrite Int.unsigned_zero.
              destruct (zlt (Int.unsigned i3 - Int.unsigned i2 - 0) 0); try Psatz.nia.
              rewrite Int.unsigned_zero. Psatz.nia. }
        * destruct (ident_eq b i0); inv H4.
          simpl. simpl in H2. destruct (args); inv H2. destruct args; inv H4.
          destruct range. exploit range_leb_spec; eauto.
          unfold Genv.symbol_address in *. case_eq (Genv.find_symbol ge i0); intros; rewrite H0 in H3; inv H3.
          case_eq (rs # r); intros; rewrite H3 in H6; inv H6.
          generalize norepet_prog_defs. intros Hnorepet.
          generalize (valid_access_in_bounds_invariant prog Hnorepet). intros Hinvariant.
          unfold MoreSemantics.invariant in Hinvariant. unfold MoreSemantics.reachable in Hinvariant.
          inv H. destruct init_state_exists as [s0 Hinit].
          generalize (STEP s0 Hinit). intros Hstep.
          generalize (Mem.store_valid_access_3 _ _ _ _ _ _ H7). intros Hvalid.
          edestruct Hinvariant.
          { destruct Hstep. eexists. eexists. split; eauto. unfold ge in H.
            eapply FSIM_implies; eauto. }
          { eapply H0. }
          { eapply Hvalid. }
          destruct (unsigned_p1 (Int.sub i3 i2)) as [n Hn].
          destruct (addr_of_global_exists b kappa (Pos.to_nat n) i2) as [vptrs Hvptrs].
          eexists. split.
          { econstructor; eauto. econstructor. }
          { simpl. rewrite app_nil_r.
            exploit store_align_chunk; eauto. intros.
            exploit transf_function_spec; eauto. intros [pcs HA]. inv HA.
            simpl in Hglobrange. generalize (Hglobrange _ _ _ (or_introl eq_refl)). intros XA.
            generalize (int_add_sub _ _ XA). intros XB. rewrite Hn in XB.
            rewrite <- positive_nat_Z in XB.
            eapply (proj2 (addr_of_global_in _ _ _ _ _ Hvptrs XB (Vptr b (Int.add i1 i4)))).
            exists (Int.add i1 i4); repeat split; eauto.
            { destruct H2. rewrite Int.unsigned_zero in H2.
              generalize (Int.unsigned_range i2). intros LO.
              assert (Int.unsigned i2 = 0); try Psatz.nia. }
            { rewrite positive_nat_Z. rewrite <- Hn.
              rewrite Int.unsigned_sub_borrow.
              unfold Int.sub_borrow. rewrite Int.unsigned_zero.
              destruct (zlt (Int.unsigned i3 - Int.unsigned i2 - 0) 0); try Psatz.nia.
              rewrite Int.unsigned_zero. eapply Z.le_lt_trans.
              - eapply H4.
              - eapply Z.le_lt_trans.
                Focus 2. instantiate (1 := Int.unsigned (Int.repr (Z.max 0 (Z.min (MoreRTL.sizeof prog i0 - size_chunk kappa) Int.max_unsigned)))); try Psatz.nia.
                rewrite Int.unsigned_repr; try Psatz.nia.
                rewrite Zmax_spec. destruct (zlt (Z.min (MoreRTL.sizeof prog i0 - size_chunk kappa) Int.max_unsigned) 0); try Psatz.nia.
                rewrite Zmin_spec in l. destruct (zlt (MoreRTL.sizeof prog i0 - size_chunk kappa) Int.max_unsigned); try Psatz.nia.
                change Int.max_unsigned with 4294967295 in l. Psatz.nia.
                rewrite Zmin_spec. destruct (zlt (MoreRTL.sizeof prog i0 - size_chunk kappa) Int.max_unsigned); try Psatz.nia.
                generalize (sizeof_prog i0). generalize (size_chunk_pos kappa). unfold Int.max_unsigned. Psatz.nia.
                rewrite Zmax_spec. destruct (zlt (Z.min (MoreRTL.sizeof prog i0 - size_chunk kappa) Int.max_unsigned) 0); try Psatz.nia. change Int.max_unsigned with 4294967295. Psatz.nia. } }
        * destruct (ident_eq b i1); inv H4.
          simpl. simpl in H2. destruct (args); inv H2. destruct args; inv H4.
          destruct range. exploit range_leb_spec; eauto.
          unfold Genv.symbol_address in *. case_eq (Genv.find_symbol ge i1); intros; rewrite H0 in H3; inv H3.
          case_eq (rs # r); intros; rewrite H3 in H6; inv H6.
          generalize norepet_prog_defs. intros Hnorepet.
          generalize (valid_access_in_bounds_invariant prog Hnorepet). intros Hinvariant.
          unfold MoreSemantics.invariant in Hinvariant. unfold MoreSemantics.reachable in Hinvariant.
          inv H. destruct init_state_exists as [s0 Hinit].
          generalize (STEP s0 Hinit). intros Hstep.
          generalize (Mem.store_valid_access_3 _ _ _ _ _ _ H7). intros Hvalid.
          edestruct Hinvariant.
          { destruct Hstep. eexists. eexists. split; eauto. unfold ge in H.
            eapply FSIM_implies; eauto. }
          { eapply H0. }
          { eapply Hvalid. }
          destruct (unsigned_p1 (Int.sub i4 i3)) as [n Hn].
          destruct (addr_of_global_exists b kappa (Pos.to_nat n) i3) as [vptrs Hvptrs].
          eexists. split.
          { econstructor; eauto. econstructor. }
          { simpl. rewrite app_nil_r.
            exploit store_align_chunk; eauto. intros.
            exploit transf_function_spec; eauto. intros [pcs HA]. inv HA.
            simpl in Hglobrange. generalize (Hglobrange _ _ _ (or_introl eq_refl)). intros XA.
            generalize (int_add_sub _ _ XA). intros XB. rewrite Hn in XB.
            rewrite <- positive_nat_Z in XB.
            eapply (proj2 (addr_of_global_in _ _ _ _ _ Hvptrs XB (Vptr b (Int.add i2 (Int.mul i5 i0))))).
            eexists; repeat split; eauto.
            { destruct H2. rewrite Int.unsigned_zero in H2.
              generalize (Int.unsigned_range i3). intros LO.
              assert (Int.unsigned i3 = 0); try Psatz.nia. }
            { rewrite positive_nat_Z. rewrite <- Hn.
              rewrite Int.unsigned_sub_borrow.
              unfold Int.sub_borrow. rewrite Int.unsigned_zero.
              destruct (zlt (Int.unsigned i4 - Int.unsigned i3 - 0) 0); try Psatz.nia.
              rewrite Int.unsigned_zero. eapply Z.le_lt_trans.
              - eapply H4.
              - eapply Z.le_lt_trans.
                Focus 2. instantiate (1 := Int.unsigned (Int.repr (Z.max 0 (Z.min (MoreRTL.sizeof prog i1 - size_chunk kappa) Int.max_unsigned)))); try Psatz.nia.
                rewrite Int.unsigned_repr; try Psatz.nia.
                rewrite Zmax_spec. destruct (zlt (Z.min (MoreRTL.sizeof prog i1 - size_chunk kappa) Int.max_unsigned) 0); try Psatz.nia.
                rewrite Zmin_spec in l. destruct (zlt (MoreRTL.sizeof prog i1 - size_chunk kappa) Int.max_unsigned); try Psatz.nia.
                change Int.max_unsigned with 4294967295 in l. Psatz.nia.
                rewrite Zmin_spec. destruct (zlt (MoreRTL.sizeof prog i1 - size_chunk kappa) Int.max_unsigned); try Psatz.nia.
                generalize (sizeof_prog i1). generalize (size_chunk_pos kappa). unfold Int.max_unsigned. Psatz.nia.
                rewrite Zmax_spec. destruct (zlt (Z.min (MoreRTL.sizeof prog i1 - size_chunk kappa) Int.max_unsigned) 0); try Psatz.nia. change Int.max_unsigned with 4294967295. Psatz.nia. } }
  Qed.

  Lemma load_step:
    forall s ts f tf sp tsp pc rs trs m tm alpha kappa addr args dst pc' a v vals (Htriv: MoreRTL.is_trivial_annotation prog alpha kappa addr = false) (Hsingleton: is_singleton (snd alpha) = false),
      match_states (State s f sp pc rs m) (State ts tf tsp pc trs tm) ->
      (fn_code f)!pc = Some (Iload alpha kappa addr args dst pc') ->
      eval_addressing ge sp addr (rs##args) = Some a ->
      Mem.loadv kappa m a = Some v ->
      addr_of_annotations kappa ge (sp::map (fun s => match s with | Stackframe _ _ sp _ _ => sp end) s) (snd alpha) vals ->
      ((forall b ofs, In (Vptr b ofs) vals -> (eval_condition (Ccompu Ceq) (a::(Vptr b ofs)::nil) m = Some true \/ eval_condition (Ccompu Ceq) (a::(Vptr b ofs)::nil) m = Some false)) /\ (match snd alpha with | nil => True | _ => In a vals end)).
Proof.
    intros. inv H. exploit transf_function_spec; eauto. intros [pcs HA]. inv HA.
    rewrite Htriv in H14. rewrite Hsingleton in H14. inv H14.
    assert (HB: forall sp : val, In sp (Vptr tsp0 Int.zero :: map (fun s0 : stackframe => match s0 with | Stackframe _ _ sp1 _ _ => sp1 end) ts) -> exists b : block, sp = Vptr b Int.zero).
    { intros. destruct H. inv H6; eauto.
      eapply match_stackframes_sps_are_ptrs; eauto. }
    exploit addr_of_annotations_translated; eauto.
    { instantiate (2 := j). instantiate (1 := (Vptr tsp0 Int.zero) :: (map (fun s => match s with | Stackframe _ _ sp _ _ => sp end) ts)). econstructor.
      - eexists; eexists; repeat split; eauto.
      - eapply match_stackframes_sps; eauto. }
    { intros. eapply GINJ.
      eapply Genv.genv_symb_range; eauto. }
    intros [tvals [AA BB]].
    exploit (eval_addressing_inj ge tge).
    { intros. eapply symbol_address_inject; eauto. intros; eapply GINJ_implies; eauto. }
    { instantiate (1 := Vptr tsp0 Int.zero). econstructor; eauto. rewrite Int.add_zero. eauto. }
    { instantiate (1 := trs##args). eapply regs_agree_inject_list; eauto.
      intros; eapply max_reg_function_use; eauto. }
    { eauto. }
    intros [ta [Heval Hinj]]. assert (RES': regs_agree j (max_reg_function f) rs (trs # reg0 <- ta)).
    { intro. generalize (RES r). intros [[LA LB] | [LA LB]].
      - left; split; auto. rewrite PMap.gso; try xomega. eauto.
      - right; split; auto. rewrite UNDEF; try xomega. eauto. }
    exploit tr_regs_annot_correct; eauto.
    intros [trs' [Hstar [X [Y Z]]]]. exploit tr_cmp_regs_correct; eauto.
    { eapply tr_regs_annot_regs_plt; eauto. }
    { eapply tr_regs_annot_regs_norepet; eauto. } instantiate (1 := tm). instantiate (1 := (Vptr tsp0 Int.zero)).
    instantiate (1 := ts). intros [trs'' [Hstar' [XX YY]]].
    rewrite <- (Z reg0 ((proj2 (not_in_app _ _ _ _)) (conj H18 H19))) in XX.
    rewrite PMap.gss in XX. exploit Mem.loadv_inject; eauto. intros [tv [Hload' Hinj']].
    generalize (regs_are_unknown _ _ _ _ _ _ _ Hload' XX (addr_of_annotations_are_ptrs _ _ _ _ _ AA HB)).
    intros Hundef. generalize (Hundef reg1 (in_eq _ _)). intros Hundef1.
    assert (Hundef2: forall r, In r regs' -> trs'' # r = Vtrue \/ trs'' # r = Vfalse \/ trs'' # r = Vundef) by (intros; eapply Hundef; eapply in_cons; eauto).
    assert (Hundef': (trs'' # reg1 = Vtrue \/ trs'' # reg1 = Vfalse) \/ trs'' # reg1 = Vundef) by tauto.
    clear Hundef1. destruct (Classical_Prop.classic (exists r : positive, (trs'' # reg0 <- (trs'' # reg1)) # r = Vundef /\ In r regs')).
    { destruct Hundef' as [Hundef1 | Hundef1].
      { assert (Hundef2': forall r : reg, In r regs' -> (trs'' # reg0 <- (trs'' # reg1)) # r = Vtrue \/ (trs'' # reg0 <- (trs'' # reg1)) # r = Vfalse \/ (trs'' # reg0 <- (trs'' # reg1)) # r = Vundef).
        { intros; rewrite PMap.gso; eauto.
          unfold not; intros. subst r. eapply H18; eapply in_cons; eauto. }
        assert (Hundef1': (trs'' # reg0 <- (trs'' # reg1)) # reg0 = Vtrue \/ (trs'' # reg0 <- (trs'' # reg1)) # reg0 = Vfalse) by (rewrite ! PMap.gss; auto).
        exploit tr_or_regs_undef'; eauto.
        { unfold not; intros. eapply H18; eapply in_cons; eauto. }
        instantiate (1 := tm). instantiate (1 := tsp0). instantiate (1 := ts).
        intros [trs''' [Hstar'' [Hundef' HO]]].
        destruct init_state_exists' as [s0 Hinit].
        generalize (STEP' s0 Hinit). intros [t Hstep].
        assert (program_behaves (semantics tprog) (Goes_wrong t)).
        - econstructor; eauto.
          econstructor. eapply star_trans; eauto.
          eapply star_step. eapply exec_Inop; eauto.
          eapply star_step. eapply exec_Iop; eauto.
          destruct addr; simpl; eauto. simpl in Heval.
          destruct (Int.eq_dec i Int.zero); simpl; eauto.
          rewrite e in Heval. destruct (trs ## args); inv Heval.
          destruct l; inv H20. unfold Mem.loadv in Hload'. destruct v0; simpl in Hload'; inv Hload'.
          simpl. rewrite Int.add_zero; eauto.
          eapply star_trans. eapply Hstar.
          eapply star_trans. eapply Hstar'.
          eapply star_step. eapply exec_Iop; simpl; eauto. simpl. eauto.
          eapply star_trans; eauto. eapply star_refl. eauto. eauto. eauto. eauto. eauto. repeat rewrite E0_right; eauto.
          red; unfold not; intros. inv H14; try congruence.
          rewrite H28 in H9; inv H9. simpl in H29. rewrite Hundef' in H29.
          simpl in H29. inv H29.
          unfold not; intros. inv H14.
        - eapply DEFSAFE in H14; inv H14. }
      assert (Hundef1': (trs'' # reg0 <- (trs'' # reg1)) # reg0 = Vundef) by (rewrite PMap.gss; eauto).
      exploit tr_or_regs_undef; eauto.
      { unfold not; intros. eapply H18; eapply in_cons; eauto. }
      instantiate (1 := tm). instantiate (1 := tsp0). instantiate (1 := ts).
      intros [trs''' [Hstar'' [Hundef' HO]]].
      destruct init_state_exists' as [s0 Hinit].
      generalize (STEP' s0 Hinit). intros [t Hstep].
      assert (program_behaves (semantics tprog) (Goes_wrong t)).
      - econstructor; eauto.
        econstructor. eapply star_trans; eauto.
        eapply star_step. eapply exec_Inop; eauto.
        eapply star_step. eapply exec_Iop; eauto.
        destruct addr; simpl; eauto. simpl in Heval.
        destruct (Int.eq_dec i Int.zero); simpl; eauto.
        rewrite e in Heval. destruct (trs ## args); inv Heval.
        destruct l; inv H20. unfold Mem.loadv in Hload'. destruct v0; simpl in Hload'; inv Hload'.
        simpl. rewrite Int.add_zero; eauto.
        eapply star_trans. eapply Hstar.
        eapply star_trans. eapply Hstar'.
        eapply star_step. eapply exec_Iop; simpl; eauto. simpl. eauto.
        eapply star_trans. eapply Hstar''. eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto. repeat rewrite E0_right; eauto.
        red; unfold not; intros. inv H14; try congruence.
        rewrite H28 in H9; inv H9. simpl in H29. rewrite Hundef' in H29.
        simpl in H29. inv H29.
        unfold not; intros. inv H14.
      - eapply DEFSAFE in H14; inv H14. }
    { generalize (Classical_Pred_Type.not_ex_all_not _ _ H6). intros Hall. clear H6.
      assert (Hall': forall r, In r regs' -> (trs'' # reg0 <- (trs'' # reg1)) # r = Vtrue \/ (trs'' # reg0 <- (trs'' # reg1)) # r = Vfalse).
      { intros. rewrite ! PMap.gso; eauto.
        - generalize (Hundef r (in_cons _ _ _ H6)). intros [XA | [XA | XA]]; eauto.
          generalize (Hall r). unfold not; intros. exfalso; eapply H14.
          split; eauto. rewrite PMap.gso; eauto.
          unfold not; intros; eapply H18; eapply in_cons; eauto. subst r; eauto.
        - unfold not; intros; eapply H18; eapply in_cons; eauto. subst r; eauto. }
      destruct Hundef' as [Hundef' | Hundef'].
      { destruct Hundef' as [Hundef' | Hundef'].
        { assert (HB': forall sp : val, In sp (Vptr sp0 Int.zero :: map (fun s0 : stackframe => match s0 with | Stackframe _ _ sp1 _ _ => sp1 end) s) -> exists b : block, sp = Vptr b Int.zero).
          { intros. destruct H. inv H6; eauto.
            eapply match_stackframes_sps_are_ptrs'; eauto. }
          generalize (addr_of_annotations_are_ptrs _ _ _ _ _ H3 HB'). intros Hvals.
          split; intros.
          - assert (HLL: forall r, In r (reg1 :: regs') -> trs'' # r = Vtrue \/ trs'' # r = Vfalse).
            { intros. inv H14; eauto. generalize (Hall' r H20). intros LL.
              rewrite ! PMap.gso in LL; auto. unfold not; intros. subst r. eapply H18; eapply in_cons; eauto. }
            generalize (eval_condition_are_bools _ _ _ _ _ XX (addr_of_annotations_are_ptrs _ _ _ _ _ AA HB) HLL).
            intros. destruct a; simpl in H2; inv H2.
            destruct ta; simpl in Hload'; inv Hload'.
            eapply eval_condition_translated'; eauto.
            eapply addr_of_annotations_are_ptrs; eauto.
          - destruct a; simpl in H2; inv H2.
            destruct ta; simpl in Hload'; inv Hload'.
            inv XX. rewrite H21 in Hundef'.
            simpl in H21. exploit eval_condition_is_true_implies; eauto. intros Hintvals. subst b1.
            inv BB. inv H24.
            + exploit FLATINJ; eauto. intros; subst delta.
              rewrite Int.add_zero in Hinj. inv Hinj.
              exploit FLATINJ; eauto. intros; subst delta.
              generalize (FLATINJ' _ _ _ H26 H24). intros; subst b1.
              rewrite Int.add_zero. destruct (snd alpha); auto. eapply in_eq.
            + generalize (Hvals Vundef (in_eq _ _)). intros [bb [bo Hlo]]. inv Hlo. }
        { assert (HB': forall sp : val, In sp (Vptr sp0 Int.zero :: map (fun s0 : stackframe => match s0 with | Stackframe _ _ sp1 _ _ => sp1 end) s) -> exists b : block, sp = Vptr b Int.zero).
          { intros. destruct H. inv H6; eauto.
            eapply match_stackframes_sps_are_ptrs'; eauto. }
          generalize (addr_of_annotations_are_ptrs _ _ _ _ _ H3 HB'). intros Hvals.
          split; intros.
          - assert (HLL: forall r, In r (reg1 :: regs') -> trs'' # r = Vtrue \/ trs'' # r = Vfalse).
            { intros. inv H14; eauto. generalize (Hall' r H20). intros LL.
              rewrite ! PMap.gso in LL; auto. unfold not; intros. subst r. eapply H18; eapply in_cons; eauto. }
            generalize (eval_condition_are_bools _ _ _ _ _ XX (addr_of_annotations_are_ptrs _ _ _ _ _ AA HB) HLL).
            intros. destruct a; simpl in H2; inv H2.
            destruct ta; simpl in Hload'; inv Hload'.
            eapply eval_condition_translated'; eauto.
            eapply addr_of_annotations_are_ptrs; eauto.
          - assert (HLL: forall r, In r (reg1 :: regs') -> trs'' # r = Vtrue \/ trs'' # r = Vfalse).
            { intros. inv H6; eauto. generalize (Hall' r H14). intros LL.
              rewrite ! PMap.gso in LL; auto. unfold not; intros. subst r. eapply H18; eapply in_cons; eauto. }
            generalize (eval_condition_are_bools _ _ _ _ _ XX (addr_of_annotations_are_ptrs _ _ _ _ _ AA HB) HLL).
            intros. destruct (Classical_Prop.classic (exists r, In r regs' /\ trs'' # r = Vtrue)).
            + assert (exists v, In v tvals /\ Val.of_optbool (eval_condition (Ccompu Ceq) (ta :: v :: nil) tm) = Vtrue).
              { destruct H14 as [r [Hinregs Heq]].
                generalize (list_forall2_in_1 _ _ _ _ _ _ XX (in_cons _ _ _ Hinregs)).
                intros [y [LA LB]]. exists y; split; try congruence. }
              destruct H20 as [ta' [Hintval Hevalcond]].
              exploit eval_condition_is_true_implies; eauto. intros; subst ta'.
              destruct a; simpl in H2; inv H2.
              destruct ta; simpl in Hload'; inv Hload'.
              generalize (list_forall2_in_2 _ _ _ _ _ _ BB Hintval). intros [a' [Hinval Hvinj]].
              inv Hvinj.
              * exploit FLATINJ; eauto. intros; subst delta. rewrite Int.add_zero in Hinj.
                inv Hinj. exploit FLATINJ; eauto. intros; subst delta. rewrite Int.add_zero in Hinval.
                generalize (FLATINJ' _ _ _ H24 H25). intros; subst b1.
                destruct (snd alpha); eauto.
              * generalize (addr_of_annotations_are_ptrs _ _ _ _ _ H3 HB' _ Hinval). intros [bbb [oooo aaaaa]]. inv aaaaa.
            + assert (Hall'': forall r, In r regs' -> (trs'' # reg0 <- (trs'' # reg1)) # r = Vfalse).
              { generalize (Classical_Pred_Type.not_ex_all_not _ _ H14). intro lolo.
                intros. generalize (Hall' _ H20). intros [lo | lo].
                - exfalso. eapply lolo. split; eauto.
                  rewrite <- lo. rewrite PMap.gso; eauto.
                  red; intros. eapply H18. eapply in_cons; try congruence.
                - eauto. }
              clear Hall'. assert (exists t, program_behaves (semantics tprog) (Goes_wrong t)).
              { destruct init_state_exists' as [s0 Hinit].
                exploit STEP'; eauto. intros [t Hstep].
                exploit tr_or_regs_false; eauto.
                - eapply not_in_cons in H18. destruct H18; eauto.
                - rewrite PMap.gss. eauto.
                - intros [trs''' [Hstar'' [Hfalse Htrs]]].
                  inv H11. eexists; econstructor.
                  + eauto.
                  + econstructor. eapply star_trans; eauto.
                    eapply star_step. eapply exec_Inop; eauto.
                    eapply star_step. eapply exec_Iop; eauto.
                    simpl. destruct addr; eauto. destruct (Int.eq_dec i Int.zero); simpl; eauto.
                    destruct (trs ## args); eauto. destruct l; eauto. simpl in Heval. subst i.
                    destruct ta; simpl in Hload'; inv Hload'.
                    simpl in v0. destruct v0; simpl in Heval; inv Heval; eauto. rewrite Int.add_zero; eauto.
                    eapply star_trans. eapply Hstar. eapply star_trans. eapply Hstar'.
                    eapply star_step. eapply exec_Iop; eauto. simpl. eauto.
                    eapply star_trans. eapply Hstar''.
                    eapply star_step. eapply exec_Icond; eauto. simpl. rewrite Hfalse. simpl.
                    rewrite Int.eq_true. simpl. eauto. simpl.
                    eapply star_step. eapply exec_Iop; eauto. simpl. eauto.
                    eapply star_step. eapply exec_Iop; eauto. simpl. eauto.
                    eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
                    red; unfold not; intros. inv H11; try congruence.
                    rewrite H32 in H22; inv H22.
                    simpl in H33. rewrite PMap.gss in H33. rewrite PMap.gso in H33; eauto.
                    rewrite PMap.gss in H33. simpl in H33. rewrite Int.eq_true in H33; simpl in H33. inv H33.
                    unfold not; intros. inv H11. }
              destruct H20 as [tr H20]. eapply DEFSAFE in H20; inv H20. } }
      { assert (Hundef'': trs'' # reg0 <- (trs'' # reg1) # reg0 = Vundef) by (rewrite PMap.gss; eauto).
        exploit tr_or_regs_undef; eauto. eapply not_in_cons in H18; destruct H18; eauto.
        intros [trs''' [Hstar'' [Hundef''' Htrs]]].
        assert (exists t, program_behaves (semantics tprog) (Goes_wrong t)).
        { destruct init_state_exists' as [s0 Hinit].
          exploit STEP'; eauto. intros [t Hstep].
          eexists. econstructor.
          - eauto.
          - econstructor. eapply star_trans; eauto.
            eapply star_step. eapply exec_Inop; eauto.
            eapply star_step. eapply exec_Iop; eauto.
            simpl. destruct addr; eauto. destruct (Int.eq_dec i Int.zero); simpl; eauto.
            destruct (trs ## args); eauto. destruct l; eauto. simpl in Heval. subst i.
            destruct ta; simpl in Hload'; inv Hload'.
            simpl in v0. destruct v0; simpl in Heval; inv Heval; eauto. rewrite Int.add_zero; eauto.
            eapply star_trans. eapply Hstar. eapply star_trans. eapply Hstar'.
            eapply star_step. eapply exec_Iop; eauto. simpl. eauto.
            eapply star_trans. eapply Hstar''.
            eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto.
            red; unfold not; intros. inv H6; try congruence.
            rewrite H27 in H9; inv H9. simpl in H28.
            rewrite Hundef''' in H28. simpl in H28. inv H28.
            unfold not; intros. inv H6. }
        destruct H6 as [tt H6]. eapply DEFSAFE in H6; inv H6. } }
  Qed.

  Lemma store_step:
    forall s ts f tf sp tsp pc rs trs m tm alpha kappa addr args src pc' a m' vals (Htriv: MoreRTL.is_trivial_annotation prog alpha kappa addr = false) (Hsingleton: is_singleton (snd alpha) = false),
      match_states (State s f sp pc rs m) (State ts tf tsp pc trs tm) ->
      (fn_code f)!pc = Some (Istore alpha kappa addr args src pc') ->
      eval_addressing ge sp addr (rs##args) = Some a ->
      Mem.storev kappa m a (rs#src) = Some m' ->
      addr_of_annotations kappa ge (sp::map (fun s => match s with | Stackframe _ _ sp _ _ => sp end) s) (snd alpha) vals ->
      ((forall b ofs, In (Vptr b ofs) vals -> (eval_condition (Ccompu Ceq) (a::(Vptr b ofs)::nil) m = Some true \/ eval_condition (Ccompu Ceq) (a::(Vptr b ofs)::nil) m = Some false)) /\ (match snd alpha with | nil => True | _ => In a vals end)).
Proof.
    intros. inv H. exploit transf_function_spec; eauto. intros [pcs HA]. inv HA.
    rewrite Htriv in H14. rewrite Hsingleton in H14. inv H14.
    assert (HB: forall sp : val, In sp (Vptr tsp0 Int.zero :: map (fun s0 : stackframe => match s0 with | Stackframe _ _ sp1 _ _ => sp1 end) ts) -> exists b : block, sp = Vptr b Int.zero).
    { intros. destruct H. inv H6; eauto.
      eapply match_stackframes_sps_are_ptrs; eauto. }
    exploit addr_of_annotations_translated; eauto.
    { instantiate (2 := j). instantiate (1 := (Vptr tsp0 Int.zero) :: (map (fun s => match s with | Stackframe _ _ sp _ _ => sp end) ts)). econstructor.
      - eexists; eexists; repeat split; eauto.
      - eapply match_stackframes_sps; eauto. }
    { intros. eapply GINJ.
      eapply Genv.genv_symb_range; eauto. }
    intros [tvals [AA BB]].
    exploit (eval_addressing_inj ge tge).
    { intros. eapply symbol_address_inject; eauto. intros; eapply GINJ_implies; eauto. }
    { instantiate (1 := Vptr tsp0 Int.zero). econstructor; eauto. rewrite Int.add_zero. eauto. }
    { instantiate (1 := trs##args). eapply regs_agree_inject_list; eauto.
      intros; eapply max_reg_function_use; eauto. simpl. right; auto. }
    { eauto. }
    intros [ta [Heval Hinj]]. assert (RES': regs_agree j (max_reg_function f) rs (trs # reg0 <- ta)).
    { intro. generalize (RES r). intros [[LA LB] | [LA LB]].
      - left; split; auto. rewrite PMap.gso; try xomega. eauto.
      - right; split; auto. rewrite UNDEF; try xomega. eauto. }
    exploit tr_regs_annot_correct; eauto.
    intros [trs' [Hstar [X [Y Z]]]]. exploit tr_cmp_regs_correct; eauto.
    { eapply tr_regs_annot_regs_plt; eauto. }
    { eapply tr_regs_annot_regs_norepet; eauto. } instantiate (1 := tm). instantiate (1 := (Vptr tsp0 Int.zero)).
    instantiate (1 := ts). intros [trs'' [Hstar' [XX YY]]].
    rewrite <- (Z reg0 ((proj2 (not_in_app _ _ _ _)) (conj H18 H19))) in XX.
    rewrite PMap.gss in XX. exploit Mem.storev_mapped_inject; eauto.
    { generalize (RES src). intros [[HU HV] | [HU HV]]; eauto. assert (Ple src (max_reg_function f)). eapply max_reg_function_use; eauto. simpl. left; auto. xomega. } intros [tm' [Hstore' Hinj']].
    generalize (regs_are_unknown' _ _ _ _ _ _ _ _ Hstore' XX (addr_of_annotations_are_ptrs _ _ _ _ _ AA HB)).
    intros Hundef. generalize (Hundef reg1 (in_eq _ _)). intros Hundef1.
    assert (Hundef2: forall r, In r regs' -> trs'' # r = Vtrue \/ trs'' # r = Vfalse \/ trs'' # r = Vundef) by (intros; eapply Hundef; eapply in_cons; eauto).
    assert (Hundef': (trs'' # reg1 = Vtrue \/ trs'' # reg1 = Vfalse) \/ trs'' # reg1 = Vundef) by tauto.
    clear Hundef1. destruct (Classical_Prop.classic (exists r : positive, (trs'' # reg0 <- (trs'' # reg1)) # r = Vundef /\ In r regs')).
    { destruct Hundef' as [Hundef1 | Hundef1].
      { assert (Hundef2': forall r : reg, In r regs' -> (trs'' # reg0 <- (trs'' # reg1)) # r = Vtrue \/ (trs'' # reg0 <- (trs'' # reg1)) # r = Vfalse \/ (trs'' # reg0 <- (trs'' # reg1)) # r = Vundef).
        { intros; rewrite PMap.gso; eauto.
          unfold not; intros. subst r. eapply H18; eapply in_cons; eauto. }
        assert (Hundef1': (trs'' # reg0 <- (trs'' # reg1)) # reg0 = Vtrue \/ (trs'' # reg0 <- (trs'' # reg1)) # reg0 = Vfalse) by (rewrite ! PMap.gss; auto).
        exploit tr_or_regs_undef'; eauto.
        { unfold not; intros. eapply H18; eapply in_cons; eauto. }
        instantiate (1 := tm). instantiate (1 := tsp0). instantiate (1 := ts).
        intros [trs''' [Hstar'' [Hundef' HO]]].
        destruct init_state_exists' as [s0 Hinit].
        generalize (STEP' s0 Hinit). intros [t Hstep].
        assert (program_behaves (semantics tprog) (Goes_wrong t)).
        - econstructor; eauto.
          econstructor. eapply star_trans; eauto.
          eapply star_step. eapply exec_Inop; eauto.
          eapply star_step. eapply exec_Iop; eauto.
          destruct addr; simpl; eauto. simpl in Heval.
          destruct (Int.eq_dec i Int.zero); simpl; eauto.
          rewrite e in Heval. destruct (trs ## args); inv Heval.
          destruct l; inv H20. unfold Mem.storev in Hstore'. destruct v; simpl in Hstore'; inv Hstore'.
          simpl. rewrite Int.add_zero; eauto.
          eapply star_trans. eapply Hstar.
          eapply star_trans. eapply Hstar'.
          eapply star_step. eapply exec_Iop; simpl; eauto. simpl. eauto.
          eapply star_trans; eauto. eapply star_refl. eauto. eauto. eauto. eauto. eauto. repeat rewrite E0_right; eauto.
          red; unfold not; intros. inv H14; try congruence.
          rewrite H28 in H9; inv H9. simpl in H29. rewrite Hundef' in H29.
          simpl in H29. inv H29.
          unfold not; intros. inv H14.
        - eapply DEFSAFE in H14; inv H14. }
      assert (Hundef1': (trs'' # reg0 <- (trs'' # reg1)) # reg0 = Vundef) by (rewrite PMap.gss; eauto).
      exploit tr_or_regs_undef; eauto.
      { unfold not; intros. eapply H18; eapply in_cons; eauto. }
      instantiate (1 := tm). instantiate (1 := tsp0). instantiate (1 := ts).
      intros [trs''' [Hstar'' [Hundef' HO]]].
      destruct init_state_exists' as [s0 Hinit].
      generalize (STEP' s0 Hinit). intros [t Hstep].
      assert (program_behaves (semantics tprog) (Goes_wrong t)).
      - econstructor; eauto.
        econstructor. eapply star_trans; eauto.
        eapply star_step. eapply exec_Inop; eauto.
        eapply star_step. eapply exec_Iop; eauto.
        destruct addr; simpl; eauto. simpl in Heval.
        destruct (Int.eq_dec i Int.zero); simpl; eauto.
        rewrite e in Heval. destruct (trs ## args); inv Heval.
        destruct l; inv H20. unfold Mem.storev in Hstore'. destruct v; simpl in Hstore'; inv Hstore'.
        simpl. rewrite Int.add_zero; eauto.
        eapply star_trans. eapply Hstar.
        eapply star_trans. eapply Hstar'.
        eapply star_step. eapply exec_Iop; simpl; eauto. simpl. eauto.
        eapply star_trans. eapply Hstar''. eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto. repeat rewrite E0_right; eauto.
        red; unfold not; intros. inv H14; try congruence.
        rewrite H28 in H9; inv H9. simpl in H29. rewrite Hundef' in H29.
        simpl in H29. inv H29.
        unfold not; intros. inv H14.
      - eapply DEFSAFE in H14; inv H14. }
    { generalize (Classical_Pred_Type.not_ex_all_not _ _ H6). intros Hall. clear H6.
      assert (Hall': forall r, In r regs' -> (trs'' # reg0 <- (trs'' # reg1)) # r = Vtrue \/ (trs'' # reg0 <- (trs'' # reg1)) # r = Vfalse).
      { intros. rewrite ! PMap.gso; eauto.
        - generalize (Hundef r (in_cons _ _ _ H6)). intros [XA | [XA | XA]]; eauto.
          generalize (Hall r). unfold not; intros. exfalso; eapply H14.
          split; eauto. rewrite PMap.gso; eauto.
          unfold not; intros; eapply H18; eapply in_cons; eauto. subst r; eauto.
        - unfold not; intros; eapply H18; eapply in_cons; eauto. subst r; eauto. }
      destruct Hundef' as [Hundef' | Hundef'].
      { destruct Hundef' as [Hundef' | Hundef'].
        { assert (HB': forall sp : val, In sp (Vptr sp0 Int.zero :: map (fun s0 : stackframe => match s0 with | Stackframe _ _ sp1 _ _ => sp1 end) s) -> exists b : block, sp = Vptr b Int.zero).
          { intros. destruct H. inv H6; eauto.
            eapply match_stackframes_sps_are_ptrs'; eauto. }
          generalize (addr_of_annotations_are_ptrs _ _ _ _ _ H3 HB'). intros Hvals.
          split; intros.
          - assert (HLL: forall r, In r (reg1 :: regs') -> trs'' # r = Vtrue \/ trs'' # r = Vfalse).
            { intros. inv H14; eauto. generalize (Hall' r H20). intros LL.
              rewrite ! PMap.gso in LL; auto. unfold not; intros. subst r. eapply H18; eapply in_cons; eauto. }
            generalize (eval_condition_are_bools _ _ _ _ _ XX (addr_of_annotations_are_ptrs _ _ _ _ _ AA HB) HLL).
            intros. destruct a; simpl in H2; inv H2.
            destruct ta; simpl in Hstore'; inv Hstore'.
            eapply eval_condition_translated'; eauto.
            eapply addr_of_annotations_are_ptrs; eauto.
          - destruct a; simpl in H2; inv H2.
            destruct ta; simpl in Hstore'; inv Hstore'.
            inv XX. rewrite H21 in Hundef'.
            simpl in H21. exploit eval_condition_is_true_implies; eauto. intros Hintvals. subst b1.
            inv BB. inv H24.
            + exploit FLATINJ; eauto. intros; subst delta.
              rewrite Int.add_zero in Hinj. inv Hinj.
              exploit FLATINJ; eauto. intros; subst delta.
              generalize (FLATINJ' _ _ _ H26 H24). intros; subst b1.
              rewrite Int.add_zero. destruct (snd alpha); auto. eapply in_eq.
            + generalize (Hvals Vundef (in_eq _ _)). intros [bb [bo Hlo]]. inv Hlo. }
        { assert (HB': forall sp : val, In sp (Vptr sp0 Int.zero :: map (fun s0 : stackframe => match s0 with | Stackframe _ _ sp1 _ _ => sp1 end) s) -> exists b : block, sp = Vptr b Int.zero).
          { intros. destruct H. inv H6; eauto.
            eapply match_stackframes_sps_are_ptrs'; eauto. }
          generalize (addr_of_annotations_are_ptrs _ _ _ _ _ H3 HB'). intros Hvals.
          split; intros.
          - assert (HLL: forall r, In r (reg1 :: regs') -> trs'' # r = Vtrue \/ trs'' # r = Vfalse).
            { intros. inv H14; eauto. generalize (Hall' r H20). intros LL.
              rewrite ! PMap.gso in LL; auto. unfold not; intros. subst r. eapply H18; eapply in_cons; eauto. }
            generalize (eval_condition_are_bools _ _ _ _ _ XX (addr_of_annotations_are_ptrs _ _ _ _ _ AA HB) HLL).
            intros. destruct a; simpl in H2; inv H2.
            destruct ta; simpl in Hstore'; inv Hstore'.
            eapply eval_condition_translated'; eauto.
            eapply addr_of_annotations_are_ptrs; eauto.
          - assert (HLL: forall r, In r (reg1 :: regs') -> trs'' # r = Vtrue \/ trs'' # r = Vfalse).
            { intros. inv H6; eauto. generalize (Hall' r H14). intros LL.
              rewrite ! PMap.gso in LL; auto. unfold not; intros. subst r. eapply H18; eapply in_cons; eauto. }
            generalize (eval_condition_are_bools _ _ _ _ _ XX (addr_of_annotations_are_ptrs _ _ _ _ _ AA HB) HLL).
            intros. destruct (Classical_Prop.classic (exists r, In r regs' /\ trs'' # r = Vtrue)).
            + assert (exists v, In v tvals /\ Val.of_optbool (eval_condition (Ccompu Ceq) (ta :: v :: nil) tm) = Vtrue).
              { destruct H14 as [r [Hinregs Heq]].
                generalize (list_forall2_in_1 _ _ _ _ _ _ XX (in_cons _ _ _ Hinregs)).
                intros [y [LA LB]]. exists y; split; try congruence. }
              destruct H20 as [ta' [Hintval Hevalcond]].
              exploit eval_condition_is_true_implies; eauto. intros; subst ta'.
              destruct a; simpl in H2; inv H2.
              destruct ta; simpl in Hstore'; inv Hstore'.
              generalize (list_forall2_in_2 _ _ _ _ _ _ BB Hintval). intros [a' [Hinval Hvinj]].
              inv Hvinj.
              * exploit FLATINJ; eauto. intros; subst delta. rewrite Int.add_zero in Hinj.
                inv Hinj. exploit FLATINJ; eauto. intros; subst delta. rewrite Int.add_zero in Hinval.
                generalize (FLATINJ' _ _ _ H24 H25). intros; subst b1.
                destruct (snd alpha); eauto.
              * generalize (addr_of_annotations_are_ptrs _ _ _ _ _ H3 HB' _ Hinval). intros [bbb [oooo aaaaa]]. inv aaaaa.
            + assert (Hall'': forall r, In r regs' -> (trs'' # reg0 <- (trs'' # reg1)) # r = Vfalse).
              { generalize (Classical_Pred_Type.not_ex_all_not _ _ H14). intro lolo.
                intros. generalize (Hall' _ H20). intros [lo | lo].
                - exfalso. eapply lolo. split; eauto.
                  rewrite <- lo. rewrite PMap.gso; eauto.
                  red; intros. eapply H18. eapply in_cons; try congruence.
                - eauto. }
              clear Hall'. assert (exists t, program_behaves (semantics tprog) (Goes_wrong t)).
              { destruct init_state_exists' as [s0 Hinit].
                exploit STEP'; eauto. intros [t Hstep].
                exploit tr_or_regs_false; eauto.
                - eapply not_in_cons in H18. destruct H18; eauto.
                - rewrite PMap.gss. eauto.
                - intros [trs''' [Hstar'' [Hfalse Htrs]]].
                  inv H11. eexists; econstructor.
                  + eauto.
                  + econstructor. eapply star_trans; eauto.
                    eapply star_step. eapply exec_Inop; eauto.
                    eapply star_step. eapply exec_Iop; eauto.
                    simpl. destruct addr; eauto. destruct (Int.eq_dec i Int.zero); simpl; eauto.
                    destruct (trs ## args); eauto. destruct l; eauto. simpl in Heval. subst i.
                    destruct ta; simpl in Hstore'; inv Hstore'.
                    simpl in v. destruct v; simpl in Heval; inv Heval; eauto. rewrite Int.add_zero; eauto.
                    eapply star_trans. eapply Hstar. eapply star_trans. eapply Hstar'.
                    eapply star_step. eapply exec_Iop; eauto. simpl. eauto.
                    eapply star_trans. eapply Hstar''.
                    eapply star_step. eapply exec_Icond; eauto. simpl. rewrite Hfalse. simpl.
                    rewrite Int.eq_true. simpl. eauto. simpl.
                    eapply star_step. eapply exec_Iop; eauto. simpl. eauto.
                    eapply star_step. eapply exec_Iop; eauto. simpl. eauto.
                    eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
                    red; unfold not; intros. inv H11; try congruence.
                    rewrite H32 in H22; inv H22.
                    simpl in H33. rewrite PMap.gss in H33. rewrite PMap.gso in H33; eauto.
                    rewrite PMap.gss in H33. simpl in H33. rewrite Int.eq_true in H33; simpl in H33. inv H33.
                    unfold not; intros. inv H11. }
              destruct H20 as [tr H20]. eapply DEFSAFE in H20; inv H20. } }
      { assert (Hundef'': trs'' # reg0 <- (trs'' # reg1) # reg0 = Vundef) by (rewrite PMap.gss; eauto).
        exploit tr_or_regs_undef; eauto. eapply not_in_cons in H18; destruct H18; eauto.
        intros [trs''' [Hstar'' [Hundef''' Htrs]]].
        assert (exists t, program_behaves (semantics tprog) (Goes_wrong t)).
        { destruct init_state_exists' as [s0 Hinit].
          exploit STEP'; eauto. intros [t Hstep].
          eexists. econstructor.
          - eauto.
          - econstructor. eapply star_trans; eauto.
            eapply star_step. eapply exec_Inop; eauto.
            eapply star_step. eapply exec_Iop; eauto.
            simpl. destruct addr; eauto. destruct (Int.eq_dec i Int.zero); simpl; eauto.
            destruct (trs ## args); eauto. destruct l; eauto. simpl in Heval. subst i.
            destruct ta; simpl in Hstore'; inv Hstore'.
            simpl in v. destruct v; simpl in Heval; inv Heval; eauto. rewrite Int.add_zero; eauto.
            eapply star_trans. eapply Hstar. eapply star_trans. eapply Hstar'.
            eapply star_step. eapply exec_Iop; eauto. simpl. eauto.
            eapply star_trans. eapply Hstar''.
            eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto.
            red; unfold not; intros. inv H6; try congruence.
            rewrite H27 in H9; inv H9. simpl in H28.
            rewrite Hundef''' in H28. simpl in H28. inv H28.
            unfold not; intros. inv H6. }
        destruct H6 as [tt H6]. eapply DEFSAFE in H6; inv H6. } }
  Qed.

  Lemma tr_local_regs_inv_singleton:
    forall f pc1 base bound depth regs regs' pc2 pcs stk tf tsp trs m,
      tr_local_regs' STK f (fn_code tf) pc1 depth base bound regs regs' pc2 pcs ->
      (depth < 128)%nat ->
      shadowstack_is_sound (tsp::map (fun s => match s with | Stackframe _ _ sp _ _ => sp end) stk) m ->
      (forall s0, initial_state tprog s0 -> exists t : trace, star step tge s0 t (State stk tf tsp pc1 trs m)) ->
      (forall bSTK, Genv.find_symbol tge STK = Some bSTK -> forall ofs : Z, Mem.perm m bSTK ofs Cur Readable <-> 0 <= ofs < 512) ->
      exists sp, pop depth (tsp::map (fun s => match s with | Stackframe _ _ sp _ _ => sp end) stk) = Some sp.
Proof.
    intros.
    inv H; try congruence.
    { destruct (Classical_Prop.classic (exists t' s', step tge (State stk tf tsp pc1 trs m) t' s')).
      * destruct H as [t' [s' Hs']].
        destruct (Classical_Prop.classic (exists t'' s'', step tge s' t'' s'')).
        { destruct H as [t'' [s'' Hs'']].
          inv Hs'; try congruence. rewrite H15 in H5; inv H5.
          inv Hs''; try congruence. rewrite H14 in H6; inv H6.
          simpl in H18; simpl in H16. unfold Genv.symbol_address in H16. unfold Genv.symbol_address in H18. fold SIZE in H16.
          destruct SIZE_exists as [bSIZE [HSIZE HSIZEvar]].
          destruct STK_exists as [bSTK [HSTK HSTKvar]].
          rewrite HSIZE in H16. rewrite HSTK in H18.
          inv H16. rewrite PMap.gss in H18.
          inv H1. destruct H as [SS1 SS2].
          unfold Genv.symbol_address in SS1; rewrite HSIZE in SS1.
          rewrite SS1 in H17; inv H17. simpl in H18. rewrite repr_add in H18. inv H18.
          simpl in H19. unfold Genv.symbol_address in SS2; rewrite HSTK in SS2.
          rewrite map_length in *. simpl in SS2. rewrite map_length in SS2.
          exploit Mem.load_valid_access; eauto. intro Hperm.
          red in Hperm. destruct Hperm as [Hperm1 Hperm2].
          red in Hperm1. exploit (Hperm1 (Int.unsigned (Int.repr (-4 * Z.of_nat depth + 4 * (Z.pos (Pos.of_succ_nat (length stk)) - 1))))); simpl; try omega.
          intro Hperm. eapply H3 in Hperm; eauto.
          assert (Hdepthbound: (depth < S (length stk))%nat).
          { rewrite Int.unsigned_repr_eq in Hperm.
            replace Int.modulus with 4294967296 in Hperm; try reflexivity.
            destruct (le_dec depth (length stk)); try omega.
            eapply not_le in n.
            assert (512 < (-4 * Z.of_nat depth + 4 * (Z.pos (Pos.of_succ_nat (length stk)) - 1)) mod 4294967296).
            { assert ((-4 * Z.of_nat depth + 4 * (Z.pos (Pos.of_succ_nat (length stk)) - 1)) < 0) by Psatz.lia.
              assert (-512 < (-4 * Z.of_nat depth + 4 * (Z.pos (Pos.of_succ_nat (length stk)) - 1))) by Psatz.lia.
              rewrite mod_neg. Psatz.lia. Psatz.lia. Psatz.lia. }
            omega. }
          rewrite <- repr_add in H19.
          generalize (proj2 (SS2 _ _) (conj Hdepthbound H19)). intros Hpop.
          eauto. }
        { destruct init_state_exists' as [s0 Hinit].
          generalize (H2 s0 Hinit). intros [t Hstep].
          assert (program_behaves (semantics tprog) (Goes_wrong (t ** E0 ** t' ** E0))).
          - econstructor; eauto.
            econstructor. eapply star_trans; eauto.
            eapply star_step; eauto. eapply star_refl.
            eauto. red; unfold not; intros. eapply H; eauto.
            unfold not; intros. inv Hs'; try congruence; inv H4.
          - eapply DEFSAFE in H4; inv H4. }
      * destruct init_state_exists' as [s0 Hinit].
        generalize (H2 s0 Hinit). intros [t Hstep].
        assert (program_behaves (semantics tprog) (Goes_wrong (t ** E0))).
        { econstructor; eauto.
          econstructor. eapply star_trans; eauto. eapply star_refl.
          red; unfold not; intros. eapply H; eauto.
          unfold not; intros; inv H4. }
        eapply DEFSAFE in H4; inv H4. }
    { destruct (Classical_Prop.classic (exists t' s', step tge (State stk tf tsp pc1 trs m) t' s')).
      * destruct H as [t' [s' Hs']].
        destruct (Classical_Prop.classic (exists t'' s'', step tge s' t'' s'')).
        { destruct H as [t'' [s'' Hs'']].
          inv Hs'; try congruence. rewrite H19 in H5; inv H5.
          inv Hs''; try congruence. rewrite H18 in H6; inv H6.
          simpl in H22; simpl in H20. unfold Genv.symbol_address in H20. unfold Genv.symbol_address in H22. fold SIZE in H20.
          destruct SIZE_exists as [bSIZE [HSIZE HSIZEvar]].
          destruct STK_exists as [bSTK [HSTK HSTKvar]].
          rewrite HSIZE in H20. rewrite HSTK in H22.
          inv H20. rewrite PMap.gss in H22.
          inv H1. destruct H as [SS1 SS2].
          unfold Genv.symbol_address in SS1; rewrite HSIZE in SS1.
          rewrite SS1 in H21; inv H21. simpl in H22. rewrite repr_add in H22. inv H22.
          simpl in H23. unfold Genv.symbol_address in SS2; rewrite HSTK in SS2.
          rewrite map_length in *. simpl in SS2. rewrite map_length in SS2.
          exploit Mem.load_valid_access; eauto. intro Hperm.
          red in Hperm. destruct Hperm as [Hperm1 Hperm2].
          red in Hperm1. exploit (Hperm1 (Int.unsigned (Int.repr (-4 * Z.of_nat depth + 4 * (Z.pos (Pos.of_succ_nat (length stk)) - 1))))); simpl; try omega.
          intro Hperm. eapply H3 in Hperm; eauto.
          assert (Hdepthbound: (depth < S (length stk))%nat).
          { rewrite Int.unsigned_repr_eq in Hperm.
            replace Int.modulus with 4294967296 in Hperm; try reflexivity.
            destruct (le_dec depth (length stk)); try omega.
            eapply not_le in n.
            assert (512 < (-4 * Z.of_nat depth + 4 * (Z.pos (Pos.of_succ_nat (length stk)) - 1)) mod 4294967296).
            { assert ((-4 * Z.of_nat depth + 4 * (Z.pos (Pos.of_succ_nat (length stk)) - 1)) < 0) by Psatz.lia.
              assert (-512 < (-4 * Z.of_nat depth + 4 * (Z.pos (Pos.of_succ_nat (length stk)) - 1))) by Psatz.lia.
              rewrite mod_neg. Psatz.lia. Psatz.lia. Psatz.lia. }
            omega. }
          rewrite <- repr_add in H23.
          generalize (proj2 (SS2 _ _) (conj Hdepthbound H23)). intros Hpop.
          eauto. }
        { destruct init_state_exists' as [s0 Hinit].
          generalize (H2 s0 Hinit). intros [t Hstep].
          assert (program_behaves (semantics tprog) (Goes_wrong (t ** E0 ** t' ** E0))).
          - econstructor; eauto.
            econstructor. eapply star_trans; eauto.
            eapply star_step; eauto. eapply star_refl.
            eauto. red; unfold not; intros. eapply H; eauto.
            unfold not; intros. inv Hs'; try congruence; inv H11.
          - eapply DEFSAFE in H11; inv H11. }
      * destruct init_state_exists' as [s0 Hinit].
        generalize (H2 s0 Hinit). intros [t Hstep].
        assert (program_behaves (semantics tprog) (Goes_wrong (t ** E0))).
        { econstructor; eauto.
          econstructor. eapply star_trans; eauto. eapply star_refl.
          red; unfold not; intros. eapply H; eauto.
          unfold not; intros; inv H11. }
        eapply DEFSAFE in H11; inv H11. }
  Qed.

  Lemma tr_local_regs_star_singleton:
    forall sp stk f tf base bound depth pc1 regs regs' pc2 pcs trs m,
      (forall s0, initial_state tprog s0 -> exists t : trace, star step tge s0 t (State stk tf sp pc1 trs m)) ->
      tr_local_regs' STK f (fn_code tf) pc1 depth base bound regs regs' pc2 pcs ->
      exists trs', star step tge (State stk tf sp pc1 trs m) E0 (State stk tf sp pc2 trs' m).
Proof.
    intros. generalize init_state_exists'; intros [s0 Hinit]. inv H0.
    - destruct (Classical_Prop.classic (exists t' s', step tge (State stk tf sp pc1 trs m) t' s')).
      + destruct H0 as [t' [s' Hs']].
        destruct (Classical_Prop.classic (exists t1 s1, step tge s' t1 s1)).
        * destruct H0 as [t1 [s1 Hs1]].
          destruct (Classical_Prop.classic (exists t2 s2, step tge s1 t2 s2)).
          { destruct H0 as [t2 [s2 Hs2]].
            inv Hs'; try congruence. rewrite H12 in H2; inv H2.
            inv Hs1; try congruence. rewrite H11 in H3; inv H3.
            inv Hs2; try congruence. rewrite H10 in H4; inv H4.
            eexists.
            eapply star_step. eapply exec_Iload; eauto.
            eapply star_step. eapply exec_Iload; eauto.
            eapply star_step. eapply exec_Iop; eauto.
            eapply star_refl. eauto. eauto. eauto. }
          { generalize (H s0 Hinit). intros [t Hstar].
            assert (program_behaves (semantics tprog) (Goes_wrong (t ** t' ** t1 ** E0))).
            - econstructor; eauto.
              econstructor. eapply star_trans. eapply Hstar.
              eapply star_step. eapply Hs'. eapply star_step. eapply Hs1.
              eapply star_refl. eauto. eauto. reflexivity.
              intro. unfold not; intros. eapply H0; eauto.
              unfold not; intros. inv Hs'; try congruence.
              inv Hs1; try congruence. inv H1.
            - eapply DEFSAFE in H1. inv H1. }
        * generalize (H s0 Hinit). intros [t Hstar].
          assert (program_behaves (semantics tprog) (Goes_wrong (t ** t' ** E0))).
          { econstructor; eauto.
            econstructor. eapply star_trans; eauto.
            eapply star_step. eapply Hs'. eapply star_refl. eauto.
            intro. unfold not; intros. eapply H0; eauto.
            unfold not; intros. inv Hs'; try congruence.
            inv H1. }
          { eapply DEFSAFE in H1; inv H1. }
      + generalize (H s0 Hinit). intros [t Hstar].
        assert (program_behaves (semantics tprog) (Goes_wrong (t ** E0))).
        * econstructor; eauto.
          econstructor. eapply star_trans; eauto.
          eapply star_refl. eauto.
          intro. unfold not; intros. eapply H0; eauto.
          unfold not; intros. inv H1.
        * eapply DEFSAFE in H1; inv H1.
    - destruct (Classical_Prop.classic (exists t' s', step tge (State stk tf sp pc1 trs m) t' s')).
      + destruct H0 as [t' [s' Hs']].
        destruct (Classical_Prop.classic (exists t1 s1, step tge s' t1 s1)).
        * destruct H0 as [t1 [s1 Hs1]].
          destruct (Classical_Prop.classic (exists t2 s2, step tge s1 t2 s2)).
          { destruct H0 as [t2 [s2 Hs2]].
            destruct (Classical_Prop.classic (exists t3 s3, step tge s2 t3 s3)).
            - destruct H0 as [t3 [s3 Hs3]].
              destruct (Classical_Prop.classic (exists t4 s4, step tge s3 t4 s4)).
              + destruct H0 as [t4 [s4 Hs4]].
                destruct (Classical_Prop.classic (exists t5 s5, step tge s4 t5 s5)).
                * destruct H0 as [t5 [s5 Hs5]].
                  inv Hs'; try congruence. rewrite H16 in H2; inv H2.
                  inv Hs1; try congruence. rewrite H15 in H3; inv H3.
                  inv Hs2; try congruence. rewrite H14 in H4; inv H4.
                  inv Hs3; try congruence. rewrite H13 in H5; inv H5.
                  inv Hs4; try congruence. rewrite H12 in H6; inv H6.
                  inv Hs5; try congruence. rewrite H11 in H7; inv H7.
                  eexists. eapply star_step. eapply exec_Iload; try (exact H17); eauto.
                  eapply star_step. eapply exec_Iload; try (exact H19); eauto.
                  eapply star_step. eapply exec_Iop; eauto.
                  eapply star_step. eapply exec_Iload; eauto.
                  eapply star_step. eapply exec_Iload; eauto.
                  eapply star_step. eapply exec_Iop; eauto.
                  eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto.
                * generalize (H s0 Hinit). intros [t Hstar].
                  assert (program_behaves (semantics tprog) (Goes_wrong (t ** t' ** t1 ** t2 ** t3 ** t4 ** E0))).
                  { econstructor; eauto.
                    econstructor. eapply star_trans; eauto.
                    eapply star_step. eapply Hs'.
                    eapply star_step. eapply Hs1.
                    eapply star_step. eapply Hs2.
                    eapply star_step. eapply Hs3.
                    eapply star_step. eapply Hs4.
                    eapply star_refl. eauto. eauto. eauto. eauto. eauto.
                    intro. unfold not; intros. eapply H0; eauto.
                    unfold not; intros.
                    inv Hs'; try congruence. rewrite H18 in H2; inv H2.
                    inv Hs1; try congruence. rewrite H17 in H3; inv H3.
                    inv Hs2; try congruence. rewrite H16 in H4; inv H4.
                    inv Hs3; try congruence. rewrite H15 in H5; inv H5.
                    inv Hs4; try congruence. rewrite H14 in H6; inv H6.
                    inv H8. }
                  { eapply DEFSAFE in H8; inv H8. }
              + generalize (H s0 Hinit). intros [t Hstar].
                assert (program_behaves (semantics tprog) (Goes_wrong (t ** t' ** t1 ** t2 ** t3 ** E0))).
                * econstructor; eauto.
                  econstructor. eapply star_trans; eauto.
                  eapply star_step. eapply Hs'.
                  eapply star_step. eapply Hs1.
                  eapply star_step. eapply Hs2.
                  eapply star_step. eapply Hs3.
                  eapply star_refl. eauto. eauto. eauto. eauto. eauto.
                  intro. unfold not; intros. eapply H0; eauto.
                  unfold not; intros.
                  inv Hs'; try congruence. rewrite H18 in H2; inv H2.
                  inv Hs1; try congruence. rewrite H17 in H3; inv H3.
                  inv Hs2; try congruence. rewrite H16 in H4; inv H4.
                  inv Hs3; try congruence. rewrite H15 in H5; inv H5.
                  inv H8.
                * eapply DEFSAFE in H8; inv H8.
            - generalize (H s0 Hinit). intros [t Hstar].
              assert (program_behaves (semantics tprog) (Goes_wrong (t ** t' ** t1 ** t2 ** E0))).
              + econstructor; eauto.
                econstructor. eapply star_trans; eauto.
                eapply star_step. eapply Hs'.
                eapply star_step. eapply Hs1.
                eapply star_step. eapply Hs2.
                eapply star_refl. eauto. eauto. eauto. eauto. eauto.
                intro. unfold not; intros. eapply H0; eauto.
                unfold not; intros.
                inv Hs'; try congruence. rewrite H18 in H2; inv H2.
                inv Hs1; try congruence. rewrite H17 in H3; inv H3.
                inv Hs2; try congruence. rewrite H16 in H4; inv H4.
                inv H8.
              + eapply DEFSAFE in H8; inv H8. }
          { generalize (H s0 Hinit). intros [t Hstar].
            assert (program_behaves (semantics tprog) (Goes_wrong (t ** t' ** t1 ** E0))).
            - econstructor; eauto.
              econstructor. eapply star_trans; eauto.
              eapply star_step. eapply Hs'.
              eapply star_step. eapply Hs1.
              eapply star_refl. eauto. eauto. eauto. eauto. eauto.
              intro. unfold not; intros. eapply H0; eauto.
              unfold not; intros.
              inv Hs'; try congruence. rewrite H18 in H2; inv H2.
              inv Hs1; try congruence. rewrite H17 in H3; inv H3.
              inv H8.
            - eapply DEFSAFE in H8; inv H8. }
        * generalize (H s0 Hinit). intros [t Hstar].
          assert (program_behaves (semantics tprog) (Goes_wrong (t ** t' ** E0))).
          { econstructor; eauto.
            econstructor. eapply star_trans; eauto.
            eapply star_step. eapply Hs'.
            eapply star_refl. eauto. eauto. eauto. eauto. eauto.
            intro. unfold not; intros. eapply H0; eauto.
            unfold not; intros.
            inv Hs'; try congruence. rewrite H18 in H2; inv H2.
            inv H8. }
          { eapply DEFSAFE in H8; inv H8. }
      + generalize (H s0 Hinit). intros [t Hstar].
        assert (program_behaves (semantics tprog) (Goes_wrong (t ** E0))).
        * econstructor; eauto.
          econstructor. eapply star_trans; eauto.
          eapply star_refl. eauto. eauto. eauto. eauto. eauto.
          intro. unfold not; intros. eapply H0; eauto.
          unfold not; intros.
          inv H8.
        * eapply DEFSAFE in H8; inv H8.
  Qed.

  Lemma tr_global_regs_star_singleton:
    forall sp stk f tf id base bound pc1 regs pc2 pcs trs m,
      (forall s0, initial_state tprog s0 -> exists t : trace, star step tge s0 t (State stk tf sp pc1 trs m)) ->
      tr_global_regs' f (fn_code tf) pc1 id base bound regs pc2 pcs ->
      exists trs', star step tge (State stk tf sp pc1 trs m) E0 (State stk tf sp pc2 trs' m).
Proof.
    intros. generalize init_state_exists'; intros [s0 Hinit].
    generalize (H s0 Hinit). intros [t Hstar]. inv H0.
    - destruct (Classical_Prop.classic (exists t' s', step tge (State stk tf sp pc1 trs m) t' s')).
      + destruct H0 as [t' [s' Hs']]. inv Hs'; try congruence. rewrite H10 in H2; inv H2.
        eexists. eapply star_trans; eauto.
        eapply star_step. eapply exec_Iop; eauto.
        eapply star_refl. eauto. eapply star_refl. eauto.
      + assert (program_behaves (semantics tprog) (Goes_wrong t)).
        * econstructor; eauto.
          econstructor. eapply Hstar.
          intro; unfold not; intros. eapply H0; eauto.
          unfold not; intros. inv H1.
        * eapply DEFSAFE in H1; inv H1.
    - destruct (Classical_Prop.classic (exists t' s', step tge (State stk tf sp pc1 trs m) t' s')).
      + destruct H0 as [t' [s' Hs']].
        destruct (Classical_Prop.classic (exists t'' s'', step tge s' t'' s'')).
        * destruct H0 as [t'' [s'' Hs'']].
          inv Hs'; try congruence. rewrite H12 in H2; inv H2.
          inv Hs''; try congruence. rewrite H11 in H3; inv H3.
          eexists. eapply star_trans; eauto.
          eapply star_step. eapply exec_Iop; eauto.
          eapply star_step. eapply exec_Iop; eauto.
          eapply star_refl. eauto. eauto. eapply star_refl. eauto.
        * assert (program_behaves (semantics tprog) (Goes_wrong (t ** t'))).
          { econstructor; eauto.
            econstructor. eapply star_trans; eauto.
            eapply star_step; eauto. eapply star_refl. rewrite E0_right. auto.
            intro; unfold not; intros. eapply H0; eauto.
            inv Hs'; try congruence. rewrite H13 in H2; inv H2.
            unfold not; intros. inv H2. }
          { eapply DEFSAFE in H4; inv H4. }
      + assert (program_behaves (semantics tprog) (Goes_wrong t)).
        * econstructor; eauto.
          econstructor. eapply Hstar.
          intro; unfold not; intros. eapply H0; eauto.
          unfold not; intros. inv H4.
        * eapply DEFSAFE in H4; inv H4.
  Qed.

  Lemma tr_regs_annot_inv_singleton:
    forall kappa sp stk f tf alpha pc1 regs regs' pc2 pcs trs m
      (Hex: check_annotations_divides kappa alpha = OK tt),
      (forall ptr, In ptr (sp::map (fun s => match s with | Stackframe _ _ sp _ _ => sp end) stk) ->
              exists b, ptr = Vptr b Int.zero) ->
      tr_regs_annot' prog STK f (fn_code tf) pc1 alpha regs regs' pc2 pcs ->
      shadowstack_is_sound (sp::map (fun s => match s with | Stackframe _ _ sp _ _ => sp end) stk) m ->
      (forall depth varname range, In (ABlocal depth varname range) alpha -> (depth < 128)%nat) ->
      (forall id range, In (ABglobal id range) alpha -> id <> STK /\ id <> SIZE) ->
      (forall s0, initial_state tprog s0 -> exists t : trace, star step tge s0 t (State stk tf sp pc1 trs m)) ->
      (forall bSTK, Genv.find_symbol tge STK = Some bSTK -> forall ofs : Z, Mem.perm m bSTK ofs Cur Readable <-> 0 <= ofs < 512) ->
      exists vals, addr_of_annotations_singleton tge (sp::map (fun s => match s with | Stackframe _ _ sp _ _ => sp end) stk) alpha vals.
Proof.
    induction alpha; intros.
    - exists nil; econstructor.
    - destruct a.
      + inv H0.
        exploit tr_local_regs_inv_singleton; eauto. eapply H2; eapply in_eq. intros [sp' Hsp].
        exploit tr_local_regs_star_singleton; eauto. intros [trs' Hstar].
        exploit IHalpha; eauto. simpl in Hex; monadInv Hex. destruct x; auto.
        intros. eapply H2; right; eauto. intros; eapply H3; right; eauto.
        intros. eapply H4 in H0. destruct H0. eexists. eapply star_trans; eauto. intros [vals Hvals].
        eexists. econstructor; eauto.
      + inv H0. generalize (symbols_preserved' _ _ H9). intros.
        exploit tr_global_regs_star_singleton; eauto. intros [trs' Hstar].
        exploit IHalpha; eauto. simpl in Hex; monadInv Hex. destruct x; auto.
        intros. eapply H2; right; eauto. intros; eapply H3; right; eauto.
        intros. eapply H4 in H6. destruct H6. eexists. eapply star_trans; eauto. intros [vals Hvals].
        eexists. econstructor; eauto.
  Qed.

  Inductive match_vals j: (val + val * val) -> (val + val * val) -> Prop :=
  | match_vals_intro1:
      forall v tv,
        Val.inject j v tv ->
        match_vals j (inl v) (inl tv)
  | match_vals_intro2:
      forall v1 v2 tv1 tv2,
        Val.inject j v1 tv1 ->
        Val.inject j v2 tv2 ->
        match_vals j (inr (v1, v2)) (inr (tv1, tv2)).

  Lemma addr_of_annotations_translated_singleton:
    forall j sps tsps alpha tvals,
      list_forall2 (fun sp tsp => exists bsp btsp, sp = Vptr bsp Int.zero /\ tsp = Vptr btsp Int.zero /\ j bsp = Some (btsp, 0)) sps tsps ->
      (forall b id, Genv.find_symbol ge id = Some b -> j b = Some (b, 0)) ->
      (forall id range, In (ABglobal id range) alpha -> id <> STK /\ id <> SIZE) ->
      addr_of_annotations_singleton tge tsps alpha tvals ->
      exists vals, addr_of_annotations_singleton ge sps alpha vals /\ list_forall2 (match_vals j) vals tvals.
Proof.
    induction alpha; intros.
    - inv H2. exists nil; split; econstructor; eauto.
    - inv H2.
      + generalize (pop_inject' _ _ _ H _ _ H5). intros [sp' [A B]].
        destruct B as [bsp [tbsp [B [C D]]]]. subst sp'; subst sp.
        exploit IHalpha; eauto.
        { intros; eapply H1; eapply in_cons; eauto. }
        intros [vals2 [I J]].
        eexists; split.
        * econstructor; eauto.
        * econstructor; eauto.
          destruct (Int.eq_dec base bound); econstructor; eauto.
          simpl. rewrite Int.add_zero_l. econstructor; eauto. rewrite Int.add_zero. reflexivity.
          simpl. rewrite Int.add_zero_l. econstructor; eauto. rewrite Int.add_zero. reflexivity.
          simpl. rewrite Int.add_zero_l. econstructor; eauto. rewrite Int.add_zero. reflexivity.
      + generalize (H1 _ _ (in_eq _ _)). intros [A B].
        rewrite symbols_preserved in H5; eauto.
        * generalize (H0 _ _ H5). intros C.
          exploit IHalpha; eauto.
          { intros; eapply H1; eapply in_cons; eauto. }
          intros [vals2 [HC HD]].
          eexists; split.
          { econstructor; eauto. }
          { econstructor; eauto.
            destruct (Int.eq_dec base bound); econstructor; eauto.
            econstructor; eauto. rewrite Int.add_zero. reflexivity.
            econstructor; eauto. rewrite Int.add_zero. reflexivity.
            econstructor; eauto. rewrite Int.add_zero. reflexivity. }
        * unfold not; intros. destruct H2 as [H2 | [H2 | H2]]; try (inv H2; fail).
          { eapply (proj1 (H1 _ _ (in_eq _ _))). eauto. }
          { eapply (proj2 (H1 _ _ (in_eq _ _))). eauto. }
  Qed.

  Lemma addr_of_annotations_singleton_determ:
    forall ge sps alpha vals1,
      addr_of_annotations_singleton ge sps alpha vals1 ->
      forall vals2, addr_of_annotations_singleton ge sps alpha vals2 ->
      vals1 = vals2.
Proof.
    induction 1; intros.
    - inv H1; eauto.
      f_equal; eauto. rewrite H in H8; inv H8; auto.
    - inv H1; eauto. rewrite H in H7; inv H7; f_equal; auto.
    - inv H; reflexivity.
  Qed.

  Lemma int_ranges_spec:
    forall n base x,
      Int.unsigned base + Z.of_nat n < Int.modulus ->
      In x (int_ranges n base) ->
      exists y, x = Int.unsigned y /\ Int.unsigned base <= x < Int.unsigned base + Z.of_nat n.
Proof.
    induction n; intros.
    - simpl in H0; inv H0.
    - simpl in H0. destruct H0.
      + eexists; split; eauto. rewrite <- H0. Psatz.lia.
      + eapply IHn in H0.
        * destruct H0 as [y [HA HB]].
          exists y; split; eauto. rewrite Int.unsigned_add_carry in HB.
          unfold Int.add_carry in HB. rewrite Int.unsigned_one in HB; rewrite Int.unsigned_zero in HB. simpl in H.
          destruct (zlt (Int.unsigned base + 1 + 0) Int.modulus); try Psatz.lia.
          rewrite Int.unsigned_zero in HB. simpl; Psatz.lia.
        * rewrite Int.unsigned_add_carry.
          unfold Int.add_carry. rewrite Int.unsigned_one; rewrite Int.unsigned_zero. simpl in H.
          destruct (zlt (Int.unsigned base + 1 + 0) Int.modulus); try Psatz.lia.
          rewrite Int.unsigned_zero. Psatz.lia.
  Qed.

  Lemma check_annotations_divides_spec_2:
    forall kappa alpha x,
      check_annotations_divides kappa alpha = OK x ->
      (forall id base bound, In (ABglobal id (base, bound)) alpha ->
                        forall size, Int.unsigned (Int.sub bound base) + 1 = Z.pos size ->
                                exists x, In x (int_ranges (Pos.to_nat size) base) /\ ((align_chunk kappa) | x)).
Proof.
    induction alpha; intros.
    - inv H0.
    - destruct H0 as [H0 | H0].
      + subst a. simpl in H. monadInv H.
        rewrite H1 in EQ0. eapply check_annotations_divides_spec'; eauto.
      + simpl in H. destruct a; try monadInv H; eauto.
        destruct range; monadInv H.
        eapply IHalpha; eauto.
        destruct range; monadInv H. eapply IHalpha; eauto.
  Qed.

  Lemma addr_of_annotations_singleton_implies:
    forall kappa ge sps alpha vals' (Hdivides: check_annotations_divides kappa alpha = OK tt),
      (forall sp, In sp sps -> exists b, sp = Vptr b Int.zero) ->
      check_annotations_range alpha = OK tt ->
      addr_of_annotations_singleton ge sps alpha vals' ->
      exists vals,
        addr_of_annotations kappa ge sps alpha vals /\
        (forall b ofs,
            In (Vptr b ofs) vals ->
            In (inl (Vptr b ofs)) vals' \/
            (exists ofs1 ofs2,
                In (inr (Vptr b ofs1, Vptr b ofs2)) vals' /\ Int.unsigned ofs1 <= Int.unsigned ofs <= Int.unsigned ofs2)) /\
        (forall v,
            In v vals' ->
            match v with
            | inl (Vptr b ofs) => In (Vptr b ofs) vals
            | inr (Vptr b ofs1, Vptr b' ofs2) => b = b' /\ exists ofs, In (Vptr b ofs) vals /\ Int.unsigned ofs1 <= Int.unsigned ofs <= Int.unsigned ofs2
            | _ => False
            end).
Proof.
    intros. induction H1.
    - exploit IHaddr_of_annotations_singleton; eauto.
      { simpl in Hdivides. monadInv Hdivides. destruct x; auto. }
      { simpl in H0. destruct (zle (Int.unsigned base) (Int.unsigned bound)); destruct (zlt (Int.unsigned bound) (Int.modulus - 1)); try monadInv H0; auto. }
      intros [vals2 [Hvals2 [HA HA']]].
      exploit check_annotations_range_spec; eauto. left; auto. intros Hrange.
      assert (exists size, Int.unsigned (Int.sub bound base) + 1 = Z.pos size).
      { rewrite Int.unsigned_sub_borrow. unfold Int.sub_borrow. rewrite Int.unsigned_zero.
        destruct (zlt (Int.unsigned bound - Int.unsigned base - 0) 0); try Psatz.lia.
        rewrite Int.unsigned_zero. replace (Int.unsigned bound - Int.unsigned base + 0 * Int.modulus + 1) with (Int.unsigned bound - Int.unsigned base + 1) by Psatz.lia.
        assert (Int.unsigned bound - Int.unsigned base + 1 >= 1) by Psatz.lia.
        case_eq (Int.unsigned bound - Int.unsigned base + 1); intros. exfalso. Psatz.lia.
        eauto. exfalso. Psatz.lia. }
      destruct H3 as [size Hsize].
      generalize (addr_of_local_exists (Pos.to_nat size) kappa base sp). intros [vals1 Hvals1].
      exploit addr_of_annotations_implies_singleton; eauto.
      econstructor; eauto. intros [vals' [HB HC]].
      inv HB. rewrite H1 in H9; inv H9. replace vals0 with vals in * by (eapply addr_of_annotations_singleton_determ; eauto).
      econstructor; split; eauto. econstructor; eauto. split; eauto.
      intros. destruct H3.
      + destruct (Int.eq_dec base bound).
        * subst v. generalize (pop_is_in _ _ _ H1). intros JA. eapply H in JA. destruct JA as [bsp JA]. subst sp0.
          simpl. rewrite Int.add_zero_l. eapply in_or_app. left.
          generalize (check_annotations_divides_spec _ _ _ Hdivides _ _ _ _ (in_eq _ _) _ Hsize). intros [x [LA LB]].
          eapply addr_of_local_in; eauto. rewrite positive_nat_Z. rewrite <- Hsize.
          eapply int_add_sub; eauto.
          exists base. split. simpl; rewrite Int.add_zero_l; auto. split. rewrite positive_nat_Z. Psatz.lia.
          subst base. rewrite Int.sub_idem in Hsize. rewrite Int.unsigned_zero in Hsize.
          assert (size = xH) by Psatz.lia. subst size. simpl in LA. destruct LA; auto. subst x; exact LB. inv H3.
        * subst v. generalize (pop_is_in _ _ _ H1). intros JA. eapply H in JA. destruct JA as [bsp JA]. subst sp0.
          simpl. rewrite Int.add_zero_l. split; auto. rewrite Int.add_zero_l.
          generalize (check_annotations_divides_spec _ _ _ Hdivides _ _ _ _ (in_eq _ _) _ Hsize). intros [x [LA LB]].
          assert (HHH: Int.unsigned base + Z.of_nat (Pos.to_nat size) < Int.modulus).
          { rewrite positive_nat_Z. rewrite <- Hsize. eapply int_add_sub; auto. }
          generalize (int_ranges_spec _ _ _ HHH LA). intros [x' [YA YB]]. generalize YB; intros YB'.
          subst x. exists x'. rewrite positive_nat_Z in YB. rewrite <- Hsize in YB.
          rewrite Int.unsigned_sub_borrow in YB. unfold Int.sub_borrow in YB.
          rewrite Int.unsigned_zero in YB. destruct (zlt (Int.unsigned bound - Int.unsigned base - 0) 0); try Psatz.lia.
          rewrite Int.unsigned_zero in YB. split; try Psatz.lia.
          eapply in_or_app. left. eapply addr_of_local_in; eauto.
          exists x'. repeat split; try Psatz.lia; auto.
          simpl. rewrite Int.add_zero_l; auto.
      + generalize (HA' _ H3). intros GA. destruct v; try (inv GA; fail).
        * destruct v; try (inv GA; fail).
          eapply in_or_app. right; auto.
        * destruct p. destruct v; try (inv GA; fail).
          destruct v0; try (inv GA; fail).
          destruct GA as [GA1 [ofs [GA2 GA3]]].
          split; eauto. exists ofs; split; eauto. eapply in_or_app; right; auto.
    - exploit IHaddr_of_annotations_singleton; eauto.
      { simpl in Hdivides. monadInv Hdivides. destruct x; auto. }
      { simpl in H0. destruct (zle (Int.unsigned base) (Int.unsigned bound)); destruct (zlt (Int.unsigned bound) (Int.modulus - 1)); try monadInv H0; auto. }
      intros [vals2 [Hvals2 [HA HA']]].
      exploit check_annotations_range_spec'; eauto. left; auto. intros Hrange.
      assert (exists size, Int.unsigned (Int.sub bound base) + 1 = Z.pos size).
      { rewrite Int.unsigned_sub_borrow. unfold Int.sub_borrow. rewrite Int.unsigned_zero.
        destruct (zlt (Int.unsigned bound - Int.unsigned base - 0) 0); try Psatz.lia.
        rewrite Int.unsigned_zero. replace (Int.unsigned bound - Int.unsigned base + 0 * Int.modulus + 1) with (Int.unsigned bound - Int.unsigned base + 1) by Psatz.lia.
        assert (Int.unsigned bound - Int.unsigned base + 1 >= 1) by Psatz.lia.
        case_eq (Int.unsigned bound - Int.unsigned base + 1); intros. exfalso. Psatz.lia.
        eauto. exfalso. Psatz.lia. }
      destruct H3 as [size Hsize].
      generalize (addr_of_global_exists id kappa (Pos.to_nat size) base). intros [vals1 Hvals1].
      exploit addr_of_annotations_implies_singleton; eauto.
      econstructor; eauto. intros [vals' [HB HC]].
      inv HB. rewrite H1 in H8; inv H8. replace vals0 with vals in * by (eapply addr_of_annotations_singleton_determ; eauto).
      econstructor; split; eauto. econstructor; eauto. split; auto.
      intros. destruct H3.
      + destruct (Int.eq_dec base bound).
        * subst v. eapply in_or_app. left.
          generalize (check_annotations_divides_spec_2 _ _ _ Hdivides _ _ _ (in_eq _ _) _ Hsize). intros [x [LA LB]].
          eapply addr_of_global_in; eauto. rewrite positive_nat_Z. rewrite <- Hsize.
          eapply int_add_sub; eauto.
          exists base. split. eauto. split. rewrite positive_nat_Z. Psatz.lia.
          subst base. rewrite Int.sub_idem in Hsize. rewrite Int.unsigned_zero in Hsize.
          assert (size = xH) by Psatz.lia. subst size. simpl in LA. destruct LA; auto. subst x; exact LB. inv H3.
        * subst v. split; auto.
          generalize (check_annotations_divides_spec_2 _ _ _ Hdivides _ _ _ (in_eq _ _) _ Hsize). intros [x [LA LB]].
          assert (HHH: Int.unsigned base + Z.of_nat (Pos.to_nat size) < Int.modulus).
          { rewrite positive_nat_Z. rewrite <- Hsize. eapply int_add_sub; auto. }
          generalize (int_ranges_spec _ _ _ HHH LA). intros [x' [YA YB]]. generalize YB; intros YB'.
          subst x. exists x'. rewrite positive_nat_Z in YB. rewrite <- Hsize in YB.
          rewrite Int.unsigned_sub_borrow in YB. unfold Int.sub_borrow in YB.
          rewrite Int.unsigned_zero in YB. destruct (zlt (Int.unsigned bound - Int.unsigned base - 0) 0); try Psatz.lia.
          rewrite Int.unsigned_zero in YB. split; try Psatz.lia.
          eapply in_or_app. left. eapply addr_of_global_in; eauto.
      + generalize (HA' _ H3). intros GA. destruct v; try (inv GA; fail).
        * destruct v; try (inv GA; fail).
          eapply in_or_app. right; auto.
        * destruct p. destruct v; try (inv GA; fail).
          destruct v0; try (inv GA; fail).
          destruct GA as [GA1 [ofs [GA2 GA3]]].
          split; eauto. exists ofs; split; eauto. eapply in_or_app; right; auto.
    - exists nil. split; eauto. econstructor. split; eauto. intros. inv H1.
  Qed.

  Lemma valand_true:
    forall x y,
      Val.and (Val.of_optbool x) (Val.of_optbool y) = Vtrue ->
      Val.of_optbool x = Vtrue /\ Val.of_optbool y = Vtrue.
Proof.
    intros. simpl; destruct x; destruct y; simpl; simpl in H; auto.
    - destruct b; destruct b0; simpl in H; try (inv H); auto.
    - destruct b; simpl in H; inv H.
    - inv H.
  Qed.

  Lemma valand_false:
    forall x y,
      Val.and (Val.of_optbool x) (Val.of_optbool y) = Vfalse ->
      Val.of_optbool x = Vfalse \/ Val.of_optbool y = Vfalse.
Proof.
    intros. simpl; destruct x; destruct y; simpl; simpl in H; auto.
    - destruct b; destruct b0; simpl in H; try (inv H); auto.
    - destruct b; simpl in H; inv H.
  Qed.

  Lemma optbool_true:
    forall x,
      Val.of_optbool x = Vtrue <-> x = Some true.
Proof.
    intros. destruct x; simpl.
    - destruct b; split; intros; inv H; auto.
    - split; intros; inv H; auto.
  Qed.

  Lemma optbool_false:
    forall x,
      Val.of_optbool x = Vfalse <-> x = Some false.
Proof.
    intros. destruct x; simpl.
    - destruct b; split; intros; inv H; auto.
    - split; intros; inv H; auto.
  Qed.

  Axiom valid_ptr_connected:
    forall m b ofs1 ofs2,
      Mem.valid_pointer m b ofs1 = true ->
      Mem.valid_pointer m b ofs2 = true ->
      forall ofs, ofs1 <= ofs <= ofs2 ->
             Mem.valid_pointer m b ofs = true.

  Lemma weak_valid_ptr_connected:
    forall m b ofs1 ofs2,
      Mem.weak_valid_pointer m b ofs1 = true ->
      Mem.weak_valid_pointer m b ofs2 = true ->
      forall ofs, ofs1 <= ofs <= ofs2 ->
             Mem.weak_valid_pointer m b ofs = true.
Proof.
    intros. eapply orb_true_iff in H. eapply orb_true_iff in H0.
    destruct H as [H | H]; destruct H0 as [H0 | H0].
    - eapply orb_true_iff. left. eapply (valid_ptr_connected m b ofs1 ofs2); eauto.
    - eapply orb_true_iff. destruct (Z_eq_dec ofs1 ofs).
      + subst ofs; left; auto.
      + destruct (Z_eq_dec ofs ofs2).
        * subst ofs; right; auto.
        * assert (ofs1 <= ofs <= ofs2 - 1) by Psatz.lia.
          left; eapply (valid_ptr_connected m b ofs1); eauto.
    - eapply orb_true_iff. left. eapply (valid_ptr_connected m b (ofs1 - 1)); eauto.
      Psatz.lia.
    - eapply orb_true_iff. right. eapply (valid_ptr_connected m b (ofs1 - 1)); eauto.
      Psatz.lia.
  Qed.

  Lemma singleton_true_false_implies:
    forall vals vals' a m,
      (forall b ofs,
          In (Vptr b ofs) vals ->
          In (inl (Vptr b ofs)) vals' \/
          (exists ofs1 ofs2,
              In (inr (Vptr b ofs1, Vptr b ofs2)) vals' /\ Int.unsigned ofs1 <= Int.unsigned ofs <= Int.unsigned ofs2)) ->
      (forall v, In v vals' ->
            match v with
            | inl v => Val.of_optbool (eval_condition (Ccompu Ceq) (v::a::nil) m) = Vtrue \/ Val.of_optbool (eval_condition (Ccompu Ceq) (v::a::nil) m) = Vfalse
            | inr (v, v') => Val.and (Val.of_optbool (Val.cmpu_bool (Mem.valid_pointer m) Cle v a)) (Val.of_optbool (Val.cmpu_bool (Mem.valid_pointer m) Cle a v')) = Vtrue \/ Val.and (Val.of_optbool (Val.cmpu_bool (Mem.valid_pointer m) Cle v a)) (Val.of_optbool (Val.cmpu_bool (Mem.valid_pointer m) Cle a v')) = Vfalse
            end) ->
      (forall b ofs,
          In (Vptr b ofs) vals ->
          eval_condition (Ccompu Ceq) (a :: Vptr b ofs :: nil) m = Some true \/
          eval_condition (Ccompu Ceq) (a :: Vptr b ofs :: nil) m = Some false).
Proof.
    induction vals; intros.
    - inv H1.
    - destruct H1.
      + subst a. generalize (H _ _ (in_eq _ _)). intros [HA | HA].
        * generalize (H0 _ HA). intros HB.
          simpl in HB. destruct a0; simpl in HB; try (destruct HB as [HB | HB]; inv HB; fail).
          { simpl. destruct (Int.eq i Int.zero && (Mem.valid_pointer m b (Int.unsigned ofs) || Mem.valid_pointer m b (Int.unsigned ofs - 1))).
            - simpl in HB. destruct HB as [HB | HB]; inv HB. auto.
            - simpl in HB. destruct HB as [HB | HB]; inv HB. }
          { simpl. destruct (eq_block b b0).
            - subst b0. destruct (eq_block b b); try congruence.
              rewrite andb_comm. destruct ((Mem.valid_pointer m b (Int.unsigned ofs) || Mem.valid_pointer m b (Int.unsigned ofs - 1)) && (Mem.valid_pointer m b (Int.unsigned i) || Mem.valid_pointer m b (Int.unsigned i - 1))).
              + destruct (Int.eq i ofs); destruct (Int.eq ofs i); simpl in HB; try congruence; auto.
              + simpl in HB; destruct HB as [HB | HB]; inv HB.
            - destruct (eq_block b0 b); try congruence.
              rewrite andb_comm. destruct (Mem.valid_pointer m b (Int.unsigned ofs) && Mem.valid_pointer m b0 (Int.unsigned i)).
              + simpl in HB; auto.
              + simpl in HB; destruct HB as [HB | HB]; inv HB. }
        * destruct HA as [ofs1 [ofs2 [HA HB]]].
          generalize (H0 _ HA). intros HC. destruct HC as [HC | HC].
          { generalize (valand_true _ _ HC). intros [HD HE].
            eapply optbool_true in HD. eapply optbool_true in HE.
            simpl in HD. simpl. unfold Val.cmpu_bool; simpl.
            destruct a0; try (inv HD; fail).
            - destruct (Int.eq i Int.zero && (Mem.valid_pointer m b (Int.unsigned ofs1) || Mem.valid_pointer m b (Int.unsigned ofs1 - 1))); inv HD.
            - rewrite andb_comm. destruct (eq_block b b0).
              + subst b0; destruct (eq_block b b); try congruence.
                case_eq ((Mem.valid_pointer m b (Int.unsigned ofs1) || Mem.valid_pointer m b (Int.unsigned ofs1 - 1)) && (Mem.valid_pointer m b (Int.unsigned i) || Mem.valid_pointer m b (Int.unsigned i - 1))); intros; rewrite H1 in HD; try (inv HD; fail).
                eapply andb_true_iff in H1. destruct H1 as [HF HG]. rewrite HG. rewrite andb_true_r.
                simpl in HE. destruct (eq_block b b); try congruence. rewrite HG in HE. simpl in HE.
                case_eq (Mem.valid_pointer m b (Int.unsigned ofs2) || Mem.valid_pointer m b (Int.unsigned ofs2 - 1)); intros; rewrite H1 in HE; try (inv HE; fail).
                eapply orb_true_iff in HF. eapply orb_true_iff in H1.
                destruct HF as [HF | HF]; destruct H1 as [HH | HH].
                * generalize (valid_ptr_connected m b _ _ HF HH _ HB). intros HI. rewrite HI; simpl.
                  destruct (Int.eq i ofs); auto.
                * destruct (Z_eq_dec (Int.unsigned ofs) (Int.unsigned ofs1)).
                  { rewrite <- e1 in *. rewrite HF; destruct (Int.eq i ofs); auto. }
                  { destruct (Z_eq_dec (Int.unsigned ofs) (Int.unsigned ofs2)).
                    - rewrite <- e1 in *. rewrite HH. rewrite orb_true_r. destruct (Int.eq i ofs); auto.
                    - assert (Int.unsigned ofs1 <= Int.unsigned ofs - 1 <= Int.unsigned ofs2 - 1) by Psatz.lia.
                      generalize (valid_ptr_connected m b _ _ HF HH _ H1). intros HI; rewrite HI; simpl.
                      rewrite orb_true_r; simpl; destruct (Int.eq i ofs); auto. }
                * assert (Int.unsigned ofs1 - 1 <= Int.unsigned ofs <= Int.unsigned ofs2) by Psatz.lia.
                  generalize (valid_ptr_connected m b _ _ HF HH _ H1); intros HI; rewrite HI; simpl.
                  destruct (Int.eq i ofs); auto.
                * assert (Int.unsigned ofs1 - 1 <= Int.unsigned ofs - 1 <= Int.unsigned ofs2 - 1) by Psatz.lia.
                  generalize (valid_ptr_connected m b _ _ HF HH _ H1); intros HI; rewrite HI; simpl.
                  rewrite orb_true_r; simpl; destruct (Int.eq i ofs); auto.
              + destruct (Mem.valid_pointer m b (Int.unsigned ofs1) && Mem.valid_pointer m b0 (Int.unsigned i)); inv HD. }
          { case_eq (Val.cmpu_bool (Mem.valid_pointer m) Cle (Vptr b ofs1) a0); intros.
            - rewrite H1 in HC. case_eq (Val.cmpu_bool (Mem.valid_pointer m) Cle a0 (Vptr b ofs2)); intros.
              + rewrite H2 in HC.
                eapply valand_false in HC. destruct HC as [HC | HC].
                * simpl in HC. destruct b0; inv HC.
                  destruct a0; simpl in H1; try (inv H1; fail).
                  { destruct (Int.eq i Int.zero && (Mem.valid_pointer m b (Int.unsigned ofs1) || Mem.valid_pointer m b (Int.unsigned ofs1 - 1))); inv H1. }
                  destruct (eq_block b b0).
                  { subst b0. case_eq ((Mem.valid_pointer m b (Int.unsigned ofs1) || Mem.valid_pointer m b (Int.unsigned ofs1 - 1)) && (Mem.valid_pointer m b (Int.unsigned i) || Mem.valid_pointer m b (Int.unsigned i - 1))); intros; rewrite H3 in H1; try (inv H1; fail).
                    eapply andb_true_iff in H3. destruct H3 as [GA GB].
                    simpl in H2. destruct (eq_block b b); try congruence.
                    case_eq ((Mem.valid_pointer m b (Int.unsigned i) || Mem.valid_pointer m b (Int.unsigned i - 1)) && (Mem.valid_pointer m b (Int.unsigned ofs2) || Mem.valid_pointer m b (Int.unsigned ofs2 - 1))); intros; rewrite H3 in H2; try (inv H2; fail).
                    eapply andb_true_iff in H3. destruct H3 as [GC GD].
                    simpl. destruct (eq_block b b); try congruence.
                    rewrite GB. simpl. inv H1. eapply negb_false_iff in H4. unfold Int.ltu in H4.
                    destruct (zlt (Int.unsigned i) (Int.unsigned ofs1)); inv H4.
                    right. generalize (weak_valid_ptr_connected _ _ _ _ GA GD _ HB). intros GE.
                    unfold Mem.weak_valid_pointer in GE. rewrite GE.
                    unfold Int.eq; unfold Int.ltu. destruct (zeq (Int.unsigned i) (Int.unsigned ofs)); try Psatz.lia.
                    destruct (zlt (Int.unsigned i) (Int.unsigned ofs1)); try Psatz.lia; auto. }
                  { destruct (Mem.valid_pointer m b (Int.unsigned ofs1) && Mem.valid_pointer m b0 (Int.unsigned i)); inv H1. }
                * simpl in HC. destruct b1; inv HC.
                  destruct a0; simpl in H1; try (inv H1; fail).
                  { destruct (Int.eq i Int.zero && (Mem.valid_pointer m b (Int.unsigned ofs1) || Mem.valid_pointer m b (Int.unsigned ofs1 - 1))); inv H1. }
                  destruct (eq_block b b1).
                  { subst b1. case_eq ((Mem.valid_pointer m b (Int.unsigned ofs1) || Mem.valid_pointer m b (Int.unsigned ofs1 - 1)) && (Mem.valid_pointer m b (Int.unsigned i) || Mem.valid_pointer m b (Int.unsigned i - 1))); intros; rewrite H3 in H1; try (inv H1; fail).
                    eapply andb_true_iff in H3. destruct H3 as [GA GB].
                    simpl in H2. destruct (eq_block b b); try congruence.
                    case_eq ((Mem.valid_pointer m b (Int.unsigned i) || Mem.valid_pointer m b (Int.unsigned i - 1)) && (Mem.valid_pointer m b (Int.unsigned ofs2) || Mem.valid_pointer m b (Int.unsigned ofs2 - 1))); intros; rewrite H3 in H2; try (inv H2; fail).
                    eapply andb_true_iff in H3. destruct H3 as [GC GD].
                    simpl. destruct (eq_block b b); try congruence.
                    rewrite GB. simpl. inv H2. eapply negb_false_iff in H4. unfold Int.ltu in H4.
                    destruct (zlt (Int.unsigned ofs2) (Int.unsigned i)); inv H4.
                    right. generalize (weak_valid_ptr_connected _ _ _ _ GA GD _ HB). intros GE.
                    unfold Mem.weak_valid_pointer in GE. rewrite GE.
                    unfold Int.eq; unfold Int.ltu. destruct (zeq (Int.unsigned i) (Int.unsigned ofs)); try Psatz.lia.
                    destruct (zlt (Int.unsigned ofs2) (Int.unsigned i)); try Psatz.lia; auto. }
                  { destruct (Mem.valid_pointer m b (Int.unsigned ofs1) && Mem.valid_pointer m b1 (Int.unsigned i)); inv H1. }
              + rewrite H2 in HC; simpl in HC. destruct b0; simpl in HC; inv HC.
            - rewrite H1 in HC; simpl in HC. inv HC. }
      + eapply IHvals; eauto.
        intros. eapply H; right; eauto.
  Qed.

  Lemma addr_of_annotations_singleton_in_implies:
    forall (ge : Genv.t fundef unit) (sps : list val) (alpha : list ablock) vals,
       addr_of_annotations_singleton ge sps alpha vals ->
       (forall sp : val, In sp sps -> exists b : block, sp = Vptr b Int.zero) ->
       forall v, In v vals -> match v with
                        | inl v =>
                          exists (b : block) (ofs : int),
                          v = Vptr b ofs /\
                          ((exists depth varname, nth_error sps depth = Some (Vptr b Int.zero) /\ In (ABlocal depth varname (ofs, ofs)) alpha) \/
                           (exists id, Genv.find_symbol ge id = Some b /\ In (ABglobal id (ofs, ofs)) alpha))
                        | inr (v, v') =>
                          exists (b : block) ofs1 ofs2,
                          v = Vptr b ofs1 /\ v' = Vptr b ofs2 /\
                          ((exists depth varname, nth_error sps depth = Some (Vptr b Int.zero) /\ In (ABlocal depth varname (ofs1, ofs2)) alpha) \/
                           (exists id, Genv.find_symbol ge id = Some b /\ In (ABglobal id (ofs1, ofs2)) alpha))
                        end.
Proof.
    induction 1; intros.
    - generalize H; intros G.
      eapply pop_is_in in H. eapply H1 in H.
      destruct H as [bsp H]. subst sp. simpl in H2. destruct H2.
      + subst v. destruct (Int.eq_dec base bound); simpl; eauto.
        * eexists. eexists. split; eauto.
          left. eexists. eexists. split; eauto.
          { rewrite <- pop_is_nth; eauto. }
          { left; rewrite Int.add_zero_l; subst base; eauto. }
        * eexists. eexists. eexists. split; eauto.
          rewrite Int.add_zero_l. split; eauto.
          left. eexists. eexists. split; eauto.
          { rewrite <- pop_is_nth; eauto. }
          { left; rewrite Int.add_zero_l; eauto. }
      + exploit IHaddr_of_annotations_singleton; eauto. intros K.
        destruct v.
        * destruct K as [b [ofs [K1 K2]]].
          eexists. eexists. split; eauto. destruct K2 as [[d [vn [K2 K2']]] | [id [K2 K2']]].
          { left; eexists; eexists; split; eauto. right; eauto. }
          { right; eexists; split; eauto. right; eauto. }
        * destruct p. destruct K as [b [ofs1 [ofs2 [K1 [K2 K3]]]]].
          eexists. eexists. eexists. repeat split; eauto.
          destruct K3 as [[d [vn [K3 K3']]] | [id [K3 K3']]].
          { left; eexists; eexists; split; eauto. right; eauto. }
          { right; eexists; split; eauto. right; eauto. }
    - destruct H2.
      + subst v. destruct (Int.eq_dec base bound); simpl; eauto.
        * eexists. eexists. split; eauto.
          right. eexists. split; eauto.
          left; subst base; eauto.
        * eexists. eexists. eexists. split; eauto.
          split; eauto.
      + exploit IHaddr_of_annotations_singleton; eauto. intros K.
        destruct v.
        * destruct K as [b' [ofs [K1 K2]]].
          eexists. eexists. split; eauto. destruct K2 as [[d [vn [K2 K2']]] | [id' [K2 K2']]].
          { left; eexists; eexists; split; eauto. right; eauto. }
          { right; eexists; split; eauto. right; eauto. }
        * destruct p. destruct K as [b' [ofs1 [ofs2 [K1 [K2 K3]]]]].
          eexists. eexists. eexists. repeat split; eauto.
          destruct K3 as [[d [vn [K3 K3']]] | [id' [K3 K3']]].
          { left; eexists; eexists; split; eauto. right; eauto. }
          { right; eexists; split; eauto. right; eauto. }
    - inv H0.
  Qed.

  Lemma cmpu_bool_cle_true_implies:
    forall m b b' ofs ofs',
      Val.cmpu_bool (Mem.valid_pointer m) Cle (Vptr b ofs) (Vptr b' ofs') = Some true ->
      b = b' /\ Int.unsigned ofs <= Int.unsigned ofs'.
Proof.
    intros. simpl in H. destruct (eq_block b b'); try (inv H; fail).
    - destruct ((Mem.valid_pointer m b (Int.unsigned ofs) || Mem.valid_pointer m b (Int.unsigned ofs - 1)) && (Mem.valid_pointer m b' (Int.unsigned ofs') || Mem.valid_pointer m b' (Int.unsigned ofs' - 1))); try (inv H; fail).
      inv H. eapply negb_true_iff in H1. unfold Int.ltu in H1.
      destruct (zlt (Int.unsigned ofs') (Int.unsigned ofs)); inv H1. split; auto. omega.
    - destruct (Mem.valid_pointer m b (Int.unsigned ofs) && Mem.valid_pointer m b' (Int.unsigned ofs')); inv H.
  Qed.

  Lemma addr_of_annotations_singleton_translated':
    forall j sps tsps alpha tvals,
      list_forall2 (fun sp tsp => exists bsp btsp, sp = Vptr bsp Int.zero /\ tsp = Vptr btsp Int.zero /\ j bsp = Some (btsp, 0)) sps tsps ->
      (forall b id, Genv.find_symbol ge id = Some b -> j b = Some (b, 0)) ->
      (forall id range, In (ABglobal id range) alpha -> id <> STK /\ id <> SIZE) ->
      addr_of_annotations_singleton tge tsps alpha tvals ->
      exists vals, addr_of_annotations_singleton ge sps alpha vals /\ list_forall2 (match_vals j) vals tvals.
Proof.
    induction alpha; intros.
    - inv H2. exists nil; split; econstructor; eauto.
    - inv H2.
      + generalize (pop_inject' _ _ _ H _ _ H5). intros [sp' [A B]].
        destruct B as [bsp [tbsp [B [C D]]]]. subst sp'; subst sp.
        exploit IHalpha; eauto.
        { intros; eapply H1; eapply in_cons; eauto. }
        intros [vals2 [I J]].
        eexists; split.
        * econstructor; eauto.
        * econstructor; eauto.
          destruct (Int.eq_dec base bound).
          { econstructor; eauto. simpl. rewrite Int.add_zero_l.
            econstructor; eauto. rewrite Int.add_zero. eauto. }
          { econstructor; eauto.
            - simpl. rewrite Int.add_zero_l. econstructor; eauto. rewrite Int.add_zero. auto.
            - simpl. rewrite Int.add_zero_l. econstructor; eauto. rewrite Int.add_zero. auto. }
      + generalize (H1 _ _ (in_eq _ _)). intros [A B].
        rewrite symbols_preserved in H5; eauto.
        * generalize (H0 _ _ H5). intros C.
          exploit IHalpha; eauto.
          { intros; eapply H1; eapply in_cons; eauto. }
          intros [vals2 [HC HD]].
          eexists; split.
          { econstructor; eauto. }
          { econstructor; eauto.
            destruct (Int.eq_dec base bound).
            - econstructor; eauto. econstructor; eauto. rewrite Int.add_zero; auto.
            - econstructor; eauto; econstructor; eauto; rewrite Int.add_zero; auto. }
        * unfold not; intros. destruct H2 as [H2 | [H2 | H2]]; try (inv H2; fail).
          { eapply (proj1 (H1 _ _ (in_eq _ _))). eauto. }
          { eapply (proj2 (H1 _ _ (in_eq _ _))). eauto. }
  Qed.

  Lemma addr_of_annotations_singleton_translated:
    forall j sps tsps alpha vals,
      list_forall2 (fun sp tsp => exists bsp btsp, sp = Vptr bsp Int.zero /\ tsp = Vptr btsp Int.zero /\ j bsp = Some (btsp, 0)) sps tsps ->
      (forall b id, Genv.find_symbol ge id = Some b -> j b = Some (b, 0)) ->
      (forall id range, In (ABglobal id range) alpha -> id <> STK /\ id <> SIZE) ->
      addr_of_annotations_singleton ge sps alpha vals ->
      exists tvals, addr_of_annotations_singleton tge tsps alpha tvals /\ list_forall2 (match_vals j) vals tvals.
Proof.
    induction alpha; intros.
    - inv H2. exists nil; split; econstructor; eauto.
    - inv H2.
      + generalize (pop_inject _ _ _ _ H _ H5). intros [sp' [A B]].
        destruct B as [bsp [tbsp [B [C D]]]]. subst sp'; subst sp.
        exploit IHalpha; eauto.
        { intros; eapply H1; eapply in_cons; eauto. }
        intros [vals2 [I J]].
        eexists; split.
        * econstructor; eauto.
        * econstructor; eauto.
          destruct (Int.eq_dec base bound).
          { econstructor; eauto. simpl. rewrite Int.add_zero_l.
            econstructor; eauto. rewrite Int.add_zero. eauto. }
          { econstructor; eauto.
            - simpl. rewrite Int.add_zero_l. econstructor; eauto. rewrite Int.add_zero. auto.
            - simpl. rewrite Int.add_zero_l. econstructor; eauto. rewrite Int.add_zero. auto. }
      + generalize (H1 _ _ (in_eq _ _)). intros [A B].
        generalize (H0 _ _ H5). intros C.
        rewrite <- symbols_preserved in H5; eauto.
        * exploit IHalpha; eauto.
          { intros; eapply H1; eapply in_cons; eauto. }
          intros [vals2 [HC HD]].
          eexists; split.
          { econstructor; eauto. }
          { econstructor; eauto.
            destruct (Int.eq_dec base bound).
            - econstructor; eauto. econstructor; eauto. rewrite Int.add_zero; auto.
            - econstructor; eauto; econstructor; eauto; rewrite Int.add_zero; auto. }
        * unfold not; intros. destruct H2 as [H2 | [H2 | H2]]; try (inv H2; fail).
          { eapply (proj1 (H1 _ _ (in_eq _ _))). eauto. }
          { eapply (proj2 (H1 _ _ (in_eq _ _))). eauto. }
  Qed.

  Lemma load_step_singleton:
    forall s ts f tf sp tsp pc rs trs m tm alpha kappa addr args dst pc' a v vals (Htriv: MoreRTL.is_trivial_annotation prog alpha kappa addr = false) (Hsingleton: is_singleton (snd alpha) = true),
      match_states (State s f sp pc rs m) (State ts tf tsp pc trs tm) ->
      (fn_code f)!pc = Some (Iload alpha kappa addr args dst pc') ->
      eval_addressing ge sp addr (rs##args) = Some a ->
      Mem.loadv kappa m a = Some v ->
      addr_of_annotations_singleton ge (sp::map (fun s => match s with | Stackframe _ _ sp _ _ => sp end) s) (snd alpha) vals ->
      annot_sem (Genv.find_symbol ge) (sp::map (fun s => match s with | Stackframe _ _ sp _ _ => sp end) s) (snd alpha) a.
Proof.
    intros. inv H. exploit transf_function_spec; eauto. intros [pcs G].
    inv G. rewrite Htriv in H14. rewrite Hsingleton in H14.
    inv H14. assert (SPINJ': Val.inject j (Vptr sp0 Int.zero) (Vptr tsp0 Int.zero)) by (econstructor; eauto).
    generalize (max_reg_function_use' _ _ _ H0). simpl; intros XXXX.
    generalize (regs_agree_inject_list _ _ _ _ _ XXXX RES). intros YYYY.
    exploit (eval_addressing_inj ge tge); eauto.
    { intros. eapply symbol_address_inject; eauto. intros; eapply GINJ_implies; eauto. } intros [ta [XYY YYX]].
    generalize (Mem.loadv_inject j m tm kappa a ta v MINJ H2 YYX). intros [tv [ZA ZB]].
    assert (regs_agree j (max_reg_function f) rs (trs # reg0 <- ta)).
    { unfold regs_agree. intros; destruct (plt (max_reg_function f) r).
      - right; split; auto.
        rewrite UNDEF; eauto.
      - left; split; try xomega.
        generalize (RES r). intros [[D E] | D]; try xomega.
        rewrite PMap.gso; eauto. xomega. }
    exploit addr_of_annotations_singleton_translated; eauto.
    { econstructor; eauto.
      eapply match_stackframes_sps; eauto. }
    { intros. eapply GINJ. eapply ge.(Genv.genv_symb_range); eauto. }
    intros [tvals [Htvals Hinjtvals]].
    generalize (not_is_trivial_annotation_implies _ _ _ _ Htriv). intros Hnottriv.
    exploit tr_regs_annot_correct_singleton; eauto.
    { simpl. intros. destruct H20; eauto.
      eapply match_stackframes_sps_are_ptrs; eauto. }
    intros [trs' [HA [HB [HC HD]]]].
    generalize (tr_regs_annot_regs_singleton_plt _ _ _ _ _ _ _ _ H4). intros AA.
    generalize (tr_regs_annot_regs'_singleton_plt _ _ _ _ _ _ _ _ H4). intros AA'.
    generalize (tr_regs_annot_regs_singleton_norepet _ _ _ _ _ _ _ _ H4). intros AB.
    exploit tr_cmp_regs_correct_singleton; eauto. intros [trs'' [HE [HF HG]]].
    assert (J: star step tge (State ts tf (Vptr tsp0 Int.zero) pc1 trs tm) E0 (State ts tf (Vptr tsp0 Int.zero) (Psucc pc4) (trs'' # reg0 <- (trs''#reg1)) tm)).
    { eapply star_trans.
      - eapply star_step. eapply exec_Iop; eauto. destruct addr; simpl; eauto.
        destruct (Int.eq_dec i Int.zero); simpl; eauto.
        simpl in XYY. subst i. destruct trs##args; auto.
        destruct l; auto. rewrite <- XYY. inv XYY.
        unfold Mem.loadv in ZA. destruct v0; simpl in ZA; inv ZA.
        simpl; auto. simpl; rewrite Int.add_zero. reflexivity.
        eapply star_trans; eauto. eauto.
      - eapply star_one. eapply exec_Iop; eauto.
      - eauto. }
    generalize (regs_are_unknown_2 _ _ _ _ _ _ HF). intros XAXA. rewrite H6 in XAXA.
    assert (XAXA1: (trs''#reg1 = Vtrue \/ trs''#reg1 = Vfalse) \/ trs''#reg1 = Vundef) by (eapply or_assoc; eapply XAXA; eapply in_eq).
    assert (XAXA2: forall r, In r regs' -> trs'' # r = Vtrue \/ trs'' # r = Vfalse \/ trs'' # r = Vundef) by (intros; eapply XAXA; eapply in_cons; eauto).
    assert (NA': ~ In reg0 regs').
    { intro. destruct regs; simpl in H6; inv H6. eapply in_map_iff in H20. destruct H20 as [rx [SA SB]].
      eapply H18. simpl. clear -SA SB. destruct s0.
      - right. induction regs.
        + inv SB.
        + destruct SB.
          * subst a. destruct rx; subst; simpl; auto.
            destruct p; simpl; auto.
          * simpl. destruct a. right; auto.
            destruct p. right. right; auto.
      - destruct p. right. right. induction regs.
        + inv SB.
        + destruct SB.
          * subst a. destruct rx; subst; simpl; auto.
            destruct p; simpl; auto.
          * simpl. destruct a. right; auto.
            destruct p. right. right; auto. }destruct XAXA1 as [XAXA1 | XAXA1].
    { destruct (Classical_Prop.classic (exists r, trs'' # r = Vundef /\ In r regs')).
      - assert (CN1: trs'' # reg0 <- (trs'' # reg1) # reg0 = Vtrue \/ trs'' # reg0 <- (trs'' # reg1) # reg0 = Vfalse) by (rewrite PMap.gss; eauto).
        assert (CN2: forall r, In r regs' -> trs'' # reg0 <- (trs'' # reg1) # r = Vtrue \/ trs'' # reg0 <- (trs'' # reg1) # r = Vfalse \/ trs'' # reg0 <- (trs'' # reg1) # r = Vundef).
        { intros; rewrite ! PMap.gso. eapply XAXA2. eauto. unfold not; intros. subst r; eapply NA'; eauto. }
        assert (CN3: exists r, (trs'' # reg0 <- (trs'' # reg1)) # r = Vundef /\ In r regs').
        { destruct H20. eexists. rewrite PMap.gso. eapply H20. unfold not; intros; subst x. destruct H20; eapply NA'; eauto. }
        generalize (tr_or_regs_undef' ts _ tm _ _ _ _ _ tsp0 _ H8 NA' CN2 CN3 CN1). intros [trs''' [Hstar [Hundef Htrs''']]].
        assert (exists t, program_behaves (semantics tprog) (Goes_wrong t)).
        + destruct init_state_exists' as [s0 Hinit].
          generalize (STEP' _ Hinit). intros [t Hstep].
          eexists. econstructor; eauto.
          econstructor. eapply star_trans; eauto.
          eapply star_step. eapply exec_Inop; eauto.
          eapply star_trans. eapply J.
          eapply Hstar. eauto. eauto.
          red; unfold not; intros. inv H21; try congruence.
          rewrite H30 in H9; inv H9. simpl in H31. rewrite Hundef in H31. simpl in H31.
          inv H31.
          unfold not; intros. inv H21.
        + destruct H21. eapply DEFSAFE in H21; inv H21.
      - generalize (proj1 (not_undef _ _ XAXA2) H20). intros XAXA3.
        assert (XAXA4: forall r, In r (reg1 :: regs') -> trs'' # r = Vtrue \/ trs'' # r = Vfalse).
        { intros. destruct H21; eauto. subst r; eauto. }
        assert (AC': forall v, In v tvals -> match v with | inl v0 => exists (b : block) (ofs : int), v0 = Vptr b ofs | inr (v0, v') => exists (b : block) (ofs ofs' : int), v0 = Vptr b ofs /\ v' = Vptr b ofs' end).
        { intros; exploit addr_of_annotations_singleton_in_implies; eauto.
          - simpl. intros. destruct H22; eauto.
            eapply match_stackframes_sps_are_ptrs; eauto.
          - intros LA. destruct v0; eauto.
            + destruct LA as [b [ofs [LA LB]]]; eauto.
            + destruct p. destruct LA as [b [ofs1 [ofs2 [LA [LB LC]]]]]; eauto. }
        destruct (Classical_Prop.classic (exists r, trs''#r = Vtrue /\ In r (reg1::regs'))).
        { destruct H21 as [r [MA MB]].
          assert ((exists tv, In (inl tv) tvals /\ trs''#r = Val.of_optbool (eval_condition (Ccompu Ceq) (tv :: trs' # reg0 :: nil) tm)) \/
                  (exists tv1 tv2, In (inr (tv1, tv2)) tvals /\ trs''#r = Val.and (Val.of_optbool (Val.cmpu_bool (Mem.valid_pointer tm) Cle tv1 trs' # reg0)) (Val.of_optbool (Val.cmpu_bool (Mem.valid_pointer tm) Cle trs' # reg0 tv2)))).
          { clear -MB HF H6. rewrite <- H6 in MB. clear H6.
            eapply in_map_iff in MB. destruct MB as [x [K1 K2]].
            exploit list_forall2_in_1; eauto. intros [y [J1 J2]].
            unfold match_reg_val' in J2. destruct x; destruct y; try (inv J2; fail).
            - left; eexists; split; eauto. subst r0; eauto.
            - destruct p; inv J2.
            - destruct p; destruct p0. right. eexists. eexists. split; eauto.
              simpl in K1; subst r0. eauto. }
          destruct H21 as [[tv0 [K1 K2]] | [tv1 [tv2 [K1 K2]]]].
          { exploit addr_of_annotations_singleton_in_implies; eauto.
            - simpl. intros. destruct H21; eauto.
              eapply match_stackframes_sps_are_ptrs; eauto.
            - simpl. intros [b [ofs [W1 W2]]]. subst tv0.
              rewrite MA in K2. eapply eq_sym in K2.
              eapply eval_condition_is_true_implies in K2.
              rewrite <- HD in K2. rewrite PMap.gss in K2.
              subst ta. destruct a; simpl in H2; inv H2.
              right. destruct W2 as [W2 | W2].
              + destruct W2 as [depth [varname [W2 W3]]].
                left. eexists. eexists. eexists. eexists. split; eauto.
                rewrite <- pop_is_nth in W2. exploit pop_inject'; eauto.
                { econstructor; try (eapply match_stackframes_sps; eauto).
                  simpl. eauto. }
                simpl. intros [sp [U1 U2]].
                destruct U2 as [bsp [btsp [U2 [U3 U4]]]].
                subst sp; inv U4. rewrite pop_is_nth in U1.
                eexists. eexists; split; eauto. simpl. rewrite Int.add_zero_l.
                inv U3. inv YYX. generalize (FLATINJ _ _ _ H25). intros; subst delta.
                generalize (FLATINJ' _ _ _ H25 H21). intros; subst b0. rewrite Int.add_zero.
                split; eauto. Psatz.lia.
              + destruct W2 as [id [W2 W3]].
                right. eexists. eexists. eexists. split; eauto.
                rewrite symbols_preserved in W2.
                eexists. eexists. split; eauto. inv YYX.
                generalize (FLATINJ _ _ _ H24). intros; subst delta.
                eapply GINJ' in H24. subst b0; split; eauto.
                rewrite Int.add_zero; Psatz.lia.
                eapply Genv.genv_symb_range; eauto. generalize (H16 _ _ W3). intros [SA SB].
                intro. destruct H2; try congruence. destruct H2; try congruence. unfold SIZE in H2. congruence. inv H2.
              + eapply not_in_app. split; auto. }
          { rewrite MA in K2. eapply eq_sym in K2. eapply valand_true in K2.
            destruct K2 as [K2 K3]. eapply optbool_true in K2. eapply optbool_true in K3.
            exploit addr_of_annotations_singleton_in_implies; eauto.
            - simpl. intros. destruct H21; eauto.
              eapply match_stackframes_sps_are_ptrs; eauto.
            - simpl. intros [b [ofs1 [ofs2 [W1 [W2 W3]]]]].
              subst tv1; subst tv2. assert (trs'#reg0 = ta).
              { rewrite <- HD. eapply PMap.gss.
                eapply not_in_app; eauto. }
              rewrite H21 in *. clear H21. destruct a; simpl in H2; inv H2.
              inv YYX. generalize (FLATINJ _ _ _ H23). intros; subst delta. rewrite Int.add_zero in K2, K3.
              eapply cmpu_bool_cle_true_implies in K2. eapply cmpu_bool_cle_true_implies in K3.
              destruct K2 as [KK K2]. subst b2. destruct K3 as [KK K3]. clear KK.
              right. destruct W3 as [W3 | W3].
              + destruct W3 as [depth [varname [W3 W4]]].
                left. eexists. eexists. eexists. eexists. split; eauto.
                rewrite <- pop_is_nth in W3. exploit pop_inject'; eauto.
                { econstructor; try (eapply match_stackframes_sps; eauto).
                  simpl. eauto. }
                simpl. intros [sp [U1 U2]].
                destruct U2 as [bsp [btsp [U2 [U3 U4]]]].
                subst sp; inv U4. rewrite pop_is_nth in U1.
                eexists. eexists; split; eauto. simpl. rewrite Int.add_zero_l.
                inv U3. generalize (FLATINJ' _ _ _ H23 H21). intros; subst b0.
                split; eauto.
              + destruct W3 as [id [W3 W4]].
                right. eexists. eexists. eexists. split; eauto.
                rewrite symbols_preserved in W3.
                eexists. eexists. split; eauto.
                eapply GINJ' in H23. subst b0; split; eauto.
                eapply Genv.genv_symb_range; eauto. generalize (H16 _ _ W4). intros [SA SB].
                intro. destruct H2; try congruence. destruct H2; try congruence. unfold SIZE in H2. congruence. inv H2. } }
        { generalize (Classical_Pred_Type.not_ex_all_not _ _ H21). intros Hall.
          assert (Hall': forall r, In r (reg1::regs') -> trs''#r = Vfalse).
          { intros. generalize (XAXA4 _ H22); intros. destruct H23; auto.
            exfalso. eapply Hall. split; eauto. }
          exploit tr_or_regs_false; eauto.
          instantiate (1 := trs''#reg0 <- (trs''#reg1)). intros.
          rewrite PMap.gso. eapply Hall'; right; auto.
          intro; eapply NA'; subst r; auto.
          rewrite PMap.gss. eapply Hall'; left; auto.
          intros [trs''' [Hstar [Hfalse Htrs''']]]. inv H11.
          assert (exists t, program_behaves (semantics tprog) (Goes_wrong t)).
          - destruct init_state_exists' as [s0 Hinit].
            generalize (STEP' _ Hinit). intros [t Hstep].
            eexists. econstructor; eauto.
            econstructor. eapply star_trans; eauto.
            eapply star_step. eapply exec_Inop; eauto.
            eapply star_trans. eapply J.
            eapply star_trans. eapply Hstar.
            eapply star_step. eapply exec_Icond; eauto.
            simpl. rewrite Hfalse. simpl. rewrite Int.eq_true. simpl. auto.
            simpl. eapply star_step. eapply exec_Iop; eauto.
            simpl. eauto. eapply star_step. eapply exec_Iop; eauto.
            simpl. eauto. eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto.
            red; unfold not; intros. inv H11; try congruence.
            rewrite H34 in H24; inv H24. simpl in H35.
            rewrite PMap.gss in H35. rewrite PMap.gso in H35; auto.
            rewrite PMap.gss in H35. simpl in H35. rewrite Int.eq_true in H35.
            simpl in H35. inv H35.
            unfold not; intros. inv H11.
          - destruct H11. eapply DEFSAFE in H11; inv H11. } }
    { assert (XAXA3: trs''#reg0 <- (trs''#reg1)#reg0 = Vundef) by (rewrite PMap.gss; rewrite XAXA1; auto).
      exploit tr_or_regs_undef; eauto.
      intros [trs''' [Hstar [Hundef Htrs''']]].
      assert (exists t, program_behaves (semantics tprog) (Goes_wrong t)).
      - destruct init_state_exists' as [s0 Hinit].
        generalize (STEP' _ Hinit). intros [t Hstep].
        eexists. econstructor; eauto.
        econstructor. eapply star_trans; eauto.
        eapply star_step. eapply exec_Inop; eauto.
        eapply star_trans. eapply J.
        eapply Hstar. eauto. eauto.
        red; unfold not; intros. inv H20; try congruence.
        rewrite H29 in H9; inv H9. simpl in H30. rewrite Hundef in H30. simpl in H30.
        inv H30.
        unfold not; intros. inv H20.
      - destruct H20. eapply DEFSAFE in H20; inv H20. }
  Qed.

  Lemma store_step_singleton:
    forall s ts f tf sp tsp pc rs trs m m' tm alpha kappa addr args src pc' a vals (Htriv: MoreRTL.is_trivial_annotation prog alpha kappa addr = false) (Hsingleton: is_singleton (snd alpha) = true),
      match_states (State s f sp pc rs m) (State ts tf tsp pc trs tm) ->
      (fn_code f)!pc = Some (Istore alpha kappa addr args src pc') ->
      eval_addressing ge sp addr (rs##args) = Some a ->
      Mem.storev kappa m a rs#src = Some m' ->
      addr_of_annotations_singleton ge (sp::map (fun s => match s with | Stackframe _ _ sp _ _ => sp end) s) (snd alpha) vals ->
      annot_sem (Genv.find_symbol ge) (sp::map (fun s => match s with | Stackframe _ _ sp _ _ => sp end) s) (snd alpha) a.
Proof.
    intros. inv H. exploit transf_function_spec; eauto. intros [pcs G].
    inv G. rewrite Htriv in H14. rewrite Hsingleton in H14.
    inv H14. assert (SPINJ': Val.inject j (Vptr sp0 Int.zero) (Vptr tsp0 Int.zero)) by (econstructor; eauto).
    generalize (max_reg_function_use' _ _ _ H0). simpl; intros XXXX.
    generalize (regs_agree_inject_list _ _ _ _ _ (fun r H => XXXX r (or_intror H)) RES). intros YYYY.
    exploit (eval_addressing_inj ge tge); eauto.
    { intros. eapply symbol_address_inject; eauto. intros; eapply GINJ_implies; eauto. } intros [ta [XYY YYX]].
    assert (ZYF: Val.inject j rs#src trs#src).
    { generalize (max_reg_function_use' _ _ _ H0 src (or_introl eq_refl)). intros.
      generalize (RES src). intros [[A B] | [A B]]; try xomega; eauto. }
    generalize (Mem.storev_mapped_inject j kappa m a rs#src m' tm ta trs#src MINJ H2 YYX ZYF). intros [tm' [ZA ZB]].
    assert (regs_agree j (max_reg_function f) rs (trs # reg0 <- ta)).
    { unfold regs_agree. intros; destruct (plt (max_reg_function f) r).
      - right; split; auto.
        rewrite UNDEF; eauto.
      - left; split; try xomega.
        generalize (RES r). intros [[D E] | D]; try xomega.
        rewrite PMap.gso; eauto. xomega. }
    exploit addr_of_annotations_singleton_translated; eauto.
    { econstructor; eauto.
      eapply match_stackframes_sps; eauto. }
    { intros. eapply GINJ. eapply ge.(Genv.genv_symb_range); eauto. }
    intros [tvals [Htvals Hinjtvals]].
    generalize (not_is_trivial_annotation_implies _ _ _ _ Htriv). intros Hnottriv.
    exploit tr_regs_annot_correct_singleton; eauto.
    { simpl. intros. destruct H20; eauto.
      eapply match_stackframes_sps_are_ptrs; eauto. }
    intros [trs' [HA [HB [HC HD]]]].
    generalize (tr_regs_annot_regs_singleton_plt _ _ _ _ _ _ _ _ H4). intros AA.
    generalize (tr_regs_annot_regs'_singleton_plt _ _ _ _ _ _ _ _ H4). intros AA'.
    generalize (tr_regs_annot_regs_singleton_norepet _ _ _ _ _ _ _ _ H4). intros AB.
    exploit tr_cmp_regs_correct_singleton; eauto. intros [trs'' [HE [HF HG]]].
    assert (J: star step tge (State ts tf (Vptr tsp0 Int.zero) pc1 trs tm) E0 (State ts tf (Vptr tsp0 Int.zero) (Psucc pc4) (trs'' # reg0 <- (trs''#reg1)) tm)).
    { eapply star_trans.
      - eapply star_step. eapply exec_Iop; eauto. destruct addr; simpl; eauto.
        destruct (Int.eq_dec i Int.zero); simpl; eauto.
        simpl in XYY. subst i. destruct trs##args; auto.
        destruct l; auto. rewrite <- XYY. inv XYY.
        unfold Mem.storev in ZA. destruct v; simpl in ZA; inv ZA.
        simpl; auto. simpl; rewrite Int.add_zero. reflexivity.
        eapply star_trans; eauto. eauto.
      - eapply star_one. eapply exec_Iop; eauto.
      - eauto. }
    generalize (regs_are_unknown_2 _ _ _ _ _ _ HF). intros XAXA. rewrite H6 in XAXA.
    assert (XAXA1: (trs''#reg1 = Vtrue \/ trs''#reg1 = Vfalse) \/ trs''#reg1 = Vundef) by (eapply or_assoc; eapply XAXA; eapply in_eq).
    assert (XAXA2: forall r, In r regs' -> trs'' # r = Vtrue \/ trs'' # r = Vfalse \/ trs'' # r = Vundef) by (intros; eapply XAXA; eapply in_cons; eauto).
    assert (NA': ~ In reg0 regs').
    { intro. destruct regs; simpl in H6; inv H6. eapply in_map_iff in H20. destruct H20 as [rx [SA SB]].
      eapply H18. simpl. clear -SA SB. destruct s0.
      - right. induction regs.
        + inv SB.
        + destruct SB.
          * subst a. destruct rx; subst; simpl; auto.
            destruct p; simpl; auto.
          * simpl. destruct a. right; auto.
            destruct p. right. right; auto.
      - destruct p. right. right. induction regs.
        + inv SB.
        + destruct SB.
          * subst a. destruct rx; subst; simpl; auto.
            destruct p; simpl; auto.
          * simpl. destruct a. right; auto.
            destruct p. right. right; auto. }destruct XAXA1 as [XAXA1 | XAXA1].
    { destruct (Classical_Prop.classic (exists r, trs'' # r = Vundef /\ In r regs')).
      - assert (CN1: trs'' # reg0 <- (trs'' # reg1) # reg0 = Vtrue \/ trs'' # reg0 <- (trs'' # reg1) # reg0 = Vfalse) by (rewrite PMap.gss; eauto).
        assert (CN2: forall r, In r regs' -> trs'' # reg0 <- (trs'' # reg1) # r = Vtrue \/ trs'' # reg0 <- (trs'' # reg1) # r = Vfalse \/ trs'' # reg0 <- (trs'' # reg1) # r = Vundef).
        { intros; rewrite ! PMap.gso. eapply XAXA2. eauto. unfold not; intros. subst r; eapply NA'; eauto. }
        assert (CN3: exists r, (trs'' # reg0 <- (trs'' # reg1)) # r = Vundef /\ In r regs').
        { destruct H20. eexists. rewrite PMap.gso. eapply H20. unfold not; intros; subst x. destruct H20; eapply NA'; eauto. }
        generalize (tr_or_regs_undef' ts _ tm _ _ _ _ _ tsp0 _ H8 NA' CN2 CN3 CN1). intros [trs''' [Hstar [Hundef Htrs''']]].
        assert (exists t, program_behaves (semantics tprog) (Goes_wrong t)).
        + destruct init_state_exists' as [s0 Hinit].
          generalize (STEP' _ Hinit). intros [t Hstep].
          eexists. econstructor; eauto.
          econstructor. eapply star_trans; eauto.
          eapply star_step. eapply exec_Inop; eauto.
          eapply star_trans. eapply J.
          eapply Hstar. eauto. eauto.
          red; unfold not; intros. inv H21; try congruence.
          rewrite H30 in H9; inv H9. simpl in H31. rewrite Hundef in H31. simpl in H31.
          inv H31.
          unfold not; intros. inv H21.
        + destruct H21. eapply DEFSAFE in H21; inv H21.
      - generalize (proj1 (not_undef _ _ XAXA2) H20). intros XAXA3.
        assert (XAXA4: forall r, In r (reg1 :: regs') -> trs'' # r = Vtrue \/ trs'' # r = Vfalse).
        { intros. destruct H21; eauto. subst r; eauto. }
        assert (AC': forall v, In v tvals -> match v with | inl v0 => exists (b : block) (ofs : int), v0 = Vptr b ofs | inr (v0, v') => exists (b : block) (ofs ofs' : int), v0 = Vptr b ofs /\ v' = Vptr b ofs' end).
        { intros; exploit addr_of_annotations_singleton_in_implies; eauto.
          - simpl. intros. destruct H22; eauto.
            eapply match_stackframes_sps_are_ptrs; eauto.
          - intros LA. destruct v; eauto.
            + destruct LA as [b [ofs [LA LB]]]; eauto.
            + destruct p. destruct LA as [b [ofs1 [ofs2 [LA [LB LC]]]]]; eauto. }
        destruct (Classical_Prop.classic (exists r, trs''#r = Vtrue /\ In r (reg1::regs'))).
        { destruct H21 as [r [MA MB]].
          assert ((exists tv, In (inl tv) tvals /\ trs''#r = Val.of_optbool (eval_condition (Ccompu Ceq) (tv :: trs' # reg0 :: nil) tm)) \/
                  (exists tv1 tv2, In (inr (tv1, tv2)) tvals /\ trs''#r = Val.and (Val.of_optbool (Val.cmpu_bool (Mem.valid_pointer tm) Cle tv1 trs' # reg0)) (Val.of_optbool (Val.cmpu_bool (Mem.valid_pointer tm) Cle trs' # reg0 tv2)))).
          { clear -MB HF H6. rewrite <- H6 in MB. clear H6.
            eapply in_map_iff in MB. destruct MB as [x [K1 K2]].
            exploit list_forall2_in_1; eauto. intros [y [J1 J2]].
            unfold match_reg_val' in J2. destruct x; destruct y; try (inv J2; fail).
            - left; eexists; split; eauto. subst r0; eauto.
            - destruct p; inv J2.
            - destruct p; destruct p0. right. eexists. eexists. split; eauto.
              simpl in K1; subst r0. eauto. }
          destruct H21 as [[tv0 [K1 K2]] | [tv1 [tv2 [K1 K2]]]].
          { exploit addr_of_annotations_singleton_in_implies; eauto.
            - simpl. intros. destruct H21; eauto.
              eapply match_stackframes_sps_are_ptrs; eauto.
            - simpl. intros [b [ofs [W1 W2]]]. subst tv0.
              rewrite MA in K2. eapply eq_sym in K2.
              eapply eval_condition_is_true_implies in K2.
              rewrite <- HD in K2. rewrite PMap.gss in K2.
              subst ta. destruct a; simpl in H2; inv H2.
              right. destruct W2 as [W2 | W2].
              + destruct W2 as [depth [varname [W2 W3]]].
                left. eexists. eexists. eexists. eexists. split; eauto.
                rewrite <- pop_is_nth in W2. exploit pop_inject'; eauto.
                { econstructor; try (eapply match_stackframes_sps; eauto).
                  simpl. eauto. }
                simpl. intros [sp [U1 U2]].
                destruct U2 as [bsp [btsp [U2 [U3 U4]]]].
                subst sp; inv U4. rewrite pop_is_nth in U1.
                eexists. eexists; split; eauto. simpl. rewrite Int.add_zero_l.
                inv U3. inv YYX. generalize (FLATINJ _ _ _ H25). intros; subst delta.
                generalize (FLATINJ' _ _ _ H25 H21). intros; subst b0. rewrite Int.add_zero.
                split; eauto. Psatz.lia.
              + destruct W2 as [id [W2 W3]].
                right. eexists. eexists. eexists. split; eauto.
                rewrite symbols_preserved in W2.
                eexists. eexists. split; eauto. inv YYX.
                generalize (FLATINJ _ _ _ H24). intros; subst delta.
                eapply GINJ' in H24. subst b0; split; eauto.
                rewrite Int.add_zero; Psatz.lia.
                eapply Genv.genv_symb_range; eauto. generalize (H16 _ _ W3). intros [SA SB].
                intro. destruct H2; try congruence. destruct H2; try congruence. unfold SIZE in H2. congruence. inv H2.
              + eapply not_in_app. split; auto. }
          { rewrite MA in K2. eapply eq_sym in K2. eapply valand_true in K2.
            destruct K2 as [K2 K3]. eapply optbool_true in K2. eapply optbool_true in K3.
            exploit addr_of_annotations_singleton_in_implies; eauto.
            - simpl. intros. destruct H21; eauto.
              eapply match_stackframes_sps_are_ptrs; eauto.
            - simpl. intros [b [ofs1 [ofs2 [W1 [W2 W3]]]]].
              subst tv1; subst tv2. assert (trs'#reg0 = ta).
              { rewrite <- HD. eapply PMap.gss.
                eapply not_in_app; eauto. }
              rewrite H21 in *. clear H21. destruct a; simpl in H2; inv H2.
              inv YYX. generalize (FLATINJ _ _ _ H23). intros; subst delta. rewrite Int.add_zero in K2, K3.
              eapply cmpu_bool_cle_true_implies in K2. eapply cmpu_bool_cle_true_implies in K3.
              destruct K2 as [KK K2]. subst b2. destruct K3 as [KK K3]. clear KK.
              right. destruct W3 as [W3 | W3].
              + destruct W3 as [depth [varname [W3 W4]]].
                left. eexists. eexists. eexists. eexists. split; eauto.
                rewrite <- pop_is_nth in W3. exploit pop_inject'; eauto.
                { econstructor; try (eapply match_stackframes_sps; eauto).
                  simpl. eauto. }
                simpl. intros [sp [U1 U2]].
                destruct U2 as [bsp [btsp [U2 [U3 U4]]]].
                subst sp; inv U4. rewrite pop_is_nth in U1.
                eexists. eexists; split; eauto. simpl. rewrite Int.add_zero_l.
                inv U3. generalize (FLATINJ' _ _ _ H23 H21). intros; subst b0.
                split; eauto.
              + destruct W3 as [id [W3 W4]].
                right. eexists. eexists. eexists. split; eauto.
                rewrite symbols_preserved in W3.
                eexists. eexists. split; eauto.
                eapply GINJ' in H23. subst b0; split; eauto.
                eapply Genv.genv_symb_range; eauto. generalize (H16 _ _ W4). intros [SA SB].
                intro. destruct H2; try congruence. destruct H2; try congruence. unfold SIZE in H2. congruence. inv H2. } }
        { generalize (Classical_Pred_Type.not_ex_all_not _ _ H21). intros Hall.
          assert (Hall': forall r, In r (reg1::regs') -> trs''#r = Vfalse).
          { intros. generalize (XAXA4 _ H22); intros. destruct H23; auto.
            exfalso. eapply Hall. split; eauto. }
          exploit tr_or_regs_false; eauto.
          instantiate (1 := trs''#reg0 <- (trs''#reg1)). intros.
          rewrite PMap.gso. eapply Hall'; right; auto.
          intro; eapply NA'; subst r; auto.
          rewrite PMap.gss. eapply Hall'; left; auto.
          intros [trs''' [Hstar [Hfalse Htrs''']]]. inv H11.
          assert (exists t, program_behaves (semantics tprog) (Goes_wrong t)).
          - destruct init_state_exists' as [s0 Hinit].
            generalize (STEP' _ Hinit). intros [t Hstep].
            eexists. econstructor; eauto.
            econstructor. eapply star_trans; eauto.
            eapply star_step. eapply exec_Inop; eauto.
            eapply star_trans. eapply J.
            eapply star_trans. eapply Hstar.
            eapply star_step. eapply exec_Icond; eauto.
            simpl. rewrite Hfalse. simpl. rewrite Int.eq_true. simpl. auto.
            simpl. eapply star_step. eapply exec_Iop; eauto.
            simpl. eauto. eapply star_step. eapply exec_Iop; eauto.
            simpl. eauto. eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto.
            red; unfold not; intros. inv H11; try congruence.
            rewrite H34 in H24; inv H24. simpl in H35.
            rewrite PMap.gss in H35. rewrite PMap.gso in H35; auto.
            rewrite PMap.gss in H35. simpl in H35. rewrite Int.eq_true in H35.
            simpl in H35. inv H35.
            unfold not; intros. inv H11.
          - destruct H11. eapply DEFSAFE in H11; inv H11. } }
    { assert (XAXA3: trs''#reg0 <- (trs''#reg1)#reg0 = Vundef) by (rewrite PMap.gss; rewrite XAXA1; auto).
      exploit tr_or_regs_undef; eauto.
      intros [trs''' [Hstar [Hundef Htrs''']]].
      assert (exists t, program_behaves (semantics tprog) (Goes_wrong t)).
      - destruct init_state_exists' as [s0 Hinit].
        generalize (STEP' _ Hinit). intros [t Hstep].
        eexists. econstructor; eauto.
        econstructor. eapply star_trans; eauto.
        eapply star_step. eapply exec_Inop; eauto.
        eapply star_trans. eapply J.
        eapply Hstar. eauto. eauto.
        red; unfold not; intros. inv H20; try congruence.
        rewrite H29 in H9; inv H9. simpl in H30. rewrite Hundef in H30. simpl in H30.
        inv H30.
        unfold not; intros. inv H20.
      - destruct H20. eapply DEFSAFE in H20; inv H20. }
  Qed.

  Lemma load_checks_are_correct:
    forall stk f sp pc rs m tstk tf tsp tpc trs tm alpha kappa addr args dst pc' a v,
      match_states (State stk f sp pc rs m) (State tstk tf tsp tpc trs tm) ->
      (fn_code f)!pc = Some (Iload alpha kappa addr args dst pc') ->
      eval_addressing ge sp addr (rs##args) = Some a ->
      Mem.loadv kappa m a = Some v ->
      annot_sem (Genv.find_symbol ge)
                (sp :: map (fun s : stackframe => match s with
                                               | Stackframe _ _ sp _ _ => sp
                                               end) stk) (snd alpha) a ->
      exists s2', plus step tge (State tstk tf tsp tpc trs tm) E0 s2' /\
             match_states (State stk f sp pc' (rs#dst <- v) m) s2'.
Proof.
    intros; inv H. generalize (transf_function_spec prog STK _ _ _ _ FUN H0). intros [pcs HA].
    inv HA. case_eq (MoreRTL.is_trivial_annotation prog alpha kappa addr); intros; rename H into HOH; rewrite HOH in H14.
    { assert (SPINJ': Val.inject j (Vptr sp0 Int.zero) (Vptr tsp0 Int.zero)) by (econstructor; eauto).
      generalize (max_reg_function_use' _ _ _ H0). simpl; intros XXXX.
      generalize (regs_agree_inject_list _ _ _ _ _ XXXX RES). intros YYYY.
      exploit (eval_addressing_inj ge tge); eauto.
      { intros. eapply symbol_address_inject; eauto. intros; eapply GINJ_implies; eauto. } intros [ta [XYY YYX]].
      generalize (Mem.loadv_inject j m tm kappa a ta v MINJ H2 YYX). intros [tv [ZA ZB]].
      eexists. split.
      - econstructor. eapply exec_Inop; eauto.
        eapply star_step. eapply exec_Iload; eauto.
        eapply star_refl. eauto. eauto.
      - econstructor; eauto.
        + red; intros. destruct (peq r dst).
          * subst r; rewrite ! PMap.gss. left.
            generalize (max_reg_function_def _ _ _ _ H0 eq_refl). intros; split; auto.
          * rewrite ! PMap.gso; eauto.
        + intros. eapply STEP in H; eauto. destruct H as [t Hstep].
          exists (t ** E0); eapply star_right; eauto. eapply exec_Iload_block'; eauto.
        + intros. eapply STEP' in H; eauto. destruct H as [t Hstep].
          exists (t ** E0); eapply star_trans; eauto. eapply star_step. eapply exec_Inop; eauto.
          eapply star_step. eapply exec_Iload; eauto. eapply star_refl.
          eauto. eauto.
        + intros; rewrite PMap.gso; eauto.
          generalize (max_reg_function_def _ _ _ _ H0 eq_refl). intros; xomega. }
    case_eq (is_singleton (snd alpha)); intros; rename H into HOH2; rewrite HOH2 in H14.
    { inv H14. assert (SPINJ': Val.inject j (Vptr sp0 Int.zero) (Vptr tsp0 Int.zero)) by (econstructor; eauto).
      generalize (max_reg_function_use' _ _ _ H0). simpl; intros XXXX.
      generalize (regs_agree_inject_list _ _ _ _ _ XXXX RES). intros YYYY.
      exploit (eval_addressing_inj ge tge); eauto.
      { intros. eapply symbol_address_inject; eauto. intros; eapply GINJ_implies; eauto. } intros [ta [XYY YYX]].
      generalize (Mem.loadv_inject j m tm kappa a ta v MINJ H2 YYX). intros [tv [ZA ZB]].
      assert (regs_agree j (max_reg_function f) rs (trs # reg0 <- ta)).
      { unfold regs_agree. intros; destruct (plt (max_reg_function f) r).
        - right; split; auto.
          rewrite UNDEF; eauto.
        - left; split; try xomega.
          generalize (RES r). intros [[D E] | D]; try xomega.
          rewrite PMap.gso; eauto. xomega. }
      exploit tr_regs_annot_inv_singleton; eauto.
      { intros. destruct H20; eauto.
        eapply match_stackframes_sps_are_ptrs; eauto. }
      { intros. eapply STEP' in H20. destruct H20.
        eexists. eapply star_trans; eauto.
        eapply star_two. eapply exec_Inop; eauto.
        eapply exec_Iop; eauto. destruct addr; simpl; eauto.
        destruct (Int.eq_dec i Int.zero); simpl; eauto. subst i.
        simpl in XYY. destruct trs##args; inv XYY.
        destruct l; auto. destruct ta; simpl in ZA; inv ZA.
        destruct v0; simpl in H22; inv H22. simpl. rewrite Int.add_zero; auto.
        eauto. } intros [tvals' LA].
      assert (FFFFF: (forall sp : val, In sp (Vptr tsp0 Int.zero :: map (fun s : stackframe => match s with | Stackframe _ _ tsp _ _ => tsp end) tstk) -> exists b : block, sp = Vptr b Int.zero)).
      { intros. destruct H20. inv H20; eauto. eapply match_stackframes_sps_are_ptrs; eauto. }
      assert (GGGGG: (forall sp : val, In sp (Vptr sp0 Int.zero :: map (fun s : stackframe => match s with | Stackframe _ _ tsp _ _ => tsp end) stk) -> exists b : block, sp = Vptr b Int.zero)).
      { intros. destruct H20. inv H20; eauto. eapply match_stackframes_sps_are_ptrs'; eauto. }
      generalize (tr_regs_annot_correct_singleton _ _ _ _ _ _ _ _ _ _ _ _ _ _ tm FFFFF H4 LA H14 UNDEF SHADOW). intros [trs' [HA [HB [HC HD]]]].
      generalize (tr_regs_annot_regs_singleton_plt _ _ _ _ _ _ _ _ H4). intros AA.
      generalize (tr_regs_annot_regs'_singleton_plt _ _ _ _ _ _ _ _ H4). intros AA'.
      generalize (tr_regs_annot_regs_singleton_norepet _ _ _ _ _ _ _ _ H4). intros AB.
      generalize (tr_cmp_regs_correct_singleton j tstk (Vptr tsp0 Int.zero) f tf reg0 _ pc3 pc4 pcs2 tm rs trs' tvals' H5 H18 HB HC AA UNDEF AB). intros [trs'' [HE [HF HG]]].
      generalize (regs_are_unknown_2 _ _ _ _ _ _ HF). intros XAXA. rewrite H6 in XAXA.
      assert (XAXA1: (trs''#reg1 = Vtrue \/ trs''#reg1 = Vfalse) \/ trs''#reg1 = Vundef) by (eapply or_assoc; eapply XAXA; eapply in_eq).
      assert (XAXA2: forall r, In r regs' -> trs'' # r = Vtrue \/ trs'' # r = Vfalse \/ trs'' # r = Vundef) by (intros; eapply XAXA; eapply in_cons; eauto).
      destruct XAXA1 as [XAXA1 | XAXA1].
      { destruct (Classical_Prop.classic (exists r, trs'' # r = Vundef /\ In r regs')).
        - assert (NA': ~ In reg0 regs').
          { intro. destruct regs; simpl in H6; inv H6. eapply in_map_iff in H21. destruct H21 as [rx [SA SB]].
            eapply H18. simpl. clear -SA SB. destruct s.
            - right. induction regs.
              + inv SB.
              + destruct SB.
                * subst a. destruct rx; subst; simpl; auto.
                  destruct p; simpl; auto.
                * simpl. destruct a. right; auto.
                  destruct p. right. right; auto.
            - destruct p. right. right. induction regs.
              + inv SB.
              + destruct SB.
                * subst a. destruct rx; subst; simpl; auto.
                  destruct p; simpl; auto.
                * simpl. destruct a. right; auto.
                  destruct p. right. right; auto. }
          assert (CN1: trs'' # reg0 <- (trs'' # reg1) # reg0 = Vtrue \/ trs'' # reg0 <- (trs'' # reg1) # reg0 = Vfalse) by (rewrite PMap.gss; eauto).
          assert (CN2: forall r, In r regs' -> trs'' # reg0 <- (trs'' # reg1) # r = Vtrue \/ trs'' # reg0 <- (trs'' # reg1) # r = Vfalse \/ trs'' # reg0 <- (trs'' # reg1) # r = Vundef).
          { intros; rewrite ! PMap.gso. eapply XAXA2. eauto. unfold not; intros. subst r; eapply NA'; eauto. }
          assert (CN3: exists r, (trs'' # reg0 <- (trs'' # reg1)) # r = Vundef /\ In r regs').
          { destruct H20. eexists. rewrite PMap.gso. eapply H20. unfold not; intros; subst x. destruct H20; eapply NA'; eauto. }
          generalize (tr_or_regs_undef' tstk _ tm _ _ _ _ _ tsp0 _ H8 NA' CN2 CN3 CN1). intros [trs''' [Hstar [Hundef Htrs''']]].
          assert (exists t, program_behaves (semantics tprog) (Goes_wrong t)).
          + destruct init_state_exists' as [s0 Hinit].
            generalize (STEP' _ Hinit). intros [t Hstep].
            eexists. econstructor; eauto.
            econstructor. eapply star_trans; eauto.
            eapply star_step. eapply exec_Inop; eauto.
            eapply star_step. eapply exec_Iop; eauto.
            destruct addr; simpl; eauto.
            destruct (Int.eq_dec i Int.zero); simpl; eauto.
            simpl in XYY. subst i. destruct trs##args; auto.
            destruct l; auto. rewrite <- XYY. inv XYY.
            unfold Mem.loadv in ZA. destruct v0; simpl in ZA; inv ZA.
            simpl; auto. simpl; rewrite Int.add_zero. reflexivity.
            eapply star_trans. eapply HA.
            eapply star_trans. eapply HE.
            eapply star_step. eapply exec_Iop; eauto.
            simpl. eauto. eapply star_trans. eapply Hstar.
            eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto.
            red; unfold not; intros. inv H21; try congruence.
            rewrite H30 in H9; inv H9. simpl in H31. rewrite Hundef in H31. simpl in H31.
            inv H31.
            unfold not; intros. inv H21.
        + destruct H21. eapply DEFSAFE in H21; inv H21.
      - generalize (proj1 (not_undef _ _ XAXA2) H20). intros XAXA3.
        assert (XAXA4: forall r, In r (reg1 :: regs') -> trs'' # r = Vtrue \/ trs'' # r = Vfalse).
        { intros. destruct H21; eauto. subst r; eauto. }
        assert (AC': forall v, In v tvals' -> match v with | inl v0 => exists (b : block) (ofs : int), v0 = Vptr b ofs | inr (v0, v') => exists (b : block) (ofs ofs' : int), v0 = Vptr b ofs /\ v' = Vptr b ofs' end).
        { clear -LA FFFFF. intros; induction LA.
          - destruct (Int.eq_dec base bound).
            + destruct H.
              * subst v. subst base. eapply pop_is_in in H0. eapply FFFFF in H0.
                destruct H0 as [b H0]. subst sp. simpl; eauto.
              * eapply IHLA; eauto.
            + destruct H.
              * subst v. eapply pop_is_in in H0. eapply FFFFF in H0.
                destruct H0 as [b H0]. subst sp. simpl; eauto.
              * eapply IHLA; eauto.
          - destruct H.
            + destruct (Int.eq_dec base bound); subst v; eauto.
            + eapply IHLA; eauto.
          - inv H. }
        assert (XAXAXA: forall r, In r regs -> match r with | inl r0 => trs'' # r0 = Vtrue \/ trs'' # r0 = Vfalse | inr (r0, _) => trs'' # r0 = Vtrue \/ trs'' # r0 = Vfalse end).
        { intros. rewrite <- H6 in XAXA4. destruct r.
          - eapply XAXA4; auto. eapply in_map_iff. exists (inl r); eauto.
          - destruct p. eapply XAXA4. eapply in_map_iff. exists (inr (r, r0)); eauto. }
        generalize (eval_condition_are_bools' _ _ _ _ _ _ HF AC' XAXAXA). intros UUU.
        assert (XY: forall r, In r (map (fun r => match r with | inl r => r | inr r => fst r end) regs) -> trs''#r = Vtrue \/ trs''#r = Vfalse).
        { clear -ZA HF AC' UUU. intros. induction HF.
          - simpl in H. inv H.
          - simpl in H. destruct a1.
            + destruct H.
              * subst r0. unfold match_reg_val' in H0.
                destruct b1; try (inv H0; fail).
                rewrite H0. destruct (UUU _ (in_eq _ _)); rewrite H; auto.
              * eapply IHHF; eauto. intros; eapply AC'; right; auto.
                intros; eapply UUU; right; auto.
            + destruct p. destruct H.
              * simpl in H; subst r0. unfold match_reg_val' in H0. destruct b1; try (inv H0; fail).
                destruct p. rewrite H0. destruct (UUU _ (in_eq _ _)); rewrite H; auto.
              * eapply IHHF; eauto. intros; eapply AC'; right; auto.
                intros; eapply UUU; right; auto. }
        generalize (not_is_trivial_annotation_implies _ _ _ _ HOH). intros HOH'.
        assert (HOH'': exists xx yy, snd alpha = xx::yy).
        { destruct (snd alpha); try congruence; eauto. }
        destruct HOH'' as [xx [yy HOH'']]. rewrite HOH'' in H4.
        generalize (max_reg_function_use' _ _ _ H0); simpl; intros VV.
        assert (I0: forall r, In r args -> r <> reg0).
        { intros. eapply VV in H21. assert (Plt r reg0) by xomega. eapply Plt_ne; eauto. }
        assert (I1: list_disjoint (fold_right
            (fun (x : Registers.reg + Registers.reg * Registers.reg) (acc : list Registers.reg) =>
             match x with
             | inl r => r :: acc
             | inr (r, r') => r :: r' :: acc
             end) nil regs) args).
        { unfold list_disjoint; intros. eapply VV in H22.
          assert (Plt (max_reg_function f) x); try (eapply not_eq_sym; eapply Plt_ne; xomega; fail).
          clear -H21 AA. induction regs. simpl in H21; inv H21. simpl in H21. destruct a.
          destruct H21. subst x. eapply (AA _ (in_eq _ _)). eapply IHregs; eauto. intros; eapply AA; right; auto.
          destruct p. destruct H21. subst x. eapply (AA _ (in_eq _ _)). destruct H. subst x. eapply (AA _ (in_eq _ _)).
          eapply IHregs; eauto. intros; eapply AA; right; auto. }
        assert (I2: list_disjoint ((fold_right
            (fun (x : Registers.reg + Registers.reg * Registers.reg) (acc : list Registers.reg) =>
             match x with
             | inl r => r :: acc
             | inr (r, r') => r :: r' :: acc
             end) nil regs)++regs2) args).
        { unfold list_disjoint; intros. eapply in_app in H21. destruct H21.
          - eapply I1; auto.
          - eapply VV in H22.
            eapply AA' in H21. assert (Plt y x) by xomega. apply not_eq_sym. eapply Plt_ne; eauto. }
        rewrite H6 in XY. generalize (XY reg1 (in_eq _ _)). clear XY. intros [XY | XY].
        { generalize (list_forall2_not_in_2 _ _ _ _ _ _ reg0 Vtrue HF H18). intros HH.
          assert (AD: forall r, In r (reg1::regs') -> (trs''#reg0 <- Vtrue)#r = Vtrue \/ (trs''#reg0 <- Vtrue)#r = Vfalse).
          { clear -H6 HH AC' UUU. intros. rewrite <- H6 in H. clear H6. induction HH.
            - simpl in H. inv H.
            - simpl in H. destruct H.
              + destruct a1.
                * subst r0. unfold match_reg_val' in H0. destruct b1; inv H0.
                  rewrite H1. unfold eval_condition in UUU. destruct (UUU _ (in_eq _ _)); rewrite H; auto.
                * destruct p. simpl in H. subst.
                  unfold match_reg_val' in H0. destruct b1; try inv H0. destruct p; rewrite H0.
                  eapply (UUU _ (in_eq _ _)).
              + eapply IHHH; eauto.
                intros; eapply AC'; right; eauto.
                intros; eapply UUU; right; eauto. }
          assert (AF: trs''#reg0 <- (Vtrue)#reg0 = Vtrue) by (rewrite PMap.gss; reflexivity).
          assert (FU: ~ In reg0 regs').
          { intro. generalize (in_cons reg1 _ _ H21). intros FUU.
            rewrite <- H6 in FUU. eapply H18. eapply in_map_iff in FUU. destruct FUU as [x [FUU FUU2]].
            clear -FUU FUU2. induction regs.
            - inv FUU2.
            - destruct FUU2.
              + subst a; destruct x; simpl. left; auto.
                destruct p; left; auto.
              + destruct a; simpl; try (destruct p); right; auto. right; eapply IHregs; eauto. }
          generalize (tr_or_regs_true tstk tf tm regs' (Psucc pc4) reg0 pc5 pcs3 tsp0 (trs''#reg0 <- Vtrue) H8 (fun r H => AD r (in_cons _ _ _ H)) FU AF). intros [trs''' [HI [HJ HK]]].
          eexists; split.
          - eapply plus_left.
            + eapply exec_Inop; eauto.
            + eapply star_step.
              * eapply exec_Iop; eauto.
                destruct addr; simpl; eauto.
                destruct (Int.eq_dec i Int.zero); simpl; eauto.
                simpl in XYY. subst i. destruct trs##args; auto.
                destruct l; auto. rewrite <- XYY. inv XYY.
                unfold Mem.loadv in ZA. destruct v0; simpl in ZA; inv ZA.
                simpl; auto. simpl; rewrite Int.add_zero. reflexivity.
              * eapply star_trans.
                eapply HA. eapply star_trans. eapply HE.
                eapply star_step. eapply exec_Iop; eauto.
                simpl; eauto. eapply star_trans.
                rewrite XY. eapply HI.
                eapply star_step. eapply exec_Icond; eauto.
                simpl; rewrite HJ; simpl. rewrite Int.eq_false; simpl; auto.
                eapply Int.one_not_zero.
                simpl. eapply star_step.
                eapply exec_Iload; eauto. rewrite <- XYY.
                erewrite (regs_rewrite_one _ _ _ _ reg0 HK I0); eauto.
                erewrite regs_rewrite_one'; eauto.
                erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HG r X)) I1).
                erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HD r X)) I2).
                erewrite regs_rewrite_one'; eauto.
                eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto.
              * eauto.
            + eauto.
          - econstructor; eauto.
            + unfold regs_agree; intros.
              destruct (plt (max_reg_function f) r).
              * right; split; auto.
                generalize (max_reg_function_def _ _ _ dst H0 eq_refl). intros.
            rewrite PMap.gso; try xomega. rewrite UNDEF; auto.
          * left; split; try xomega. destruct (peq dst r).
            { subst r; repeat rewrite PMap.gss. eauto. }
            { repeat rewrite PMap.gso; auto. destruct (peq r reg0); try congruence.
              rewrite HK; auto. rewrite PMap.gso; auto.
              rewrite <- HG; auto. generalize (HC r).
              intros [[X Y] | [X Y]]; try xomega; auto.
              intro. eapply n. clear -H21 AA. induction regs. simpl in H21; inv H21. simpl in H21. destruct a.
              destruct H21. subst r. eapply (AA _ (in_eq _ _)). eapply IHregs; eauto. intros; eapply AA; right; auto.
              destruct p. destruct H21. subst r. eapply (AA _ (in_eq _ _)). destruct H. subst r. eapply (AA _ (in_eq _ _)).
              eapply IHregs; eauto. intros; eapply AA; right; auto. }
            + intros. generalize (STEP s0 H21). intros [t X].
              exists (t ** E0). eapply star_right; eauto.
              eapply exec_Iload_block'; eauto.
            + intros. generalize (STEP' s0 H21). intros [t X].
              exists (t ** E0). eapply star_trans; eauto.
              eapply star_step.
              * eapply exec_Inop; eauto.
              * eapply star_step.
                { eapply exec_Iop; eauto.
                  destruct addr; simpl; eauto.
                  destruct (Int.eq_dec i Int.zero); simpl; eauto.
                  simpl in XYY. subst i. destruct trs##args; auto.
                  destruct l; auto. rewrite <- XYY. inv XYY.
                  unfold Mem.loadv in ZA. destruct v0; simpl in ZA; inv ZA.
                  simpl. rewrite Int.add_zero. reflexivity. }
                { eapply star_trans.
                  eapply HA. eapply star_trans. eapply HE.
                  eapply star_step. eapply exec_Iop; eauto.
                  simpl; eauto. eapply star_trans.
                  rewrite XY. eapply HI.
                  eapply star_step. eapply exec_Icond; eauto.
                  simpl; rewrite HJ; simpl. rewrite Int.eq_false; simpl; auto.
                  eapply Int.one_not_zero.
                  simpl. eapply star_step.
                  eapply exec_Iload; eauto. rewrite <- XYY.
                  erewrite (regs_rewrite_one _ _ _ _ reg0 HK I0); eauto.
                  erewrite regs_rewrite_one'; eauto.
                  erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HG r X)) I1).
                  erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HD r X)) I2).
                  erewrite regs_rewrite_one'; eauto.
                  eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto. }
                { eauto. }
              * eauto.
            + generalize (max_reg_function_def _ _ _ dst H0 eq_refl). intros.
              rewrite PMap.gso; try xomega. eapply UNDEF; auto. }
        { generalize (list_forall2_not_in_2 _ _ _ _ _ _ reg0 Vfalse HF H18). intros HH.
          assert (AD: forall r, In r (reg1::regs') -> (trs''#reg0 <- Vfalse)#r = Vtrue \/ (trs''#reg0 <- Vfalse)#r = Vfalse).
          { clear -H6 HH AC' UUU. intros. rewrite <- H6 in H. clear H6. induction HH.
            - simpl in H. inv H.
            - simpl in H. destruct H.
              + destruct a1.
                * subst r0. unfold match_reg_val' in H0. destruct b1; inv H0.
                  rewrite H1. unfold eval_condition in UUU. destruct (UUU _ (in_eq _ _)); rewrite H; auto.
                * destruct p. simpl in H. subst.
                  unfold match_reg_val' in H0. destruct b1; try inv H0. destruct p; rewrite H0.
                  eapply (UUU _ (in_eq _ _)).
              + eapply IHHH; eauto.
                intros; eapply AC'; right; eauto.
                intros; eapply UUU; right; eauto. }
          assert (AF: trs''#reg0 <- (Vfalse)#reg0 = Vfalse).
          { rewrite PMap.gss; reflexivity. }
          assert (FU: ~ In reg0 regs').
          { intro. generalize (in_cons reg1 _ _ H21). intros FUU.
            rewrite <- H6 in FUU. eapply H18. eapply in_map_iff in FUU. destruct FUU as [x [FUU FUU2]].
            clear -FUU FUU2. induction regs.
            - inv FUU2.
            - destruct FUU2.
              + subst a; destruct x; simpl. left; auto.
                destruct p; left; auto.
              + destruct a; simpl; try (destruct p); right; auto. right; eapply IHregs; eauto. }
          assert (AE': exists r, In r regs' /\ (trs''#reg0 <- Vfalse)#r = Vtrue).
          { destruct (Classical_Prop.classic (exists r, In r regs' /\ (trs''#reg0 <- Vfalse)#r = Vtrue)); auto.
            generalize (Classical_Pred_Type.not_ex_all_not _ _ H21). intros Hall.
            exploit tr_or_regs_false; eauto. intros. destruct (AD _ (in_cons _ _ _ H22)); auto.
            exfalso. eapply Hall; split; eauto. intros [trs''' [Hstar [Hfalse Htrs]]].
            inv H11.
            assert (exists t, program_behaves (semantics tprog) (Goes_wrong t)).
            + destruct init_state_exists' as [s0 Hinit].
              generalize (STEP' _ Hinit). intros [t Hstep].
              eexists. econstructor; eauto.
              econstructor. eapply star_trans; eauto.
              eapply star_step. eapply exec_Inop; eauto.
              eapply star_step. eapply exec_Iop; eauto.
              destruct addr; simpl; eauto.
              destruct (Int.eq_dec i Int.zero); simpl; eauto.
              simpl in XYY. subst i. destruct trs##args; auto.
              destruct l; auto. rewrite <- XYY. inv XYY.
              unfold Mem.loadv in ZA. destruct v0; simpl in ZA; inv ZA.
              simpl; auto. simpl; rewrite Int.add_zero. reflexivity.
              eapply star_trans. eapply HA.
              eapply star_trans. eapply HE.
              eapply star_step. eapply exec_Iop; eauto.
              simpl. eauto. eapply star_trans. rewrite XY. eapply Hstar.
              eapply star_step. eapply exec_Icond; eauto. simpl. rewrite Hfalse. simpl.
              rewrite Int.eq_true. simpl. eauto. simpl.
              eapply star_step. eapply exec_Iop; eauto. simpl. eauto.
              eapply star_step. eapply exec_Iop; eauto. simpl. eauto.
              eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
              red; unfold not; intros. inv H11; try congruence.
              rewrite H34 in H24; inv H24.
              simpl in H35. rewrite PMap.gss in H35. rewrite PMap.gso in H35; eauto.
              rewrite PMap.gss in H35. simpl in H35. rewrite Int.eq_true in H35; simpl in H35. inv H35.
              unfold not; intros. inv H11.
            + destruct H11. eapply DEFSAFE in H11; inv H11. }
          generalize (tr_or_regs_correct tstk tf tm _ (Psucc pc4) reg0 pc5 pcs3 tsp0 (trs'' # reg0 <- (Vint Int.zero)) H8 (fun r H => AD r (in_cons _ _ _ H)) FU AE' (or_intror AF)). intros [trs''' [HI [HJ HK]]].
          eexists; split.
          - eapply plus_left.
            + eapply exec_Inop; eauto.
            + eapply star_step.
              * eapply exec_Iop; eauto.
                destruct addr; simpl; eauto.
                destruct (Int.eq_dec i Int.zero); simpl; eauto.
                simpl in XYY. subst i. destruct trs##args; auto.
                destruct l; auto. rewrite <- XYY. inv XYY.
                unfold Mem.loadv in ZA. destruct v0; simpl in ZA; inv ZA.
                simpl. rewrite Int.add_zero. reflexivity.
              * eapply star_trans.
                eapply HA. eapply star_trans. eapply HE.
                eapply star_step. eapply exec_Iop; eauto.
                simpl; eauto. eapply star_trans.
                rewrite XY. unfold Vfalse. eapply HI.
                eapply star_step. eapply exec_Icond; eauto.
                simpl; rewrite HJ; simpl. rewrite Int.eq_false; simpl; auto.
                eapply Int.one_not_zero.
                simpl. eapply star_step.
                eapply exec_Iload; eauto. rewrite <- XYY.
                erewrite (regs_rewrite_one _ _ _ _ reg0 HK I0); eauto.
                erewrite regs_rewrite_one'; eauto.
                erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HG r X)) I1).
                erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HD r X)) I2).
                erewrite regs_rewrite_one'; eauto.
                eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto.
              * eauto.
            + eauto.
          - econstructor; eauto.
            + unfold regs_agree; intros.
              destruct (plt (max_reg_function f) r).
              * right; split; auto.
                generalize (max_reg_function_def _ _ _ dst H0 eq_refl). intros.
                rewrite PMap.gso; try xomega. rewrite UNDEF; auto.
              * left; split; try xomega. destruct (peq dst r).
                { subst r; repeat rewrite PMap.gss. eauto. }
                { repeat rewrite PMap.gso; auto. destruct (peq r reg0); try congruence.
                  rewrite HK; auto. rewrite PMap.gso; auto.
                  rewrite <- HG; auto. generalize (HC r).
                  intros [[X Y] | [X Y]]; try xomega; auto.
                  intro. eapply n. clear -H21 AA. induction regs. simpl in H21; inv H21. simpl in H21. destruct a.
                  destruct H21. subst r. eapply (AA _ (in_eq _ _)). eapply IHregs; eauto. intros; eapply AA; right; auto.
                  destruct p. destruct H21. subst r. eapply (AA _ (in_eq _ _)). destruct H. subst r. eapply (AA _ (in_eq _ _)).
                  eapply IHregs; eauto. intros; eapply AA; right; auto. }
            + intros. generalize (STEP s0 H21). intros [t X].
              exists (t ** E0). eapply star_right; eauto.
              eapply exec_Iload_block'; eauto.
            + intros. generalize (STEP' s0 H21). intros [t X].
              exists (t ** E0). eapply star_trans; eauto.
              eapply star_step.
              * eapply exec_Inop; eauto.
              * eapply star_step.
                { eapply exec_Iop; eauto.
                  destruct addr; simpl; eauto.
                  destruct (Int.eq_dec i Int.zero); simpl; eauto.
                  simpl in XYY. subst i. destruct trs##args; auto.
                  destruct l; auto. rewrite <- XYY. inv XYY.
                  unfold Mem.loadv in ZA. destruct v0; simpl in ZA; inv ZA.
                  simpl. rewrite Int.add_zero. reflexivity. }
                { eapply star_trans.
                  eapply HA. eapply star_trans. eapply HE.
                  eapply star_step. eapply exec_Iop; eauto.
                  simpl; eauto. eapply star_trans.
                  rewrite XY. eapply HI.
                  eapply star_step. eapply exec_Icond; eauto.
                  simpl; rewrite HJ; simpl. rewrite Int.eq_false; simpl; auto.
                  eapply Int.one_not_zero.
                  simpl. eapply star_step.
                  eapply exec_Iload; eauto. rewrite <- XYY.
                  erewrite (regs_rewrite_one _ _ _ _ reg0 HK I0); eauto.
                  erewrite regs_rewrite_one'; eauto.
                  erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HG r X)) I1).
                  erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HD r X)) I2).
                  erewrite regs_rewrite_one'; eauto.
                  eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto. }
                { eauto. }
              * eauto.
            + generalize (max_reg_function_def _ _ _ dst H0 eq_refl). intros.
              rewrite PMap.gso; try xomega. eapply UNDEF; auto. } }
      { assert (NA': ~ In reg0 regs').
        { intro. generalize (in_cons reg1 _ _ H20). intros FUU.
          rewrite <- H6 in FUU. eapply H18. eapply in_map_iff in FUU. destruct FUU as [x [FUU FUU2]].
          clear -FUU FUU2. induction regs.
          - inv FUU2.
          - destruct FUU2.
            + subst a; destruct x; simpl. left; auto.
              destruct p; left; auto.
            + destruct a; simpl; try (destruct p); right; auto. right; eapply IHregs; eauto. }
        assert (CN: trs'' # reg0 <- (trs'' # reg1) # reg0 = Vundef) by (rewrite PMap.gss; eauto).
        generalize (tr_or_regs_undef tstk _ tm _ _ _ _ _ tsp0 _ H8 NA' CN). intros [trs''' [Hstar [Hundef Htrs''']]].
        inv H11.
        assert (exists t, program_behaves (semantics tprog) (Goes_wrong t)).
        - destruct init_state_exists' as [s0 Hinit].
          generalize (STEP' _ Hinit). intros [t Hstep].
          eexists. econstructor; eauto.
          econstructor. eapply star_trans; eauto.
          eapply star_step. eapply exec_Inop; eauto.
          eapply star_step. eapply exec_Iop; eauto.
          destruct addr; simpl; eauto.
          destruct (Int.eq_dec i Int.zero); simpl; eauto.
          simpl in XYY. subst i. destruct trs##args; auto.
          destruct l; auto. rewrite <- XYY. inv XYY.
          unfold Mem.loadv in ZA. destruct v0; simpl in ZA; inv ZA.
          simpl; auto. simpl; rewrite Int.add_zero. reflexivity.
          eapply star_trans. eapply HA.
          eapply star_trans. eapply HE.
          eapply star_step. eapply exec_Iop; eauto.
          simpl. eauto. eapply star_trans. eapply Hstar.
          eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto.
          red; unfold not; intros. inv H11; try congruence.
          rewrite H32 in H9; inv H9. simpl in H33. rewrite Hundef in H33. simpl in H33.
          inv H33.
          unfold not; intros. inv H11.
        - destruct H11. eapply DEFSAFE in H11; inv H11. } }
    inv H14.
    assert (SPINJ': Val.inject j (Vptr sp0 Int.zero) (Vptr tsp0 Int.zero)) by (econstructor; eauto).
    generalize (max_reg_function_use' _ _ _ H0). simpl; intros XXXX.
    generalize (regs_agree_inject_list _ _ _ _ _ XXXX RES). intros YYYY.
    exploit (eval_addressing_inj ge tge); eauto.
    { intros. eapply symbol_address_inject; eauto. intros; eapply GINJ_implies; eauto. } intros [ta [XYY YYX]].
    generalize (Mem.loadv_inject j m tm kappa a ta v MINJ H2 YYX). intros [tv [ZA ZB]].
    assert (regs_agree j (max_reg_function f) rs (trs # reg0 <- ta)).
    { unfold regs_agree. intros; destruct (plt (max_reg_function f) r).
      - right; split; auto.
        rewrite UNDEF; eauto.
      - left; split; try xomega.
        generalize (RES r). intros [[D E] | D]; try xomega.
        rewrite PMap.gso; eauto. xomega. }
    exploit tr_regs_annot_inv; eauto.
    { intros. destruct H14; eauto.
      eapply match_stackframes_sps_are_ptrs; eauto. }
    { intros. eapply STEP' in H14. destruct H14.
      eexists. eapply star_trans; eauto.
      eapply star_two. eapply exec_Inop; eauto.
      eapply exec_Iop; eauto. destruct addr; simpl; eauto.
      destruct (Int.eq_dec i Int.zero); simpl; eauto. subst i.
      simpl in XYY. destruct trs##args; inv XYY.
      destruct l; auto. destruct ta; simpl in ZA; inv ZA.
      destruct v0; simpl in H21; inv H21. simpl. rewrite Int.add_zero; auto.
      eauto. } intros [tvals ZYX].
    assert (FFFFF: (forall sp : val, In sp (Vptr tsp0 Int.zero :: map (fun s : stackframe => match s with | Stackframe _ _ tsp _ _ => tsp end) tstk) -> exists b : block, sp = Vptr b Int.zero)).
    { intros. destruct H14. inv H14; eauto. eapply match_stackframes_sps_are_ptrs; eauto. }
    assert (GGGGG: (forall sp : val, In sp (Vptr sp0 Int.zero :: map (fun s : stackframe => match s with | Stackframe _ _ tsp _ _ => tsp end) stk) -> exists b : block, sp = Vptr b Int.zero)).
    { intros. destruct H14. inv H14; eauto. eapply match_stackframes_sps_are_ptrs'; eauto. }
    generalize (tr_regs_annot_correct _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ tm FFFFF H17 H4 ZYX H6 UNDEF SHADOW). intros [trs' [HA [HB [HC HD]]]].
    generalize (tr_regs_annot_regs_plt prog STK _ _ _ _ _ _ _ _ _ H4). intros AA.
    generalize (tr_regs_annot_regs'_plt prog STK _ _ _ _ _ _ _ _ _ H4). intros AA'.
    generalize (tr_regs_annot_regs_norepet prog STK _ _ _ _ _ _ _ _ _ H4). intros AB.
    generalize (tr_cmp_regs_correct _ tstk (Vptr tsp0 Int.zero) f tf reg0 _ pc3 pc4 pcs2 tm rs trs' tvals H5 H18 HB HC AA UNDEF AB). intros [trs'' [HE [HF HG]]].
    generalize (addr_of_annotations_are_ptrs _ _ _ _ _ ZYX FFFFF). intros AC.
    rewrite <- HD in HF; auto. rewrite PMap.gss in HF. 2: eapply not_in_app; split; auto.
    generalize (regs_are_unknown _ _ _ _ _ _ _ ZA HF AC). intros XAXA.
    assert (XAXA1: (trs''#reg1 = Vtrue \/ trs''#reg1 = Vfalse) \/ trs''#reg1 = Vundef) by (eapply or_assoc; eapply XAXA; eapply in_eq).
    assert (XAXA2: forall r, In r regs' -> trs'' # r = Vtrue \/ trs'' # r = Vfalse \/ trs'' # r = Vundef) by (intros; eapply XAXA; eapply in_cons; eauto).
    destruct XAXA1 as [XAXA1 | XAXA1].
    { destruct (Classical_Prop.classic (exists r, trs'' # r = Vundef /\ In r regs')).
      - eapply not_in_cons in H18. destruct H18 as [NA NA'].
        assert (CN1: trs'' # reg0 <- (trs'' # reg1) # reg0 = Vtrue \/ trs'' # reg0 <- (trs'' # reg1) # reg0 = Vfalse) by (rewrite PMap.gss; eauto).
        assert (CN2: forall r, In r regs' -> trs'' # reg0 <- (trs'' # reg1) # r = Vtrue \/ trs'' # reg0 <- (trs'' # reg1) # r = Vfalse \/ trs'' # reg0 <- (trs'' # reg1) # r = Vundef).
        { intros; rewrite ! PMap.gso. eapply XAXA2. eauto. unfold not; intros. subst r; eapply NA'; eauto. }
        assert (CN3: exists r, (trs'' # reg0 <- (trs'' # reg1)) # r = Vundef /\ In r regs').
        { destruct H14. eexists. rewrite PMap.gso. eapply H14. unfold not; intros; subst x. destruct H14; eapply NA'; eauto. }
        generalize (tr_or_regs_undef' tstk _ tm _ _ _ _ _ tsp0 _ H8 NA' CN2 CN3 CN1). intros [trs''' [Hstar [Hundef Htrs''']]].
        assert (exists t, program_behaves (semantics tprog) (Goes_wrong t)).
        + destruct init_state_exists' as [s0 Hinit].
          generalize (STEP' _ Hinit). intros [t Hstep].
          eexists. econstructor; eauto.
          econstructor. eapply star_trans; eauto.
          eapply star_step. eapply exec_Inop; eauto.
          eapply star_step. eapply exec_Iop; eauto.
          destruct addr; simpl; eauto.
          destruct (Int.eq_dec i Int.zero); simpl; eauto.
          simpl in XYY. subst i. destruct trs##args; auto.
          destruct l; auto. rewrite <- XYY. inv XYY.
          unfold Mem.loadv in ZA. destruct v0; simpl in ZA; inv ZA.
          simpl; auto. simpl; rewrite Int.add_zero. reflexivity.
          eapply star_trans. eapply HA.
          eapply star_trans. eapply HE.
          eapply star_step. eapply exec_Iop; eauto.
          simpl. eauto. eapply star_trans. eapply Hstar.
          eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto.
          red; unfold not; intros. inv H18; try congruence.
          rewrite H28 in H9; inv H9. simpl in H29. rewrite Hundef in H29. simpl in H29.
          inv H29.
          unfold not; intros. inv H18.
        + destruct H18. eapply DEFSAFE in H18; inv H18.
      - generalize (proj1 (not_undef _ _ XAXA2) H14). intros XAXA3.
        assert (XAXA4: forall r, In r (reg1 :: regs') -> trs'' # r = Vtrue \/ trs'' # r = Vfalse).
        { intros. destruct H20; eauto. subst r; eauto. }
        generalize (eval_condition_are_bools _ _ _ _ _ HF AC XAXA4). intros UUU.
        generalize (regs_are_bools _ _ _ _ _ _ _ ZA HF AC UUU). intros XY.
        generalize (not_is_trivial_annotation_implies _ _ _ _ HOH). intros HOH'.
        assert (HOH'': exists xx yy, snd alpha = xx::yy).
        { destruct (snd alpha); try congruence; eauto. }
        destruct HOH'' as [xx [yy HOH'']]. rewrite HOH'' in H4.
        generalize (max_reg_function_use' _ _ _ H0); simpl; intros VV.
        assert (I0: forall r, In r args -> r <> reg0).
        { intros. eapply VV in H20. assert (Plt r reg0) by xomega. eapply Plt_ne; eauto. }
        assert (I1: list_disjoint (reg1::regs') args).
        { unfold list_disjoint; intros. eapply VV in H21. eapply AA in H20.
          assert (Plt y x) by xomega. apply not_eq_sym. eapply Plt_ne; eauto. }
        assert (I2: list_disjoint ((reg1::regs')++regs2) args).
        { unfold list_disjoint; intros. eapply VV in H21. eapply in_app in H20. destruct H20.
          - eapply AA in H20. assert (Plt y x) by xomega. apply not_eq_sym. eapply Plt_ne; eauto.
          - eapply AA' in H20. assert (Plt y x) by xomega. apply not_eq_sym. eapply Plt_ne; eauto. }
        generalize (XY reg1 (in_eq _ _)). clear XY. intros [XY | XY].
        { generalize (RTLdefgenspec.list_forall2_not_in' _ _ _ _ _ reg0 Vtrue HF H18). intros HH.
          generalize (regs_are_bools _ _ _ _ _ _ _ ZA HH AC UUU). intros AD.
          assert (AF: trs''#reg0 <- (Vtrue)#reg0 = Vtrue) by (rewrite PMap.gss; reflexivity).
          apply not_in_cons in H18. destruct H18.
          generalize (tr_or_regs_true tstk tf tm regs' (Psucc pc4) reg0 pc5 pcs3 tsp0 (trs''#reg0 <- Vtrue) H8 (fun r H => AD r (in_cons _ _ _ H)) H20 AF). intros [trs''' [HI [HJ HK]]].
          eexists; split.
          - eapply plus_left.
            + eapply exec_Inop; eauto.
            + eapply star_step.
              * eapply exec_Iop; eauto.
            destruct addr; simpl; eauto.
            destruct (Int.eq_dec i Int.zero); simpl; eauto.
            simpl in XYY. subst i. destruct trs##args; auto.
            destruct l; auto. rewrite <- XYY. inv XYY.
            unfold Mem.loadv in ZA. destruct v0; simpl in ZA; inv ZA.
            simpl; auto. simpl; rewrite Int.add_zero. reflexivity.
              * eapply star_trans.
                eapply HA. eapply star_trans. eapply HE.
                eapply star_step. eapply exec_Iop; eauto.
                simpl; eauto. eapply star_trans.
                rewrite XY. eapply HI.
                eapply star_step. eapply exec_Icond; eauto.
                simpl; rewrite HJ; simpl. rewrite Int.eq_false; simpl; auto.
                eapply Int.one_not_zero.
                simpl. eapply star_step.
                eapply exec_Iload; eauto. rewrite <- XYY.
                erewrite (regs_rewrite_one _ _ _ _ reg0 HK I0); eauto.
                erewrite regs_rewrite_one'; eauto.
                erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HG r X)) I1).
                erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HD r X)) I2).
                erewrite regs_rewrite_one'; eauto.
                eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto.
              * eauto.
            + eauto.
          - econstructor; eauto.
            + unfold regs_agree; intros.
              destruct (plt (max_reg_function f) r).
              * right; split; auto.
                generalize (max_reg_function_def _ _ _ dst H0 eq_refl). intros.
            rewrite PMap.gso; try xomega. rewrite UNDEF; auto.
          * left; split; try xomega. destruct (peq dst r).
            { subst r; repeat rewrite PMap.gss. eauto. }
            { repeat rewrite PMap.gso; auto. destruct (peq r reg0); try congruence.
              rewrite HK; auto. rewrite PMap.gso; auto.
              rewrite <- HG; auto. generalize (HC r).
              intros [[X Y] | [X Y]]; try xomega; auto. }
            + intros. generalize (STEP s0 H21). intros [t X].
              exists (t ** E0). eapply star_right; eauto.
              eapply exec_Iload_block'; eauto.
            + intros. generalize (STEP' s0 H21). intros [t X].
              exists (t ** E0). eapply star_trans; eauto.
              eapply star_step.
              * eapply exec_Inop; eauto.
              * eapply star_step.
                { eapply exec_Iop; eauto.
                  destruct addr; simpl; eauto.
                  destruct (Int.eq_dec i Int.zero); simpl; eauto.
                  simpl in XYY. subst i. destruct trs##args; auto.
                  destruct l; auto. rewrite <- XYY. inv XYY.
                  unfold Mem.loadv in ZA. destruct v0; simpl in ZA; inv ZA.
                  simpl. rewrite Int.add_zero. reflexivity. }
                { eapply star_trans.
                  eapply HA. eapply star_trans. eapply HE.
                  eapply star_step. eapply exec_Iop; eauto.
                  simpl; eauto. eapply star_trans.
                  rewrite XY. eapply HI.
                  eapply star_step. eapply exec_Icond; eauto.
                  simpl; rewrite HJ; simpl. rewrite Int.eq_false; simpl; auto.
                  eapply Int.one_not_zero.
                  simpl. eapply star_step.
                  eapply exec_Iload; eauto. rewrite <- XYY.
                  erewrite (regs_rewrite_one _ _ _ _ reg0 HK I0); eauto.
                  erewrite regs_rewrite_one'; eauto.
                  erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HG r X)) I1).
                  erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HD r X)) I2).
                  erewrite regs_rewrite_one'; eauto.
                  eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto. }
                { eauto. }
              * eauto.
            + generalize (max_reg_function_def _ _ _ dst H0 eq_refl). intros.
              rewrite PMap.gso; try xomega. eapply UNDEF; auto. }
        { generalize (RTLdefgenspec.list_forall2_not_in' _ _ _ _ _ reg0 Vfalse HF H18). intros HH.
          generalize (regs_are_bools _ _ _ _ _ _ _ ZA HH AC UUU). intros AD.
          destruct (Classical_Prop.classic (exists r, In r (reg1::regs') /\ (trs''#reg0 <- Vfalse)#r = Vtrue)).
          { rename H20 into AE.
            assert (AF: trs''#reg0 <- (Vfalse)#reg0 = Vfalse).
            { rewrite PMap.gss; reflexivity. }
            apply not_in_cons in H18. destruct H18.
            assert (AE': exists r, In r regs' /\ (trs''#reg0 <- Vfalse)#r = Vtrue).
            { destruct AE as [r [AE1 AE2]]. simpl in AE1. destruct AE1 as [AE1 | AE1].
              - subst r. rewrite PMap.gso in AE2; try congruence. rewrite XY in AE2. inv AE2.
              - exists r; split; assumption. }
            generalize (tr_or_regs_correct tstk tf tm _ (Psucc pc4) reg0 pc5 pcs3 tsp0 (trs'' # reg0 <- (Vint Int.zero)) H8 (fun r H => AD r (in_cons _ _ _ H)) H20 AE' (or_intror AF)). intros [trs''' [HI [HJ HK]]].
            eexists; split.
            - eapply plus_left.
              + eapply exec_Inop; eauto.
              + eapply star_step.
                * eapply exec_Iop; eauto.
                  destruct addr; simpl; eauto.
                  destruct (Int.eq_dec i Int.zero); simpl; eauto.
                  simpl in XYY. subst i. destruct trs##args; auto.
                  destruct l; auto. rewrite <- XYY. inv XYY.
                  unfold Mem.loadv in ZA. destruct v0; simpl in ZA; inv ZA.
                  simpl. rewrite Int.add_zero. reflexivity.
                * eapply star_trans.
                  eapply HA. eapply star_trans. eapply HE.
                  eapply star_step. eapply exec_Iop; eauto.
                  simpl; eauto. eapply star_trans.
                  rewrite XY. unfold Vfalse. eapply HI.
                  eapply star_step. eapply exec_Icond; eauto.
                  simpl; rewrite HJ; simpl. rewrite Int.eq_false; simpl; auto.
                  eapply Int.one_not_zero.
                  simpl. eapply star_step.
                  eapply exec_Iload; eauto. rewrite <- XYY.
                  erewrite (regs_rewrite_one _ _ _ _ reg0 HK I0); eauto.
                  erewrite regs_rewrite_one'; eauto.
                  erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HG r X)) I1).
                  erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HD r X)) I2).
                  erewrite regs_rewrite_one'; eauto.
                  eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto.
                * eauto.
              + eauto.
            - econstructor; eauto.
              + unfold regs_agree; intros.
                destruct (plt (max_reg_function f) r).
                * right; split; auto.
                  generalize (max_reg_function_def _ _ _ dst H0 eq_refl). intros.
                  rewrite PMap.gso; try xomega. rewrite UNDEF; auto.
                * left; split; try xomega. destruct (peq dst r).
                  { subst r; repeat rewrite PMap.gss. eauto. }
                  { repeat rewrite PMap.gso; auto. destruct (peq r reg0); try congruence.
                    rewrite HK; auto. rewrite PMap.gso; auto.
                    rewrite <- HG; auto. generalize (HC r).
                    intros [[X Y] | [X Y]]; try xomega; auto. }
              + intros. generalize (STEP s0 H21). intros [t X].
                exists (t ** E0). eapply star_right; eauto.
                eapply exec_Iload_block'; eauto.
              + intros. generalize (STEP' s0 H21). intros [t X].
                exists (t ** E0). eapply star_trans; eauto.
                eapply star_step.
                * eapply exec_Inop; eauto.
                * eapply star_step.
                  { eapply exec_Iop; eauto.
                    destruct addr; simpl; eauto.
                    destruct (Int.eq_dec i Int.zero); simpl; eauto.
                    simpl in XYY. subst i. destruct trs##args; auto.
                    destruct l; auto. rewrite <- XYY. inv XYY.
                    unfold Mem.loadv in ZA. destruct v0; simpl in ZA; inv ZA.
                    simpl. rewrite Int.add_zero. reflexivity. }
                  { eapply star_trans.
                    eapply HA. eapply star_trans. eapply HE.
                    eapply star_step. eapply exec_Iop; eauto.
                    simpl; eauto. eapply star_trans.
                    rewrite XY. eapply HI.
                    eapply star_step. eapply exec_Icond; eauto.
                    simpl; rewrite HJ; simpl. rewrite Int.eq_false; simpl; auto.
                    eapply Int.one_not_zero.
                    simpl. eapply star_step.
                    eapply exec_Iload; eauto. rewrite <- XYY.
                    erewrite (regs_rewrite_one _ _ _ _ reg0 HK I0); eauto.
                    erewrite regs_rewrite_one'; eauto.
                    erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HG r X)) I1).
                    erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HD r X)) I2).
                    erewrite regs_rewrite_one'; eauto.
                    eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto. }
                  { eauto. }
                * eauto.
              + generalize (max_reg_function_def _ _ _ dst H0 eq_refl). intros.
                rewrite PMap.gso; try xomega. eapply UNDEF; auto. }
          { rename H20 into AE. generalize (Classical_Pred_Type.not_ex_all_not _ _ AE). intros AE'.
            assert (Hall: forall r, In r (reg1::regs') -> (trs''#reg0 <- Vfalse)#r = Vfalse).
            { intros. destruct (AD _ H20); auto.
              exfalso; eapply AE'; split; eauto. }
            exploit tr_or_regs_false; eauto. eapply not_in_cons in H18. destruct H18; auto.
            intros; eapply Hall; right; auto. eapply PMap.gss.
            intros [trs''' [Hstar [Hfalse Htrs''']]].
            assert (exists t, program_behaves (semantics tprog) (Goes_wrong t)).
            - inv H11.
              destruct init_state_exists' as [s0 Hinit].
              generalize (STEP' _ Hinit). intros [t Hstep].
              eexists. econstructor; eauto.
              econstructor. eapply star_trans; eauto.
              eapply star_step. eapply exec_Inop; eauto.
              eapply star_step. eapply exec_Iop; eauto.
              destruct addr; simpl; eauto.
              destruct (Int.eq_dec i Int.zero); simpl; eauto.
              simpl in XYY. subst i. destruct trs##args; auto.
              destruct l; auto. rewrite <- XYY. inv XYY.
              unfold Mem.loadv in ZA. destruct v0; simpl in ZA; inv ZA.
              simpl; auto. simpl; rewrite Int.add_zero. reflexivity.
              eapply star_trans. eapply HA.
              eapply star_trans. eapply HE.
              eapply star_step. eapply exec_Iop; eauto.
              simpl. eauto. eapply star_trans. rewrite XY.
              eapply Hstar. eapply star_step. eapply exec_Icond; eauto.
              simpl. rewrite Hfalse; simpl. rewrite Int.eq_true. simpl; eauto.
              simpl. eapply star_step. eapply exec_Iop; eauto. simpl. eauto.
              eapply star_one. eapply exec_Iop; eauto. simpl; eauto.
              eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
              red; unfold not; intros. inv H11; try congruence.
              rewrite H32 in H22; inv H22. simpl in H33.
              rewrite PMap.gss in H33; rewrite PMap.gso in H33; auto. rewrite PMap.gss in H33; simpl in H33.
              rewrite Int.eq_true in H33; simpl in H33; inv H33.
              unfold not; intros. inv H11.
            - destruct H20. eapply DEFSAFE in H20; inv H20. } } }
        { eapply not_in_cons in H18. destruct H18 as [NA NA'].
          assert (CN: trs'' # reg0 <- (trs'' # reg1) # reg0 = Vundef) by (rewrite PMap.gss; eauto).
          generalize (tr_or_regs_undef tstk _ tm _ _ _ _ _ tsp0 _ H8 NA' CN). intros [trs''' [Hstar [Hundef Htrs''']]].
          assert (exists t, program_behaves (semantics tprog) (Goes_wrong t)).
          - destruct init_state_exists' as [s0 Hinit].
            generalize (STEP' _ Hinit). intros [t Hstep].
            eexists. econstructor; eauto.
            econstructor. eapply star_trans; eauto.
            eapply star_step. eapply exec_Inop; eauto.
            eapply star_step. eapply exec_Iop; eauto.
            destruct addr; simpl; eauto.
            destruct (Int.eq_dec i Int.zero); simpl; eauto.
            simpl in XYY. subst i. destruct trs##args; auto.
            destruct l; auto. rewrite <- XYY. inv XYY.
            unfold Mem.loadv in ZA. destruct v0; simpl in ZA; inv ZA.
            simpl; auto. simpl; rewrite Int.add_zero. reflexivity.
            eapply star_trans. eapply HA.
            eapply star_trans. eapply HE.
            eapply star_step. eapply exec_Iop; eauto.
            simpl. eauto. eapply star_trans. eapply Hstar.
            eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto.
            red; unfold not; intros. inv H14; try congruence.
            rewrite H27 in H9; inv H9. simpl in H28. rewrite Hundef in H28. simpl in H28.
            inv H28.
            unfold not; intros. inv H14.
          - destruct H14. eapply DEFSAFE in H14; inv H14. }
  Qed.

  Lemma store_checks_are_correct:
    forall stk f sp pc rs m tstk tf tsp tpc trs tm alpha kappa addr args src pc' a m',
      match_states (State stk f sp pc rs m) (State tstk tf tsp tpc trs tm) ->
      (fn_code f)!pc = Some (Istore alpha kappa addr args src pc') ->
      eval_addressing ge sp addr (rs##args) = Some a ->
      Mem.storev kappa m a rs#src = Some m' ->
      annot_sem (Genv.find_symbol ge)
                (sp :: map (fun s : stackframe => match s with
                                               | Stackframe _ _ sp _ _ => sp
                                               end) stk) (snd alpha) a ->
      exists s2', plus step tge (State tstk tf tsp tpc trs tm) E0 s2' /\
             match_states (State stk f sp pc' rs m') s2'.
Proof.
    intros; inv H. generalize (transf_function_spec _ _ _ _ _ _ FUN H0). intros [pcs HA].
    inv HA. case_eq (MoreRTL.is_trivial_annotation prog alpha kappa addr); intros; rename H into HOH; rewrite HOH in H14.
    { assert (SPINJ': Val.inject j (Vptr sp0 Int.zero) (Vptr tsp0 Int.zero)) by (econstructor; eauto).
      generalize (max_reg_function_use' _ _ _ H0). intros XXXX.
      generalize (regs_agree_inject_list _ _ _ _ _ (fun r X => XXXX r (or_intror X)) RES). intros YYYY.
      exploit (eval_addressing_inj ge tge); eauto.
      { intros. eapply symbol_address_inject; eauto. intros; eapply GINJ_implies; eauto. } intros [ta [XYY YYX]].
      assert (ZYF: Val.inject j rs#src trs#src).
      { generalize (max_reg_function_use' _ _ _ H0 src (or_introl eq_refl)). intros.
        generalize (RES src). intros [[A B] | [A B]]; try xomega; eauto. }
      generalize (Mem.storev_mapped_inject j kappa m a rs#src m' tm ta trs#src MINJ H2 YYX ZYF). intros [tm' [ZA ZB]].
      eexists. split.
      - econstructor. eapply exec_Inop; eauto.
        eapply star_step. eapply exec_Istore; eauto.
        eapply star_refl. eauto. eauto.
      - econstructor; eauto.
        + intros. eapply STEP in H; eauto. destruct H as [t Hstep].
          exists (t ** E0); eapply star_right; eauto. eapply exec_Istore_block'; eauto.
        + intros. eapply STEP' in H; eauto. destruct H as [t Hstep].
          exists (t ** E0); eapply star_trans; eauto. eapply star_step. eapply exec_Inop; eauto.
          eapply star_step. eapply exec_Istore; eauto. eapply star_refl.
          eauto. eauto.
        + destruct ta; simpl in ZA; inv ZA.
          erewrite Mem.nextblock_store; eauto.
        + destruct ta; simpl in ZA; inv ZA.
          erewrite Mem.nextblock_store; eauto.
        + red. intros. destruct ta; simpl in ZA; inv ZA.
          eapply Mem.perm_store_1; eauto. eapply STKPERM; eauto.
        + red. intros. destruct ta; simpl in ZA; inv ZA.
          eapply Mem.perm_store_1; eauto. eapply SIZEPERM; eauto.
        + red. intros. destruct ta; simpl in ZA; inv ZA. split.
          * intros. eapply Mem.perm_store_2 in H5; eauto.
            eapply STKRANGE; eauto.
          * intros. eapply Mem.perm_store_1; eauto.
            eapply STKRANGE; eauto.
        + red. intros. destruct ta; simpl in ZA; inv ZA. split.
          * intros. eapply Mem.perm_store_2 in H5; eauto.
            eapply SIZERANGE; eauto.
          * intros. eapply Mem.perm_store_1; eauto.
            eapply SIZERANGE; eauto.
        + destruct a; simpl in H2; inv H2. clear NEXTBLOCK'.
          erewrite Mem.nextblock_store; eauto.
        + destruct ta; simpl in ZA; inv ZA.
          erewrite Mem.nextblock_store; eauto.
        + destruct ta; simpl in ZA; inv ZA.
          destruct a; simpl in H2; inv H2. inv YYX.
          econstructor. intros. inv SHADOW. destruct H as [LO OL]. split.
          * unfold n. rewrite <- LO.
            unfold Mem.loadv. case_eq (Genv.symbol_address tge SIZE Int.zero); intros; eauto.
            eapply Mem.load_store_other; eauto.
            left. unfold not; intros. subst b1. eapply SIZENOTMAPPED; eauto.
            unfold Genv.symbol_address in *. destruct (Genv.find_symbol tge SIZE); inv H; eauto.
          * intros. unfold Mem.loadv. generalize (OL depth sp). intros [OA OB]. split; intros.
            { eapply OA in H. destruct H as [XA XB]. unfold Mem.loadv in XB.
              case_eq (Val.add (Genv.symbol_address tge STK (Int.repr (-4 * Z.of_nat depth))) (Vint (Int.repr (4 * (Z.of_nat n - 1))))); intros; unfold n in H; rewrite H in XB; inv XB. split; eauto.
              eapply Mem.load_store_other; eauto. left.
              simpl in H. unfold Genv.symbol_address in H. case_eq (Genv.find_symbol tge STK); intros; rewrite H2 in H; simpl in H; inv H.
              unfold not; intros. subst b1. eapply STKNOTMAPPED; eauto.
              unfold Genv.symbol_address; rewrite H2; eauto. }
            { destruct H. eapply OB; split; eauto.
              unfold Mem.loadv. rewrite <- H2. simpl.
              case_eq (Val.add (Genv.symbol_address tge STK (Int.repr (-4 * Z.of_nat depth))) (Vint (Int.repr (4 * (Z.of_nat n - 1))))); intros; simpl in H6; rewrite H6; eauto.
              symmetry; eapply Mem.load_store_other; eauto.
              left. unfold not; intros; subst b1. unfold Genv.symbol_address in H6. case_eq (Genv.find_symbol tge STK); intros; rewrite H8 in H6; inv H6. eapply STKNOTMAPPED; eauto.
              unfold Genv.symbol_address; rewrite H8; eauto. }
        + split; intros.
          * destruct ta; simpl in ZA; inv ZA.
            destruct a; simpl in H2; inv H2.
            eapply Mem.perm_store_1; eauto.
            eapply Mem.perm_store_2 in H4; eauto. eapply FLATPERM; eauto.
          * destruct ta; simpl in ZA; inv ZA.
            destruct a; simpl in H2; inv H2.
            eapply Mem.perm_store_1; eauto.
            eapply Mem.perm_store_2 in H4; eauto. eapply FLATPERM; eauto. }
    case_eq (is_singleton (snd alpha)); intros; rename H into HOH2; rewrite HOH2 in H14.
    { inv H14.
      assert (SPINJ': Val.inject j (Vptr sp0 Int.zero) (Vptr tsp0 Int.zero)) by (econstructor; eauto).
      generalize (max_reg_function_use' _ _ _ H0). simpl; intros XXXX.
      generalize (regs_agree_inject_list _ _ _ _ _ (fun r X => XXXX r (or_intror X)) RES). intros YYYY.
      exploit (eval_addressing_inj ge tge); eauto.
      { intros. eapply symbol_address_inject; eauto. intros; eapply GINJ_implies; eauto. } intros [ta [XYY YYX]].
      assert (ZYF: Val.inject j rs#src trs#src).
      { generalize (max_reg_function_use' _ _ _ H0 src (or_introl eq_refl)). intros.
        generalize (RES src). intros [[A B] | [A B]]; try xomega; eauto. }
      generalize (Mem.storev_mapped_inject j kappa m a rs#src m' tm ta trs#src MINJ H2 YYX ZYF). intros [tm' [ZA ZB]].
      assert (regs_agree j (max_reg_function f) rs (trs # reg0 <- ta)).
      { unfold regs_agree. intros; destruct (plt (max_reg_function f) r).
        - right; split; auto.
          rewrite UNDEF; eauto.
        - left; split; try xomega.
          generalize (RES r). intros [[D E] | D]; try xomega.
          rewrite PMap.gso; eauto. xomega. }
      exploit tr_regs_annot_inv_singleton; eauto.
      { intros. destruct H20; eauto.
        eapply match_stackframes_sps_are_ptrs; eauto. }
      { intros. eapply STEP' in H20. destruct H20.
        eexists. eapply star_trans; eauto.
        eapply star_two. eapply exec_Inop; eauto.
        eapply exec_Iop; eauto. destruct addr; simpl; eauto.
        destruct (Int.eq_dec i Int.zero); simpl; eauto. subst i.
        simpl in XYY. destruct trs##args; inv XYY.
        destruct l; auto. destruct ta; simpl in ZA; inv ZA.
        destruct v; simpl in H22; inv H22. simpl. rewrite Int.add_zero; auto.
        eauto. } intros [tvals' LA].
      assert (FFFFF: (forall sp : val, In sp (Vptr tsp0 Int.zero :: map (fun s : stackframe => match s with | Stackframe _ _ tsp _ _ => tsp end) tstk) -> exists b : block, sp = Vptr b Int.zero)).
      { intros. destruct H20. inv H20; eauto. eapply match_stackframes_sps_are_ptrs; eauto. }
      assert (GGGGG: (forall sp : val, In sp (Vptr sp0 Int.zero :: map (fun s : stackframe => match s with | Stackframe _ _ tsp _ _ => tsp end) stk) -> exists b : block, sp = Vptr b Int.zero)).
      { intros. destruct H20. inv H20; eauto. eapply match_stackframes_sps_are_ptrs'; eauto. }
      generalize (tr_regs_annot_correct_singleton _ _ _ _ _ _ _ _ _ _ _ _ _ _ tm FFFFF H4 LA H14 UNDEF SHADOW). intros [trs' [HA [HB [HC HD]]]].
      generalize (tr_regs_annot_regs_singleton_plt _ _ _ _ _ _ _ _ H4). intros AA.
      generalize (tr_regs_annot_regs'_singleton_plt _ _ _ _ _ _ _ _ H4). intros AA'.
      generalize (tr_regs_annot_regs_singleton_norepet _ _ _ _ _ _ _ _ H4). intros AB.
      generalize (tr_cmp_regs_correct_singleton j tstk (Vptr tsp0 Int.zero) f tf reg0 _ pc3 pc4 pcs2 tm rs trs' tvals' H5 H18 HB HC AA UNDEF AB). intros [trs'' [HE [HF HG]]].
      generalize (regs_are_unknown_2 _ _ _ _ _ _ HF). intros XAXA. rewrite H6 in XAXA.
      assert (XAXA1: (trs''#reg1 = Vtrue \/ trs''#reg1 = Vfalse) \/ trs''#reg1 = Vundef) by (eapply or_assoc; eapply XAXA; eapply in_eq).
      assert (XAXA2: forall r, In r regs' -> trs'' # r = Vtrue \/ trs'' # r = Vfalse \/ trs'' # r = Vundef) by (intros; eapply XAXA; eapply in_cons; eauto).
      destruct XAXA1 as [XAXA1 | XAXA1].
      { destruct (Classical_Prop.classic (exists r, trs'' # r = Vundef /\ In r regs')).
        - assert (NA': ~ In reg0 regs').
          { intro. generalize (in_cons reg1 _ _ H21). intros FUU.
            rewrite <- H6 in FUU. eapply H18. eapply in_map_iff in FUU. destruct FUU as [x [FUU FUU2]].
            clear -FUU FUU2. induction regs.
            - inv FUU2.
            - destruct FUU2.
              + subst a; destruct x; simpl. left; auto.
                destruct p; left; auto.
              + destruct a; simpl; try (destruct p); right; auto. right; eapply IHregs; eauto. }
          assert (CN1: trs'' # reg0 <- (trs'' # reg1) # reg0 = Vtrue \/ trs'' # reg0 <- (trs'' # reg1) # reg0 = Vfalse) by (rewrite PMap.gss; eauto).
          assert (CN2: forall r, In r regs' -> trs'' # reg0 <- (trs'' # reg1) # r = Vtrue \/ trs'' # reg0 <- (trs'' # reg1) # r = Vfalse \/ trs'' # reg0 <- (trs'' # reg1) # r = Vundef).
          { intros; rewrite ! PMap.gso. eapply XAXA2. eauto. unfold not; intros. subst r; eapply NA'; eauto. }
          assert (CN3: exists r, (trs'' # reg0 <- (trs'' # reg1)) # r = Vundef /\ In r regs').
          { destruct H20. eexists. rewrite PMap.gso. eapply H20. unfold not; intros; subst x. destruct H20; eapply NA'; eauto. }
          generalize (tr_or_regs_undef' tstk _ tm _ _ _ _ _ tsp0 _ H8 NA' CN2 CN3 CN1). intros [trs''' [Hstar [Hundef Htrs''']]].
          assert (exists t, program_behaves (semantics tprog) (Goes_wrong t)).
          + destruct init_state_exists' as [s0 Hinit].
            generalize (STEP' _ Hinit). intros [t Hstep].
            eexists. econstructor; eauto.
            econstructor. eapply star_trans; eauto.
            eapply star_step. eapply exec_Inop; eauto.
            eapply star_step. eapply exec_Iop; eauto.
            destruct addr; simpl; eauto.
            destruct (Int.eq_dec i Int.zero); simpl; eauto.
            simpl in XYY. subst i. destruct trs##args; auto.
            destruct l; auto. rewrite <- XYY. inv XYY.
            unfold Mem.loadv in ZA. destruct v; simpl in ZA; inv ZA.
            simpl; auto. simpl; rewrite Int.add_zero. reflexivity.
            eapply star_trans. eapply HA.
            eapply star_trans. eapply HE.
            eapply star_step. eapply exec_Iop; eauto.
            simpl. eauto. eapply star_trans. eapply Hstar.
            eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto.
            red; unfold not; intros. inv H21; try congruence.
            rewrite H30 in H9; inv H9. simpl in H31. rewrite Hundef in H31. simpl in H31.
            inv H31.
            unfold not; intros. inv H21.
          + destruct H21. eapply DEFSAFE in H21; inv H21.
        - generalize (proj1 (not_undef _ _ XAXA2) H20). intros XAXA3.
          assert (XAXA4: forall r, In r (reg1 :: regs') -> trs'' # r = Vtrue \/ trs'' # r = Vfalse).
          { intros. destruct H21; eauto. subst r; eauto. }
          assert (AC': forall v, In v tvals' -> match v with | inl v0 => exists (b : block) (ofs : int), v0 = Vptr b ofs | inr (v0, v') => exists (b : block) (ofs ofs' : int), v0 = Vptr b ofs /\ v' = Vptr b ofs' end).
          { clear -LA FFFFF. intros; induction LA.
            - destruct (Int.eq_dec base bound).
              + destruct H.
                * subst v. subst base. eapply pop_is_in in H0. eapply FFFFF in H0.
                  destruct H0 as [b H0]. subst sp. simpl; eauto.
                * eapply IHLA; eauto.
              + destruct H.
                * subst v. eapply pop_is_in in H0. eapply FFFFF in H0.
                  destruct H0 as [b H0]. subst sp. simpl; eauto.
                * eapply IHLA; eauto.
            - destruct H.
              + destruct (Int.eq_dec base bound); subst v; eauto.
              + eapply IHLA; eauto.
            - inv H. }
          assert (XAXAXA: forall r, In r regs -> match r with | inl r0 => trs'' # r0 = Vtrue \/ trs'' # r0 = Vfalse | inr (r0, _) => trs'' # r0 = Vtrue \/ trs'' # r0 = Vfalse end).
          { intros. rewrite <- H6 in XAXA4. destruct r.
            - eapply XAXA4; auto. eapply in_map_iff. exists (inl r); eauto.
            - destruct p. eapply XAXA4. eapply in_map_iff. exists (inr (r, r0)); eauto. }
          generalize (eval_condition_are_bools' _ _ _ _ _ _ HF AC' XAXAXA). intros UUU.
          assert (XY: forall r, In r (map (fun r => match r with | inl r => r | inr r => fst r end) regs) -> trs''#r = Vtrue \/ trs''#r = Vfalse).
          { clear -ZA HF AC' UUU. intros. induction HF.
            - simpl in H. inv H.
            - simpl in H. destruct a1.
              + destruct H.
                * subst r0. unfold match_reg_val' in H0.
                  destruct b1; try (inv H0; fail).
                  rewrite H0. destruct (UUU _ (in_eq _ _)); rewrite H; auto.
                * eapply IHHF; eauto. intros; eapply AC'; right; auto.
                  intros; eapply UUU; right; auto.
              + destruct p. destruct H.
                * simpl in H; subst r0. unfold match_reg_val' in H0. destruct b1; try (inv H0; fail).
                  destruct p. rewrite H0. destruct (UUU _ (in_eq _ _)); rewrite H; auto.
                * eapply IHHF; eauto. intros; eapply AC'; right; auto.
                  intros; eapply UUU; right; auto. }
          generalize (not_is_trivial_annotation_implies _ _ _ _ HOH). intros HOH'.
          assert (HOH'': exists xx yy, snd alpha = xx::yy).
          { destruct (snd alpha); try congruence; eauto. }
          destruct HOH'' as [xx [yy HOH'']]. rewrite HOH'' in H3.
          generalize (max_reg_function_use' _ _ _ H0); simpl; intros VV.
          assert (I0: forall r, In r args -> r <> reg0).
          { intros. generalize (VV r (or_intror H21)); intros. assert (Plt r reg0) by xomega. eapply Plt_ne; eauto. }
          assert (I1: list_disjoint (fold_right
                                       (fun (x : Registers.reg + Registers.reg * Registers.reg) (acc : list Registers.reg) =>
                                          match x with
                                          | inl r => r :: acc
                                          | inr (r, r') => r :: r' :: acc
                                          end) nil regs) args).
          { unfold list_disjoint; intros. eapply (fun r H => VV r (or_intror H)) in H22.
            assert (Plt (max_reg_function f) x); try (eapply not_eq_sym; eapply Plt_ne; xomega; fail).
            clear -H21 AA. induction regs. simpl in H21; inv H21. simpl in H21. destruct a.
            destruct H21. subst x. eapply (AA _ (in_eq _ _)). eapply IHregs; eauto. intros; eapply AA; right; auto.
            destruct p. destruct H21. subst x. eapply (AA _ (in_eq _ _)). destruct H. subst x. eapply (AA _ (in_eq _ _)).
            eapply IHregs; eauto. intros; eapply AA; right; auto. }
          assert (I2: list_disjoint ((fold_right
                                        (fun (x : Registers.reg + Registers.reg * Registers.reg) (acc : list Registers.reg) =>
                                           match x with
                                           | inl r => r :: acc
                                           | inr (r, r') => r :: r' :: acc
                                           end) nil regs)++regs2) args).
          { unfold list_disjoint; intros. eapply in_app in H21. destruct H21.
            - eapply I1; auto.
            - eapply (fun r H => VV r (or_intror H)) in H22.
              eapply AA' in H21. assert (Plt y x) by xomega. apply not_eq_sym. eapply Plt_ne; eauto. }
          assert (I3: src <> reg0).
          { generalize (VV src (or_introl eq_refl)). intros. assert (Plt src reg0) by xomega.
            eapply Plt_ne; eauto. }
          assert (I4: ~ In src (fold_right
                                        (fun (x : Registers.reg + Registers.reg * Registers.reg) (acc : list Registers.reg) =>
                                           match x with
                                           | inl r => r :: acc
                                           | inr (r, r') => r :: r' :: acc
                                           end) nil regs)).
          { generalize (VV src (or_introl eq_refl)). intros. intro.
            assert (Plt (max_reg_function f) src); try xomega.
            clear -H22 AA. induction regs. simpl in H22. inv H22. simpl in H22. destruct a.
            destruct H22. subst src. eapply (AA _ (in_eq _ _)). eapply IHregs; eauto. intros; eapply AA; right; auto.
            destruct p. destruct H22. subst src. eapply (AA _ (in_eq _ _)). destruct H. subst src. eapply (AA _ (in_eq _ _)).
            eapply IHregs; eauto. intros; eapply AA; right; auto. }
          assert (I5: ~ In src ((fold_right
                                        (fun (x : Registers.reg + Registers.reg * Registers.reg) (acc : list Registers.reg) =>
                                           match x with
                                           | inl r => r :: acc
                                           | inr (r, r') => r :: r' :: acc
                                           end) nil regs)++regs2)).
          { rewrite not_in_app; split.
            - eapply I4.
            - intro. eapply AA' in H21. generalize (VV src (or_introl eq_refl)). intros. xomega. }
          rewrite H6 in XY. generalize (XY reg1 (in_eq _ _)). clear XY. intros [XY | XY].
          { generalize (list_forall2_not_in_2 _ _ _ _ _ _ reg0 Vtrue HF H18). intros HH.
            assert (AD: forall r, In r (reg1::regs') -> (trs''#reg0 <- Vtrue)#r = Vtrue \/ (trs''#reg0 <- Vtrue)#r = Vfalse).
            { clear -H6 HH AC' UUU. intros. rewrite <- H6 in H. clear H6. induction HH.
              - simpl in H. inv H.
              - simpl in H. destruct H.
                + destruct a1.
                  * subst r0. unfold match_reg_val' in H0. destruct b1; inv H0.
                    rewrite H1. unfold eval_condition in UUU. destruct (UUU _ (in_eq _ _)); rewrite H; auto.
                  * destruct p. simpl in H. subst.
                    unfold match_reg_val' in H0. destruct b1; try inv H0. destruct p; rewrite H0.
                    eapply (UUU _ (in_eq _ _)).
                + eapply IHHH; eauto.
                  intros; eapply AC'; right; eauto.
                  intros; eapply UUU; right; eauto. }
            assert (AF: trs''#reg0 <- (Vtrue)#reg0 = Vtrue) by (rewrite PMap.gss; reflexivity).
            assert (FU: ~ In reg0 regs').
            { intro. generalize (in_cons reg1 _ _ H21). intros FUU.
              rewrite <- H6 in FUU. eapply H18. eapply in_map_iff in FUU. destruct FUU as [x [FUU FUU2]].
              clear -FUU FUU2. induction regs.
              - inv FUU2.
              - destruct FUU2.
                + subst a; destruct x; simpl. left; auto.
                  destruct p; left; auto.
                + destruct a; simpl; try (destruct p); right; auto. right; eapply IHregs; eauto. }
            generalize (tr_or_regs_true tstk tf tm regs' (Psucc pc4) reg0 pc5 pcs3 tsp0 (trs''#reg0 <- Vtrue) H8 (fun r H => AD r (in_cons _ _ _ H)) FU AF). intros [trs''' [HI [HJ HK]]].
            eexists; split.
            - eapply plus_left.
              + eapply exec_Inop; eauto.
              + eapply star_step.
                * eapply exec_Iop; eauto.
                  destruct addr; simpl; eauto.
                  destruct (Int.eq_dec i Int.zero); simpl; eauto.
                  simpl in XYY. subst i. destruct trs##args; auto.
                  destruct l; auto. rewrite <- XYY. inv XYY.
                  unfold Mem.storev in ZA. destruct v; simpl in ZA; inv ZA.
                  simpl. rewrite Int.add_zero. reflexivity.
                * eapply star_trans.
                  eapply HA. eapply star_trans. eapply HE.
                  eapply star_step. eapply exec_Iop; eauto.
                  simpl; eauto. eapply star_trans.
                  rewrite XY. eapply HI.
                  eapply star_step. eapply exec_Icond; eauto.
                  simpl; rewrite HJ; simpl. rewrite Int.eq_false; simpl; auto.
                  eapply Int.one_not_zero.
                  simpl. eapply star_step.
                  eapply exec_Istore; eauto. instantiate (1:= ta). rewrite <- XYY.
                  erewrite (regs_rewrite_one _ _ _ _ reg0 HK I0); eauto.
                  erewrite regs_rewrite_one'; eauto.
                  erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HG r X)) I1).
                  erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HD r X)) I2).
                  erewrite regs_rewrite_one'; eauto.
                  rewrite HK; eauto. rewrite PMap.gso; eauto.
                  rewrite <- HG; eauto. rewrite <- HD; eauto. rewrite PMap.gso; eauto.
                  eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto.
                * eauto.
              + eauto.
            - econstructor; eauto.
              + unfold regs_agree; intros.
                destruct (plt (max_reg_function f) r).
                * right; split; auto.
                  rewrite UNDEF; auto.
                * left; split; try xomega. destruct (peq r reg0); try xomega.
                  rewrite HK; auto. rewrite PMap.gso; auto.
                  rewrite <- HG; auto. generalize (HC r).
                  intros [[X Y] | [X Y]]; try xomega; auto.
                  intro. eapply n. clear -H21 AA. induction regs. simpl in H21; inv H21. simpl in H21. destruct a.
                  destruct H21. subst r. eapply (AA _ (in_eq _ _)). eapply IHregs; eauto. intros; eapply AA; right; auto.
                  destruct p. destruct H21. subst r. eapply (AA _ (in_eq _ _)). destruct H. subst r. eapply (AA _ (in_eq _ _)).
                  eapply IHregs; eauto. intros; eapply AA; right; auto.
              + intros. generalize (STEP s0 H21). intros [t X].
                exists (t ** E0). eapply star_right; eauto.
                eapply exec_Istore_block'; eauto. rewrite HOH''; auto.
              + intros. generalize (STEP' s0 H21). intros [t X].
                exists (t ** E0). eapply star_trans; eauto.
                eapply star_step.
                * eapply exec_Inop; eauto.
                * eapply star_step.
                  { eapply exec_Iop; eauto.
                    destruct addr; simpl; eauto.
                    destruct (Int.eq_dec i Int.zero); simpl; eauto.
                    simpl in XYY. subst i. destruct trs##args; auto.
                    destruct l; auto. rewrite <- XYY. inv XYY.
                    unfold Mem.storev in ZA. destruct v; simpl in ZA; inv ZA.
                    simpl. rewrite Int.add_zero. reflexivity. }
                  { eapply star_trans.
                    eapply HA. eapply star_trans. eapply HE.
                    eapply star_step. eapply exec_Iop; eauto.
                    simpl; eauto. eapply star_trans.
                    rewrite XY. eapply HI.
                    eapply star_step. eapply exec_Icond; eauto.
                    simpl; rewrite HJ; simpl. rewrite Int.eq_false; simpl; auto.
                    eapply Int.one_not_zero.
                    simpl. eapply star_step.
                    eapply exec_Istore; eauto. instantiate (1:= ta). rewrite <- XYY.
                    erewrite (regs_rewrite_one _ _ _ _ reg0 HK I0); eauto.
                    erewrite regs_rewrite_one'; eauto.
                    erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HG r X)) I1).
                    erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HD r X)) I2).
                    erewrite regs_rewrite_one'; eauto.
                    rewrite HK; eauto. rewrite PMap.gso; eauto.
                    rewrite <- HG; eauto. rewrite <- HD; eauto. rewrite PMap.gso; eauto.
                    eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto. }
                  { eauto. }
                * eauto.
              + unfold Mem.storev in ZA; destruct ta; inv ZA.
                erewrite Mem.nextblock_store; eauto.
              + unfold Mem.storev in ZA; destruct ta; inv ZA.
                erewrite Mem.nextblock_store; eauto.
              + unfold Mem.range_perm; intros.
                unfold Mem.storev in ZA. destruct ta; inv ZA.
                eapply Mem.perm_store_1; eauto. eapply STKPERM in H21.
                unfold Mem.range_perm in H21. eapply H21; eauto.
              + unfold Mem.range_perm; intros.
                unfold Mem.storev in ZA. destruct ta; inv ZA.
                eapply Mem.perm_store_1; eauto. eapply SIZEPERM in H21.
                unfold Mem.range_perm in H21. eapply H21; eauto.
              + intros. eapply STKRANGE in H21. rewrite <- H21.
                split; intros.
                * unfold Mem.storev in *. destruct ta; inv ZA; eauto.
                  eapply Mem.perm_store_2; eauto.
                * unfold Mem.storev in *. destruct ta; inv ZA; eauto.
                  eapply Mem.perm_store_1; eauto.
              + intros. eapply SIZERANGE in H21. rewrite <- H21.
                split; intros.
                * unfold Mem.storev in *. destruct ta; inv ZA; eauto.
                  eapply Mem.perm_store_2; eauto.
                * unfold Mem.storev in *. destruct ta; inv ZA; eauto.
                  eapply Mem.perm_store_1; eauto.
              + unfold Mem.storev in H2. destruct a; inv H2.
                exploit Mem.nextblock_store; eauto. intros BVC; rewrite BVC; auto.
              + unfold Mem.storev in ZA. destruct ta; inv ZA.
                exploit Mem.nextblock_store; eauto. intros BVC; rewrite BVC; auto.
              + unfold Mem.storev in ZA; destruct ta; inv ZA.
                unfold Mem.storev in H2; destruct a; inv H2.
                inversion YYX; subst. destruct SIZE_exists as [bSIZE [HSIZE HSIZE']].
                destruct STK_exists as [bSTK [HSTK HSTK']].
                eapply shadowstack_is_sound_store; eauto.
                * eapply SIZENOTMAPPED; eauto. unfold Genv.symbol_address; rewrite HSIZE; eauto.
                * eapply STKNOTMAPPED; eauto. unfold Genv.symbol_address; rewrite HSTK; eauto.
              + intros; split.
                * intros. destruct a; inv H2.
                  destruct ta; inv ZA.
                  eapply Mem.perm_store_2 in H22; eauto.
                  eapply Mem.perm_store_1; eauto. eapply FLATPERM; eauto.
                * intros. destruct a; inv H2.
                  destruct ta; inv ZA.
                  eapply Mem.perm_store_2 in H22; eauto.
                  eapply Mem.perm_store_1; eauto. eapply FLATPERM; eauto. }
          { generalize (list_forall2_not_in_2 _ _ _ _ _ _ reg0 Vfalse HF H18). intros HH.
            assert (AD: forall r, In r (reg1::regs') -> (trs''#reg0 <- Vfalse)#r = Vtrue \/ (trs''#reg0 <- Vfalse)#r = Vfalse).
            { clear -H6 HH AC' UUU. intros. rewrite <- H6 in H. clear H6. induction HH.
              - simpl in H. inv H.
              - simpl in H. destruct H.
                + destruct a1.
                  * subst r0. unfold match_reg_val' in H0. destruct b1; inv H0.
                    rewrite H1. unfold eval_condition in UUU. destruct (UUU _ (in_eq _ _)); rewrite H; auto.
                  * destruct p. simpl in H. subst.
                    unfold match_reg_val' in H0. destruct b1; try inv H0. destruct p; rewrite H0.
                    eapply (UUU _ (in_eq _ _)).
                + eapply IHHH; eauto.
                  intros; eapply AC'; right; eauto.
                  intros; eapply UUU; right; eauto. }
            assert (AF: trs''#reg0 <- (Vfalse)#reg0 = Vfalse).
            { rewrite PMap.gss; reflexivity. }
            assert (FU: ~ In reg0 regs').
            { intro. generalize (in_cons reg1 _ _ H21). intros FUU.
              rewrite <- H6 in FUU. eapply H18. eapply in_map_iff in FUU. destruct FUU as [x [FUU FUU2]].
              clear -FUU FUU2. induction regs.
              - inv FUU2.
              - destruct FUU2.
                + subst a; destruct x; simpl. left; auto.
                  destruct p; left; auto.
                + destruct a; simpl; try (destruct p); right; auto. right; eapply IHregs; eauto. }
            assert (AE': exists r, In r regs' /\ (trs''#reg0 <- Vfalse)#r = Vtrue).
            { destruct (Classical_Prop.classic (exists r, In r regs' /\ (trs''#reg0 <- Vfalse)#r = Vtrue)); auto.
              generalize (Classical_Pred_Type.not_ex_all_not _ _ H21). intros Hall.
              exploit tr_or_regs_false; eauto. intros. destruct (AD _ (in_cons _ _ _ H22)); auto.
              exfalso. eapply Hall; split; eauto. intros [trs''' [Hstar [Hfalse Htrs]]].
              inv H11.
              assert (exists t, program_behaves (semantics tprog) (Goes_wrong t)).
              + destruct init_state_exists' as [s0 Hinit].
                generalize (STEP' _ Hinit). intros [t Hstep].
                eexists. econstructor; eauto.
                econstructor. eapply star_trans; eauto.
                eapply star_step. eapply exec_Inop; eauto.
                eapply star_step. eapply exec_Iop; eauto.
                destruct addr; simpl; eauto.
                destruct (Int.eq_dec i Int.zero); simpl; eauto.
                simpl in XYY. subst i. destruct trs##args; auto.
                destruct l; auto. rewrite <- XYY. inv XYY.
                unfold Mem.storev in ZA. destruct v; simpl in ZA; inv ZA.
                simpl; auto. simpl; rewrite Int.add_zero. reflexivity.
                eapply star_trans. eapply HA.
                eapply star_trans. eapply HE.
                eapply star_step. eapply exec_Iop; eauto.
                simpl. eauto. eapply star_trans. rewrite XY. eapply Hstar.
                eapply star_step. eapply exec_Icond; eauto. simpl. rewrite Hfalse. simpl.
                rewrite Int.eq_true. simpl. eauto. simpl.
                eapply star_step. eapply exec_Iop; eauto. simpl. eauto.
                eapply star_step. eapply exec_Iop; eauto. simpl. eauto.
                eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
                red; unfold not; intros. inv H11; try congruence.
                rewrite H34 in H24; inv H24.
                simpl in H35. rewrite PMap.gss in H35. rewrite PMap.gso in H35; eauto.
                rewrite PMap.gss in H35. simpl in H35. rewrite Int.eq_true in H35; simpl in H35. inv H35.
                unfold not; intros. inv H11.
              + destruct H11. eapply DEFSAFE in H11; inv H11. }
            generalize (tr_or_regs_correct tstk tf tm _ (Psucc pc4) reg0 pc5 pcs3 tsp0 (trs'' # reg0 <- (Vint Int.zero)) H8 (fun r H => AD r (in_cons _ _ _ H)) FU AE' (or_intror AF)). intros [trs''' [HI [HJ HK]]].
            eexists; split.
            - eapply plus_left.
              + eapply exec_Inop; eauto.
              + eapply star_step.
                * eapply exec_Iop; eauto.
                  destruct addr; simpl; eauto.
                  destruct (Int.eq_dec i Int.zero); simpl; eauto.
                  simpl in XYY. subst i. destruct trs##args; auto.
                  destruct l; auto. rewrite <- XYY. inv XYY.
                  unfold Mem.storev in ZA. destruct v; simpl in ZA; inv ZA.
                  simpl. rewrite Int.add_zero. reflexivity.
                * eapply star_trans.
                  eapply HA. eapply star_trans. eapply HE.
                  eapply star_step. eapply exec_Iop; eauto.
                  simpl; eauto. eapply star_trans.
                  rewrite XY. unfold Vfalse. eapply HI.
                  eapply star_step. eapply exec_Icond; eauto.
                  simpl; rewrite HJ; simpl. rewrite Int.eq_false; simpl; auto.
                  eapply Int.one_not_zero.
                  simpl. eapply star_step.
                  eapply exec_Istore; eauto. instantiate (1:= ta). rewrite <- XYY.
                  erewrite (regs_rewrite_one _ _ _ _ reg0 HK I0); eauto.
                  erewrite regs_rewrite_one'; eauto.
                  erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HG r X)) I1).
                  erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HD r X)) I2).
                  erewrite regs_rewrite_one'; eauto.
                  rewrite HK; eauto. rewrite PMap.gso; eauto.
                  rewrite <- HG; eauto. rewrite <- HD; eauto. rewrite PMap.gso; eauto.
                  eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto.
                * eauto.
              + eauto.
            - econstructor; eauto.
              + unfold regs_agree; intros.
                destruct (plt (max_reg_function f) r).
                * right; split; auto.
                  rewrite UNDEF; auto.
                * left; split; try xomega. destruct (peq r reg0); try xomega.
                  rewrite HK; auto. rewrite PMap.gso; auto.
                  rewrite <- HG; auto. generalize (HC r).
                  intros [[X Y] | [X Y]]; try xomega; auto.
                  intro. eapply n. clear -H21 AA. induction regs. simpl in H21; inv H21. simpl in H21. destruct a.
                  destruct H21. subst r. eapply (AA _ (in_eq _ _)). eapply IHregs; eauto. intros; eapply AA; right; auto.
                  destruct p. destruct H21. subst r. eapply (AA _ (in_eq _ _)). destruct H. subst r. eapply (AA _ (in_eq _ _)).
                  eapply IHregs; eauto. intros; eapply AA; right; auto.
              + intros. generalize (STEP s0 H21). intros [t X].
                exists (t ** E0). eapply star_right; eauto.
                eapply exec_Istore_block'; eauto.
                destruct (snd alpha); eauto. econstructor; auto. rewrite HOH''; eauto.
              + intros. generalize (STEP' s0 H21). intros [t X].
                exists (t ** E0). eapply star_trans; eauto.
                eapply star_step.
                * eapply exec_Inop; eauto.
                * eapply star_step.
                  { eapply exec_Iop; eauto.
                    destruct addr; simpl; eauto.
                    destruct (Int.eq_dec i Int.zero); simpl; eauto.
                    simpl in XYY. subst i. destruct trs##args; auto.
                    destruct l; auto. rewrite <- XYY. inv XYY.
                    unfold Mem.storev in ZA. destruct v; simpl in ZA; inv ZA.
                    simpl. rewrite Int.add_zero. reflexivity. }
                  { eapply star_trans.
                    eapply HA. eapply star_trans. eapply HE.
                    eapply star_step. eapply exec_Iop; eauto.
                    simpl; eauto. eapply star_trans.
                    rewrite XY. eapply HI.
                    eapply star_step. eapply exec_Icond; eauto.
                    simpl; rewrite HJ; simpl. rewrite Int.eq_false; simpl; auto.
                    eapply Int.one_not_zero.
                    simpl. eapply star_step.
                    eapply exec_Istore; eauto. instantiate (1:= ta). rewrite <- XYY.
                    erewrite (regs_rewrite_one _ _ _ _ reg0 HK I0); eauto.
                    erewrite regs_rewrite_one'; eauto.
                    erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HG r X)) I1).
                    erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HD r X)) I2).
                    erewrite regs_rewrite_one'; eauto.
                    rewrite HK; eauto. rewrite PMap.gso; eauto.
                    rewrite <- HG; eauto. rewrite <- HD; eauto. rewrite PMap.gso; eauto.
                    eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto. }
                  { eauto. }
                * eauto.
              + unfold Mem.storev in ZA; destruct ta; inv ZA.
                erewrite Mem.nextblock_store; eauto.
              + unfold Mem.storev in ZA; destruct ta; inv ZA.
                erewrite Mem.nextblock_store; eauto.
              + unfold Mem.range_perm; intros.
                unfold Mem.storev in ZA. destruct ta; inv ZA.
                eapply Mem.perm_store_1; eauto. eapply STKPERM in H21.
                unfold Mem.range_perm in H21. eapply H21; eauto.
              + unfold Mem.range_perm; intros.
                unfold Mem.storev in ZA. destruct ta; inv ZA.
                eapply Mem.perm_store_1; eauto. eapply SIZEPERM in H21.
                unfold Mem.range_perm in H21. eapply H21; eauto.
              + intros. eapply STKRANGE in H21. rewrite <- H21.
                split; intros.
                * unfold Mem.storev in *. destruct ta; inv ZA; eauto.
                  eapply Mem.perm_store_2; eauto.
                * unfold Mem.storev in *. destruct ta; inv ZA; eauto.
                  eapply Mem.perm_store_1; eauto.
              + intros. eapply SIZERANGE in H21. rewrite <- H21.
                split; intros.
                * unfold Mem.storev in *. destruct ta; inv ZA; eauto.
                  eapply Mem.perm_store_2; eauto.
                * unfold Mem.storev in *. destruct ta; inv ZA; eauto.
                  eapply Mem.perm_store_1; eauto.
              + unfold Mem.storev in H2; destruct a; inv H2.
                exploit Mem.nextblock_store; eauto. intros ABC; rewrite ABC; auto.
              + unfold Mem.storev in ZA; destruct ta; inv ZA.
                exploit Mem.nextblock_store; eauto. intros ABC; rewrite ABC; auto.
              + unfold Mem.storev in ZA; destruct ta; inv ZA.
                unfold Mem.storev in H2; destruct a; inv H2.
                inversion YYX; subst. destruct SIZE_exists as [bSIZE [HSIZE HSIZE']].
                destruct STK_exists as [bSTK [HSTK HSTK']].
                eapply shadowstack_is_sound_store; eauto.
                * eapply SIZENOTMAPPED; eauto. unfold Genv.symbol_address; rewrite HSIZE; eauto.
                * eapply STKNOTMAPPED; eauto. unfold Genv.symbol_address; rewrite HSTK; eauto.
              + intros; split.
                * intros. destruct a; inv H2.
                  destruct ta; inv ZA.
                  eapply Mem.perm_store_2 in H22; eauto.
                  eapply Mem.perm_store_1; eauto. eapply FLATPERM; eauto.
                * intros. destruct a; inv H2.
                  destruct ta; inv ZA.
                  eapply Mem.perm_store_2 in H22; eauto.
                  eapply Mem.perm_store_1; eauto. eapply FLATPERM; eauto. } }
      { assert (NA': ~ In reg0 regs').
        { intro. generalize (in_cons reg1 _ _ H20). intros FUU.
          rewrite <- H6 in FUU. eapply H18. eapply in_map_iff in FUU. destruct FUU as [x [FUU FUU2]].
          clear -FUU FUU2. induction regs.
          - inv FUU2.
          - destruct FUU2.
            + subst a; destruct x; simpl. left; auto.
              destruct p; left; auto.
            + destruct a; simpl; try (destruct p); right; auto. right; eapply IHregs; eauto. }
        assert (CN: trs'' # reg0 <- (trs'' # reg1) # reg0 = Vundef) by (rewrite PMap.gss; eauto).
        generalize (tr_or_regs_undef tstk _ tm _ _ _ _ _ tsp0 _ H8 NA' CN). intros [trs''' [Hstar [Hundef Htrs''']]].
        inv H11.
        assert (exists t, program_behaves (semantics tprog) (Goes_wrong t)).
        - destruct init_state_exists' as [s0 Hinit].
          generalize (STEP' _ Hinit). intros [t Hstep].
          eexists. econstructor; eauto.
          econstructor. eapply star_trans; eauto.
          eapply star_step. eapply exec_Inop; eauto.
          eapply star_step. eapply exec_Iop; eauto.
          destruct addr; simpl; eauto.
          destruct (Int.eq_dec i Int.zero); simpl; eauto.
          simpl in XYY. subst i. destruct trs##args; auto.
          destruct l; auto. rewrite <- XYY. inv XYY.
          unfold Mem.storev in ZA. destruct v; simpl in ZA; inv ZA.
          simpl; auto. simpl; rewrite Int.add_zero. reflexivity.
          eapply star_trans. eapply HA.
          eapply star_trans. eapply HE.
          eapply star_step. eapply exec_Iop; eauto.
          simpl. eauto. eapply star_trans. eapply Hstar.
          eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto.
          red; unfold not; intros. inv H11; try congruence.
          rewrite H32 in H9; inv H9. simpl in H33. rewrite Hundef in H33. simpl in H33.
          inv H33.
          unfold not; intros. inv H11.
        - destruct H11. eapply DEFSAFE in H11; inv H11. } }
    inv H14.
    assert (SPINJ': Val.inject j (Vptr sp0 Int.zero) (Vptr tsp0 Int.zero)) by (econstructor; eauto).
    generalize (max_reg_function_use' _ _ _ H0). simpl; intros XXXX.
    generalize (regs_agree_inject_list _ _ _ _ _ (fun r X => XXXX r (or_intror X)) RES). intros YYYY.
    exploit (eval_addressing_inj ge tge); eauto.
    { intros. eapply symbol_address_inject; eauto. intros; eapply GINJ_implies; eauto. } intros [ta [XYY YYX]].
    assert (ZYF: Val.inject j rs#src trs#src).
    { generalize (max_reg_function_use' _ _ _ H0 src (or_introl eq_refl)). intros.
      generalize (RES src). intros [[A B] | [A B]]; try xomega; eauto. }
    generalize (Mem.storev_mapped_inject j kappa m a rs#src m' tm ta trs#src MINJ H2 YYX ZYF). intros [tm' [ZA ZB]].
    assert (regs_agree j (max_reg_function f) rs (trs # reg0 <- ta)).
    { unfold regs_agree. intros; destruct (plt (max_reg_function f) r).
      - right; split; auto.
        rewrite UNDEF; eauto.
      - left; split; try xomega.
        generalize (RES r). intros [[D E] | D]; try xomega.
        rewrite PMap.gso; eauto. xomega. }
    exploit tr_regs_annot_inv; eauto.
    { intros. destruct H14; eauto.
      eapply match_stackframes_sps_are_ptrs; eauto. }
    { intros. eapply STEP' in H14. destruct H14.
      eexists. eapply star_trans; eauto.
      eapply star_two. eapply exec_Inop; eauto.
      eapply exec_Iop; eauto. destruct addr; simpl; eauto.
      destruct (Int.eq_dec i Int.zero); simpl; eauto. subst i.
      simpl in XYY. destruct trs##args; inv XYY.
      destruct l; auto. destruct ta; simpl in ZA; inv ZA.
      destruct v; simpl in H21; inv H21. simpl. rewrite Int.add_zero; auto.
      eauto. } intros [tvals ZYX].
    assert (FFFFF: (forall sp : val, In sp (Vptr tsp0 Int.zero :: map (fun s : stackframe => match s with | Stackframe _ _ tsp _ _ => tsp end) tstk) -> exists b : block, sp = Vptr b Int.zero)).
    { intros. destruct H14. inv H14; eauto. eapply match_stackframes_sps_are_ptrs; eauto. }
    assert (GGGGG: (forall sp : val, In sp (Vptr sp0 Int.zero :: map (fun s : stackframe => match s with | Stackframe _ _ tsp _ _ => tsp end) stk) -> exists b : block, sp = Vptr b Int.zero)).
    { intros. destruct H14. inv H14; eauto. eapply match_stackframes_sps_are_ptrs'; eauto. }
    generalize (tr_regs_annot_correct _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ tm FFFFF H17 H4 ZYX H6 UNDEF SHADOW). intros [trs' [HA [HB [HC HD]]]].
    generalize (tr_regs_annot_regs_plt _ _ _ _ _ _ _ _ _ _ _ H4). intros AA.
    generalize (tr_regs_annot_regs'_plt _ _ _ _ _ _ _ _ _ _ _ H4). intros AA'.
    generalize (tr_regs_annot_regs_norepet _ _ _ _ _ _ _ _ _ _ _ H4). intros AB.
    generalize (tr_cmp_regs_correct _ tstk (Vptr tsp0 Int.zero) f tf reg0 _ pc3 pc4 pcs2 tm rs trs' tvals H5 H18 HB HC AA UNDEF AB). intros [trs'' [HE [HF HG]]].
    generalize (addr_of_annotations_are_ptrs _ _ _ _ _ ZYX FFFFF). intros AC.
    rewrite <- HD in HF; auto. rewrite PMap.gss in HF. 2: eapply not_in_app; split; auto.
    generalize (regs_are_unknown' _ _ _ _ _ _ _ _ ZA HF AC). intros XAXA.
    assert (XAXA1: (trs''#reg1 = Vtrue \/ trs''#reg1 = Vfalse) \/ trs''#reg1 = Vundef) by (eapply or_assoc; eapply XAXA; eapply in_eq).
    assert (XAXA2: forall r, In r regs' -> trs'' # r = Vtrue \/ trs'' # r = Vfalse \/ trs'' # r = Vundef) by (intros; eapply XAXA; eapply in_cons; eauto).
    destruct XAXA1 as [XAXA1 | XAXA1].
    { destruct (Classical_Prop.classic (exists r, trs'' # r = Vundef /\ In r regs')).
      - eapply not_in_cons in H18. destruct H18 as [NA NA'].
        assert (CN1: trs'' # reg0 <- (trs'' # reg1) # reg0 = Vtrue \/ trs'' # reg0 <- (trs'' # reg1) # reg0 = Vfalse) by (rewrite PMap.gss; eauto).
        assert (CN2: forall r, In r regs' -> trs'' # reg0 <- (trs'' # reg1) # r = Vtrue \/ trs'' # reg0 <- (trs'' # reg1) # r = Vfalse \/ trs'' # reg0 <- (trs'' # reg1) # r = Vundef).
        { intros; rewrite ! PMap.gso. eapply XAXA2. eauto. unfold not; intros. subst r; eapply NA'; eauto. }
        assert (CN3: exists r, (trs'' # reg0 <- (trs'' # reg1)) # r = Vundef /\ In r regs').
        { destruct H14. eexists. rewrite PMap.gso. eapply H14. unfold not; intros; subst x. destruct H14; eapply NA'; eauto. }
        generalize (tr_or_regs_undef' tstk _ tm _ _ _ _ _ tsp0 _ H8 NA' CN2 CN3 CN1). intros [trs''' [Hstar [Hundef Htrs''']]].
        assert (exists t, program_behaves (semantics tprog) (Goes_wrong t)).
        + destruct init_state_exists' as [s0 Hinit].
          generalize (STEP' _ Hinit). intros [t Hstep].
          eexists. econstructor; eauto.
          econstructor. eapply star_trans; eauto.
          eapply star_step. eapply exec_Inop; eauto.
          eapply star_step. eapply exec_Iop; eauto.
          destruct addr; simpl; eauto.
          destruct (Int.eq_dec i Int.zero); simpl; eauto.
          simpl in XYY. subst i. destruct trs##args; auto.
          destruct l; auto. rewrite <- XYY. inv XYY.
          unfold Mem.loadv in ZA. destruct v; simpl in ZA; inv ZA.
          simpl; auto. simpl; rewrite Int.add_zero. reflexivity.
          eapply star_trans. eapply HA.
          eapply star_trans. eapply HE.
          eapply star_step. eapply exec_Iop; eauto.
          simpl. eauto. eapply star_trans. eapply Hstar.
          eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto.
          red; unfold not; intros. inv H18; try congruence.
          rewrite H28 in H9; inv H9. simpl in H29. rewrite Hundef in H29. simpl in H29.
          inv H29.
          unfold not; intros. inv H18.
        + destruct H18. eapply DEFSAFE in H18; inv H18.
      - generalize (proj1 (not_undef _ _ XAXA2) H14). intros XAXA3.
        assert (XAXA4: forall r, In r (reg1 :: regs') -> trs'' # r = Vtrue \/ trs'' # r = Vfalse).
        { intros. destruct H20; eauto. subst r; eauto. }
        generalize (eval_condition_are_bools _ _ _ _ _ HF AC XAXA4). intros UUU.
        generalize (regs_are_bools' _ _ _ _ _ _ _ _ ZA HF AC UUU). intros XY.
        generalize (not_is_trivial_annotation_implies _ _ _ _ HOH). intros HOH'.
        assert (HOH'': exists xx yy, snd alpha = xx::yy).
        { destruct (snd alpha); try congruence; eauto. }
        destruct HOH'' as [xx [yy HOH'']]. rewrite HOH'' in H4.
        generalize (max_reg_function_use' _ _ _ H0); simpl; intros VV.
        assert (I0: forall r, In r args -> r <> reg0).
        { intros. generalize (VV r (or_intror H20)); intros. assert (Plt r reg0) by xomega. eapply Plt_ne; eauto. }
        assert (I1: list_disjoint (reg1::regs') args).
        { unfold list_disjoint; intros. generalize (VV y (or_intror H21)); intros. eapply AA in H20.
          assert (Plt y x) by xomega. apply not_eq_sym. eapply Plt_ne; eauto. }
        assert (I2: list_disjoint ((reg1::regs')++regs2) args).
        { unfold list_disjoint; intros. generalize (VV y (or_intror H21)); intros. eapply in_app in H20. destruct H20.
          - eapply AA in H20. assert (Plt y x) by xomega. apply not_eq_sym. eapply Plt_ne; eauto.
          - eapply AA' in H20. assert (Plt y x) by xomega. apply not_eq_sym. eapply Plt_ne; eauto. }
        assert (I3: src <> reg0).
        { generalize (VV src (or_introl eq_refl)). intros. assert (Plt src reg0) by xomega.
          eapply Plt_ne; eauto. }
        assert (I4: ~ In src (reg1::regs')).
        { generalize (VV src (or_introl eq_refl)). intros. intro. eapply AA in H21. xomega. }
        assert (I5: ~ In src ((reg1::regs')++regs2)).
        { rewrite not_in_app; split.
          - eapply I4.
          - intro. eapply AA' in H20. generalize (VV src (or_introl eq_refl)). intros. xomega. }
        generalize (XY reg1 (in_eq _ _)). clear XY. intros [XY | XY].
        { generalize (RTLdefgenspec.list_forall2_not_in' _ _ _ _ _ reg0 Vtrue HF H18). intros HH.
          generalize (regs_are_bools' _ _ _ _ _ _ _ _ ZA HH AC UUU). intros AD.
          assert (AF: trs''#reg0 <- (Vtrue)#reg0 = Vtrue) by (rewrite PMap.gss; reflexivity).
          apply not_in_cons in H18. destruct H18.
          generalize (tr_or_regs_true tstk tf tm regs' (Psucc pc4) reg0 pc5 pcs3 tsp0 (trs''#reg0 <- Vtrue) H8 (fun r H => AD r (in_cons _ _ _ H)) H20 AF). intros [trs''' [HI [HJ HK]]].
          eexists; split.
          - eapply plus_left.
            + eapply exec_Inop; eauto.
            + eapply star_step.
              * eapply exec_Iop; eauto.
                destruct addr; simpl; eauto.
                destruct (Int.eq_dec i Int.zero); simpl; eauto.
                simpl in XYY. subst i. destruct trs##args; auto.
                destruct l; auto. rewrite <- XYY. inv XYY.
                unfold Mem.storev in ZA. destruct v; simpl in ZA; inv ZA.
                simpl. rewrite Int.add_zero. reflexivity.
              * eapply star_trans.
                eapply HA. eapply star_trans. eapply HE.
                eapply star_step. eapply exec_Iop; eauto.
                simpl; eauto. eapply star_trans.
                rewrite XY. eapply HI.
                eapply star_step. eapply exec_Icond; eauto.
                simpl; rewrite HJ; simpl. rewrite Int.eq_false; simpl; auto.
                eapply Int.one_not_zero.
                simpl. eapply star_step.
                eapply exec_Istore; eauto. instantiate (1:= ta). rewrite <- XYY.
                erewrite (regs_rewrite_one _ _ _ _ reg0 HK I0); eauto.
                erewrite regs_rewrite_one'; eauto.
                erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HG r X)) I1).
                erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HD r X)) I2).
                erewrite regs_rewrite_one'; eauto.
                rewrite HK; eauto. rewrite PMap.gso; eauto.
                rewrite <- HG; eauto. rewrite <- HD; eauto. rewrite PMap.gso; eauto.
                eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto.
              * eauto.
            + eauto.
          - econstructor; eauto.
            + unfold regs_agree; intros.
              destruct (plt (max_reg_function f) r).
              * right; split; auto.
                rewrite UNDEF; auto.
              * left; split; try xomega. destruct (peq r reg0); try xomega.
                rewrite HK; auto. rewrite PMap.gso; auto.
                rewrite <- HG; auto. generalize (HC r).
                intros [[X Y] | [X Y]]; try xomega; auto.
            + intros. generalize (STEP s0 H21). intros [t X].
              exists (t ** E0). eapply star_right; eauto.
              eapply exec_Istore_block'; eauto.
            + intros. generalize (STEP' s0 H21). intros [t X].
              exists (t ** E0). eapply star_trans; eauto.
              eapply star_step.
              * eapply exec_Inop; eauto.
              * eapply star_step.
                { eapply exec_Iop; eauto.
                  destruct addr; simpl; eauto.
                  destruct (Int.eq_dec i Int.zero); simpl; eauto.
                  simpl in XYY. subst i. destruct trs##args; auto.
                  destruct l; auto. rewrite <- XYY. inv XYY.
                  unfold Mem.storev in ZA. destruct v; simpl in ZA; inv ZA.
                  simpl. rewrite Int.add_zero. reflexivity. }
                { eapply star_trans.
                  eapply HA. eapply star_trans. eapply HE.
                  eapply star_step. eapply exec_Iop; eauto.
                  simpl; eauto. eapply star_trans.
                  rewrite XY. eapply HI.
                  eapply star_step. eapply exec_Icond; eauto.
                  simpl; rewrite HJ; simpl. rewrite Int.eq_false; simpl; auto.
                  eapply Int.one_not_zero.
                  simpl. eapply star_step.
                  eapply exec_Istore; eauto. instantiate (1:= ta). rewrite <- XYY.
                  erewrite (regs_rewrite_one _ _ _ _ reg0 HK I0); eauto.
                  erewrite regs_rewrite_one'; eauto.
                  erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HG r X)) I1).
                  erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HD r X)) I2).
                  erewrite regs_rewrite_one'; eauto.
                  rewrite HK; eauto. rewrite PMap.gso; eauto.
                  rewrite <- HG; eauto. rewrite <- HD; eauto. rewrite PMap.gso; eauto.
                  eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto. }
                { eauto. }
              * eauto.
            + unfold Mem.storev in ZA; destruct ta; inv ZA.
              erewrite Mem.nextblock_store; eauto.
            + unfold Mem.storev in ZA; destruct ta; inv ZA.
              erewrite Mem.nextblock_store; eauto.
            + unfold Mem.range_perm; intros.
              unfold Mem.storev in ZA. destruct ta; inv ZA.
              eapply Mem.perm_store_1; eauto. eapply STKPERM in H21.
              unfold Mem.range_perm in H21. eapply H21; eauto.
            + unfold Mem.range_perm; intros.
              unfold Mem.storev in ZA. destruct ta; inv ZA.
              eapply Mem.perm_store_1; eauto. eapply SIZEPERM in H21.
              unfold Mem.range_perm in H21. eapply H21; eauto.
            + intros. eapply STKRANGE in H21. rewrite <- H21.
              split; intros.
              * unfold Mem.storev in *. destruct ta; inv ZA; eauto.
                eapply Mem.perm_store_2; eauto.
              * unfold Mem.storev in *. destruct ta; inv ZA; eauto.
                eapply Mem.perm_store_1; eauto.
            + intros. eapply SIZERANGE in H21. rewrite <- H21.
              split; intros.
              * unfold Mem.storev in *. destruct ta; inv ZA; eauto.
                eapply Mem.perm_store_2; eauto.
              * unfold Mem.storev in *. destruct ta; inv ZA; eauto.
                eapply Mem.perm_store_1; eauto.
            + unfold Mem.storev in H2. destruct a; inv H2.
              exploit Mem.nextblock_store; eauto. intros BVC; rewrite BVC; auto.
            + unfold Mem.storev in ZA. destruct ta; inv ZA.
              exploit Mem.nextblock_store; eauto. intros BVC; rewrite BVC; auto.
            + unfold Mem.storev in ZA; destruct ta; inv ZA.
              unfold Mem.storev in H2; destruct a; inv H2.
              inversion YYX; subst. destruct SIZE_exists as [bSIZE [HSIZE HSIZE']].
              destruct STK_exists as [bSTK [HSTK HSTK']].
              eapply shadowstack_is_sound_store; eauto.
              * eapply SIZENOTMAPPED; eauto. unfold Genv.symbol_address; rewrite HSIZE; eauto.
              * eapply STKNOTMAPPED; eauto. unfold Genv.symbol_address; rewrite HSTK; eauto.
            + intros; split.
              * intros. destruct a; inv H2.
                destruct ta; inv ZA.
                eapply Mem.perm_store_2 in H22; eauto.
                eapply Mem.perm_store_1; eauto. eapply FLATPERM; eauto.
              * intros. destruct a; inv H2.
                destruct ta; inv ZA.
                eapply Mem.perm_store_2 in H22; eauto.
                eapply Mem.perm_store_1; eauto. eapply FLATPERM; eauto. }
        { generalize (RTLdefgenspec.list_forall2_not_in' _ _ _ _ _ reg0 Vfalse HF H18). intros HH.
          generalize (regs_are_bools' _ _ _ _ _ _ _ _ ZA HH AC UUU). intros AD.
          destruct (Classical_Prop.classic (exists r, In r (reg1::regs') /\ (trs''#reg0 <- Vfalse)#r = Vtrue)).
          { rename H20 into AE.
            assert (AF: trs''#reg0 <- (Vfalse)#reg0 = Vfalse).
            { rewrite PMap.gss; reflexivity. }
            apply not_in_cons in H18. destruct H18.
            assert (AE': exists r, In r regs' /\ (trs''#reg0 <- Vfalse)#r = Vtrue).
            { destruct AE as [r [AE1 AE2]]. simpl in AE1. destruct AE1 as [AE1 | AE1].
              - subst r. rewrite PMap.gso in AE2; try congruence. rewrite XY in AE2. inv AE2.
              - exists r; split; try assumption. }
            generalize (tr_or_regs_correct tstk tf tm _ (Psucc pc4) reg0 pc5 pcs3 tsp0 (trs'' # reg0 <- (Vint Int.zero)) H8 (fun r H => AD r (in_cons _ _ _ H)) H20 AE' (or_intror AF)). intros [trs''' [HI [HJ HK]]].
            eexists; split.
            - eapply plus_left.
              + eapply exec_Inop; eauto.
              + eapply star_step.
                * eapply exec_Iop; eauto.
                  destruct addr; simpl; eauto.
                  destruct (Int.eq_dec i Int.zero); simpl; eauto.
                  simpl in XYY. subst i. destruct trs##args; auto.
                  destruct l; auto. rewrite <- XYY. inv XYY.
                  unfold Mem.storev in ZA. destruct v; simpl in ZA; inv ZA.
                  simpl. rewrite Int.add_zero. reflexivity.
                * eapply star_trans.
                  eapply HA. eapply star_trans. eapply HE.
                  eapply star_step. eapply exec_Iop; eauto.
                  simpl; eauto. eapply star_trans.
                  rewrite XY. unfold Vfalse. eapply HI.
                  eapply star_step. eapply exec_Icond; eauto.
                  simpl; rewrite HJ; simpl. rewrite Int.eq_false; simpl; auto.
                  eapply Int.one_not_zero.
                  simpl. eapply star_step.
                  eapply exec_Istore; eauto. instantiate (1:= ta). rewrite <- XYY.
                  erewrite (regs_rewrite_one _ _ _ _ reg0 HK I0); eauto.
                  erewrite regs_rewrite_one'; eauto.
                  erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HG r X)) I1).
                  erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HD r X)) I2).
                  erewrite regs_rewrite_one'; eauto.
                  rewrite HK; eauto. rewrite PMap.gso; eauto.
                  rewrite <- HG; eauto. rewrite <- HD; eauto. rewrite PMap.gso; eauto.
                  eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto.
                * eauto.
              + eauto.
            - econstructor; eauto.
              + unfold regs_agree; intros.
                destruct (plt (max_reg_function f) r).
                * right; split; auto.
                  rewrite UNDEF; auto.
                * left; split; try xomega. destruct (peq r reg0); try xomega.
                  rewrite HK; auto. rewrite PMap.gso; auto.
                  rewrite <- HG; auto. generalize (HC r).
                  intros [[X Y] | [X Y]]; try xomega; auto.
              + intros. generalize (STEP s0 H21). intros [t X].
                exists (t ** E0). eapply star_right; eauto.
                eapply exec_Istore_block'; eauto.
              + intros. generalize (STEP' s0 H21). intros [t X].
                exists (t ** E0). eapply star_trans; eauto.
                eapply star_step.
                * eapply exec_Inop; eauto.
                * eapply star_step.
                  { eapply exec_Iop; eauto.
                    destruct addr; simpl; eauto.
                    destruct (Int.eq_dec i Int.zero); simpl; eauto.
                    simpl in XYY. subst i. destruct trs##args; auto.
                    destruct l; auto. rewrite <- XYY. inv XYY.
                    unfold Mem.storev in ZA. destruct v; simpl in ZA; inv ZA.
                    simpl. rewrite Int.add_zero. reflexivity. }
                  { eapply star_trans.
                    eapply HA. eapply star_trans. eapply HE.
                    eapply star_step. eapply exec_Iop; eauto.
                    simpl; eauto. eapply star_trans.
                    rewrite XY. eapply HI.
                    eapply star_step. eapply exec_Icond; eauto.
                    simpl; rewrite HJ; simpl. rewrite Int.eq_false; simpl; auto.
                    eapply Int.one_not_zero.
                    simpl. eapply star_step.
                    eapply exec_Istore; eauto. instantiate (1:= ta). rewrite <- XYY.
                    erewrite (regs_rewrite_one _ _ _ _ reg0 HK I0); eauto.
                    erewrite regs_rewrite_one'; eauto.
                    erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HG r X)) I1).
                    erewrite (regs_rewrite_list _ _ _ _ _ (fun r X => eq_sym (HD r X)) I2).
                    erewrite regs_rewrite_one'; eauto.
                    rewrite HK; eauto. rewrite PMap.gso; eauto.
                    rewrite <- HG; eauto. rewrite <- HD; eauto. rewrite PMap.gso; eauto.
                    eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto. }
                  { eauto. }
                * eauto.
              + unfold Mem.storev in ZA; destruct ta; inv ZA.
                erewrite Mem.nextblock_store; eauto.
              + unfold Mem.storev in ZA; destruct ta; inv ZA.
                erewrite Mem.nextblock_store; eauto.
              + unfold Mem.range_perm; intros.
                unfold Mem.storev in ZA. destruct ta; inv ZA.
                eapply Mem.perm_store_1; eauto. eapply STKPERM in H21.
                unfold Mem.range_perm in H21. eapply H21; eauto.
              + unfold Mem.range_perm; intros.
                unfold Mem.storev in ZA. destruct ta; inv ZA.
                eapply Mem.perm_store_1; eauto. eapply SIZEPERM in H21.
                unfold Mem.range_perm in H21. eapply H21; eauto.
              + intros. eapply STKRANGE in H21. rewrite <- H21.
                split; intros.
                * unfold Mem.storev in *. destruct ta; inv ZA; eauto.
                  eapply Mem.perm_store_2; eauto.
                * unfold Mem.storev in *. destruct ta; inv ZA; eauto.
                  eapply Mem.perm_store_1; eauto.
              + intros. eapply SIZERANGE in H21. rewrite <- H21.
                split; intros.
                * unfold Mem.storev in *. destruct ta; inv ZA; eauto.
                  eapply Mem.perm_store_2; eauto.
                * unfold Mem.storev in *. destruct ta; inv ZA; eauto.
                  eapply Mem.perm_store_1; eauto.
              + unfold Mem.storev in H2; destruct a; inv H2.
                exploit Mem.nextblock_store; eauto. intros ABC; rewrite ABC; auto.
              + unfold Mem.storev in ZA; destruct ta; inv ZA.
                exploit Mem.nextblock_store; eauto. intros ABC; rewrite ABC; auto.
              + unfold Mem.storev in ZA; destruct ta; inv ZA.
                unfold Mem.storev in H2; destruct a; inv H2.
                inversion YYX; subst. destruct SIZE_exists as [bSIZE [HSIZE HSIZE']].
                destruct STK_exists as [bSTK [HSTK HSTK']].
                eapply shadowstack_is_sound_store; eauto.
                * eapply SIZENOTMAPPED; eauto. unfold Genv.symbol_address; rewrite HSIZE; eauto.
                * eapply STKNOTMAPPED; eauto. unfold Genv.symbol_address; rewrite HSTK; eauto.
              + intros; split.
                * intros. destruct a; inv H2.
                  destruct ta; inv ZA.
                  eapply Mem.perm_store_2 in H22; eauto.
                  eapply Mem.perm_store_1; eauto. eapply FLATPERM; eauto.
                * intros. destruct a; inv H2.
                  destruct ta; inv ZA.
                  eapply Mem.perm_store_2 in H22; eauto.
                  eapply Mem.perm_store_1; eauto. eapply FLATPERM; eauto. }
          { rename H20 into AE. generalize (Classical_Pred_Type.not_ex_all_not _ _ AE). intros AE'.
            assert (Hall: forall r, In r (reg1::regs') -> (trs''#reg0 <- Vfalse)#r = Vfalse).
            { intros. destruct (AD _ H20); auto.
              exfalso; eapply AE'; split; eauto. }
            exploit tr_or_regs_false; eauto. eapply not_in_cons in H18. destruct H18; auto.
            intros; eapply Hall; right; auto. eapply PMap.gss.
            intros [trs''' [Hstar [Hfalse Htrs''']]].
            assert (exists t, program_behaves (semantics tprog) (Goes_wrong t)).
            - inv H11.
              destruct init_state_exists' as [s0 Hinit].
              generalize (STEP' _ Hinit). intros [t Hstep].
              eexists. econstructor; eauto.
              econstructor. eapply star_trans; eauto.
              eapply star_step. eapply exec_Inop; eauto.
              eapply star_step. eapply exec_Iop; eauto.
              destruct addr; simpl; eauto.
              destruct (Int.eq_dec i Int.zero); simpl; eauto.
              simpl in XYY. subst i. destruct trs##args; auto.
              destruct l; auto. rewrite <- XYY. inv XYY.
              unfold Mem.loadv in ZA. destruct v; simpl in ZA; inv ZA.
              simpl; auto. simpl; rewrite Int.add_zero. reflexivity.
              eapply star_trans. eapply HA.
              eapply star_trans. eapply HE.
              eapply star_step. eapply exec_Iop; eauto.
              simpl. eauto. eapply star_trans. rewrite XY.
              eapply Hstar. eapply star_step. eapply exec_Icond; eauto.
              simpl. rewrite Hfalse; simpl. rewrite Int.eq_true. simpl; eauto.
              simpl. eapply star_step. eapply exec_Iop; eauto. simpl. eauto.
              eapply star_one. eapply exec_Iop; eauto. simpl; eauto.
              eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
              red; unfold not; intros. inv H11; try congruence.
              rewrite H32 in H22; inv H22. simpl in H33.
              rewrite PMap.gss in H33; rewrite PMap.gso in H33; auto. rewrite PMap.gss in H33; simpl in H33.
              rewrite Int.eq_true in H33; simpl in H33; inv H33.
              unfold not; intros. inv H11.
            - destruct H20. eapply DEFSAFE in H20; inv H20. } } }
      { eapply not_in_cons in H18. destruct H18 as [NA NA'].
        assert (CN: trs'' # reg0 <- (trs'' # reg1) # reg0 = Vundef) by (rewrite PMap.gss; eauto).
        generalize (tr_or_regs_undef tstk _ tm _ _ _ _ _ tsp0 _ H8 NA' CN). intros [trs''' [Hstar [Hundef Htrs''']]].
        assert (exists t, program_behaves (semantics tprog) (Goes_wrong t)).
        - destruct init_state_exists' as [s0 Hinit].
          generalize (STEP' _ Hinit). intros [t Hstep].
          eexists. econstructor; eauto.
          econstructor. eapply star_trans; eauto.
          eapply star_step. eapply exec_Inop; eauto.
          eapply star_step. eapply exec_Iop; eauto.
          destruct addr; simpl; eauto.
          destruct (Int.eq_dec i Int.zero); simpl; eauto.
          simpl in XYY. subst i. destruct trs##args; auto.
          destruct l; auto. rewrite <- XYY. inv XYY.
          unfold Mem.loadv in ZA. destruct v; simpl in ZA; inv ZA.
          simpl; auto. simpl; rewrite Int.add_zero. reflexivity.
          eapply star_trans. eapply HA.
          eapply star_trans. eapply HE.
          eapply star_step. eapply exec_Iop; eauto.
          simpl. eauto. eapply star_trans. eapply Hstar.
          eapply star_refl. eauto. eauto. eauto. eauto. eauto. eauto.
          red; unfold not; intros. inv H14; try congruence.
          rewrite H27 in H9; inv H9. simpl in H28. rewrite Hundef in H28. simpl in H28.
          inv H28.
          unfold not; intros. inv H14.
        - destruct H14. eapply DEFSAFE in H14; inv H14. }
    Grab Existential Variables. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero.
  Qed.

  Theorem simulation:
    forall s1 t s1', step_block' ge s1 t s1' ->
                forall s2, match_states s1 s2 ->
                      exists s2', plus step tge s2 t s2' /\ match_states s1' s2'.
Proof.
    induction 1; intros.
    - inv H0. generalize (transf_function_spec _ _ _ _ _ _ FUN H). intros [pcs A].
      eexists; split.
      + eapply plus_one. eapply exec_Inop. inv A; eauto.
      + econstructor; eauto.
        * intros. generalize (STEP s0 H0). intros [t S].
          exists t. eapply star_right; eauto.
          { eapply exec_Inop_block; eauto. }
          { rewrite E0_right; reflexivity. }
        * intros. generalize (STEP' s0 H0). intros [t S].
          exists t. eapply star_right; eauto.
          { inv A. eapply exec_Inop; eauto. }
          { rewrite E0_right; reflexivity. }
    - inv H1. generalize (transf_function_spec _ _ _ _ _ _ FUN H). intros [pcs A].
      assert (HA: exists tv, eval_operation tge (Vptr tsp Int.zero) op trs##args tm = Some tv /\ Val.inject j v tv).
      { apply eval_operation_inj with (ge1 := ge) (m1 := m) (sp1 := Vptr sp0 Int.zero) (vl1 := rs##args).
        - intros; eapply Mem.valid_pointer_inject_val; eauto.
        - intros; eapply Mem.weak_valid_pointer_inject_val; eauto.
        - intros; eapply Mem.weak_valid_pointer_inject_no_overflow; eauto.
        - intros; eapply Mem.different_pointers_inject; eauto.
        - intros; eapply symbol_address_inject; eauto.
          intros; eapply GINJ_implies; eauto.
        - eauto.
        - eapply regs_agree_ple; eauto.
          intros; eapply max_reg_function_use'; eauto.
        - exact H0. }
      destruct HA as [tv [HA HB]].
      eexists; split.
      + inv A. eapply plus_one. eapply exec_Iop; eauto.
      + econstructor; eauto.
        * generalize (max_reg_function_def _ _ _ res H eq_refl). intros B.
          eapply regs_agree_update; eauto.
        * intros. generalize (STEP s0 H1). intros [t S].
          exists t. eapply star_right; eauto.
          { eapply exec_Iop_block'; eauto. }
          { rewrite E0_right; reflexivity. }
        * intros. generalize (STEP' s0 H1). intros [t S].
          exists (t ** E0). eapply star_right; eauto.
          inv A. eapply exec_Iop; eauto.
        * intros. generalize (max_reg_function_def f _ _ res H eq_refl). intro.
          rewrite PMap.gso; eauto. xomega.
    - inv H3. generalize (transf_function_spec _ _ _ _ _ _ FUN H). intros [pcs A].
      eapply load_checks_are_correct; eauto.
      econstructor; eauto.
    - inv H3. generalize (transf_function_spec _ _ _ _ _ _ FUN H). intros [pcs A].
      eapply store_checks_are_correct; eauto.
      econstructor; eauto.
    - inv H2. generalize (transf_function_spec _ _ _ _ _ _ FUN H). intros [pcs A].
      inv A. exploit find_function_translated; eauto.
      { destruct ros.
        - simpl in H0. generalize (RES r); intros [[HA HB] | [HA HB]].
          + generalize (Genv.find_funct_inv _ _ H0). intros [b HC]. rewrite HC in H0.
            rewrite Genv.find_funct_find_funct_ptr in H0. eapply ge.(Genv.genv_funs_range) in H0.
            eapply GINJ in H0. rewrite HC in HB. inv HB. rewrite H0 in H4; inv H4.
            rewrite Int.add_zero_l. exact HC.
          + generalize (max_reg_function_use' _ _ _ H r (in_eq _ _)). intros. xomega.
        - simpl in H0. case_eq (Genv.find_symbol ge i); intros; rewrite H1 in H0; inv H0.
          eapply STK_SIZE_are_new; eauto. }
      intros [tfd [B C]].
      eexists; split.
      + eapply plus_one. eapply exec_Icall; eauto.
        eapply sig_function_translated; eauto.
      + econstructor; eauto.
        * econstructor; eauto.
          econstructor; eauto. eapply max_reg_function_def; eauto.
        * intros. generalize (STEP s0 H1). intros [t S].
          exists t. eapply star_right; eauto.
          { eapply exec_Icall_block'; eauto. }
          { rewrite E0_right; reflexivity. }
        * intros. generalize (STEP' s0 H1). intros [t S].
          exists (t ** E0). eapply star_right; eauto.
          eapply exec_Icall; eauto.
          eapply sig_function_translated; eauto.
        * eapply regs_agree_inject_list; eauto.
          intros; eapply max_reg_function_use'; simpl; eauto.
          simpl; destruct ros; eauto. eapply in_cons; eauto.
    - inv H3. generalize (transf_function_spec _ _ _ _ _ _ FUN H). intros [pcs A].
      inv A. exploit find_function_translated; eauto.
      { destruct ros.
        - simpl in H0. generalize (RES r); intros [[HA HB] | [HA HB]].
          + generalize (Genv.find_funct_inv _ _ H0). intros [b HC]. rewrite HC in H0.
            rewrite Genv.find_funct_find_funct_ptr in H0. eapply ge.(Genv.genv_funs_range) in H0.
            eapply GINJ in H0. rewrite HC in HB. inv HB. rewrite H0 in H5; inv H5.
            rewrite Int.add_zero_l. exact HC.
          + generalize (max_reg_function_use' _ _ _ H r (in_eq _ _)). intros. xomega.
        - simpl in H0. case_eq (Genv.find_symbol ge i); intros; rewrite H1 in H0; inv H0.
          eapply STK_SIZE_are_new; eauto. }
      intros [tfd [B C]]. inv H10.
      inv SHADOW. destruct H10 as [Z H10]. generalize ((proj1 (H10 O _)) eq_refl); intros ZZ.
      unfold Mem.loadv in Z.
      case_eq (Genv.symbol_address tge SIZE Int.zero); intros; rewrite H12 in Z; inv Z. simpl.
      generalize (Mem.valid_access_store tm Mint32 b (Int.unsigned i) (Vint (Int.sub (Int.repr (4 * (Z.pos (Pos.of_succ_nat (length (map (fun s0 : stackframe => match s0 with | Stackframe _ _ sp _ _ => sp end) ts))) - 1))) (Int.repr 4)))).
      intros ZZZ; destruct ZZZ.
      { unfold Mem.valid_access; split.
        - simpl. unfold Mem.range_perm; intros.
          unfold Genv.symbol_address in H12. case_eq (Genv.find_symbol tge SIZE); intros; rewrite H15 in H12; inv H12.
          eapply SIZEPERM; eauto.
        - unfold Genv.symbol_address in H12. case_eq (Genv.find_symbol tge SIZE); intros; rewrite H13 in H12; inv H12.
          simpl. rewrite Int.unsigned_zero. exists 0. omega. }
      exploit (Mem.store_outside_inject j m tm Mint32 b (Int.unsigned i) (Vint (Int.sub (Int.repr (4 * (Z.pos (Pos.of_succ_nat (length (map (fun s0 : stackframe => match s0 with | Stackframe _ _ sp _ _ => sp end) ts))) - 1))) (Int.repr 4))) x MINJ).
      { intros. eapply SIZENOTMAPPED; eauto. unfold Genv.symbol_address in H12. unfold Genv.symbol_address.
        destruct (Genv.find_symbol tge SIZE); inv H12; eauto. }
      { exact e. } intros YYY.
      generalize (Mem.free_parallel_inject j m x stk 0 (fn_stacksize f) m' tsp 0 YYY H2 SPINJ). intros [tm' [ZU UZ]].
      eexists; split.
      + econstructor.
        * eapply exec_Inop; eauto.
        * eapply star_step.
          { eapply exec_Iload.
            - eauto.
            - simpl. eauto.
            - unfold SIZE in H12.
              rewrite H12; simpl; eauto. }
          { eapply star_step.
            - eapply exec_Iop; eauto.
              simpl. eauto.
            - eapply star_step.
              + eapply exec_Iop; eauto.
                simpl. eauto.
              + eapply star_step.
                * rewrite PMap.gso; eauto. rewrite PMap.gss. rewrite PMap.gss.
                  eapply exec_Istore; eauto.
                  { simpl. eauto. }
                  { simpl. rewrite PMap.gss. unfold Mem.storev.
                    unfold SIZE in H12.
                    rewrite H12. eapply e. }
                * eapply star_step.
                  { eapply exec_Itailcall.
                    - eauto.
                    - instantiate (1 := tfd). destruct ros; simpl.
                      + repeat rewrite PMap.gso; eauto.
                        * generalize (max_reg_function_use' _ _ _ H r0 (in_eq _ _)). intros; xomega.
                        * generalize (max_reg_function_use' _ _ _ H r0 (in_eq _ _)). intros; xomega.
                        * generalize (max_reg_function_use' _ _ _ H r0 (in_eq _ _)). intros; xomega.
                      + eapply B.
                    - eapply sig_function_translated; eauto.
                    - erewrite stacksize_translated; eauto.
                      repeat rewrite Z.add_0_r in ZU. eauto. }
                  { eapply star_refl. }
                  { eauto. }
                * eauto.
              + eauto.
            - eauto. }
          { eauto. }
        * eauto.
      + econstructor; eauto.
        * intros. generalize (STEP s0 H13). intros [t S].
          exists t. eapply star_right; eauto.
          { eapply exec_Itailcall_block'; eauto. }
          { rewrite E0_right; reflexivity. }
        * intros. generalize (STEP' s0 H13). intros [t S].
          eexists. eapply star_trans; eauto.
          { eapply star_step.
            * eapply exec_Inop; eauto.
            * eapply star_step.
              { eapply exec_Iload.
                - eauto.
                - simpl. eauto.
                - unfold SIZE in H12.
                  rewrite H12; simpl; eauto. }
              { eapply star_step.
                - eapply exec_Iop; eauto.
                  simpl. eauto.
                - eapply star_step.
                  + eapply exec_Iop; eauto.
                    simpl. eauto.
                  + eapply star_step.
                    * rewrite PMap.gso; eauto. rewrite PMap.gss. rewrite PMap.gss.
                      eapply exec_Istore; eauto.
                      { simpl. eauto. }
                      { simpl. rewrite PMap.gss. unfold Mem.storev.
                        unfold SIZE in H12.
                        rewrite H12. eapply e. }
                    * eapply star_step.
                      { eapply exec_Itailcall.
                        - eauto.
                        - instantiate (1 := tfd). destruct ros; simpl.
                          + repeat rewrite PMap.gso; eauto.
                            * generalize (max_reg_function_use' _ _ _ H r0 (in_eq _ _)). intros; xomega.
                            * generalize (max_reg_function_use' _ _ _ H r0 (in_eq _ _)). intros; xomega.
                            * generalize (max_reg_function_use' _ _ _ H r0 (in_eq _ _)). intros; xomega.
                          + eapply B.
                        - eapply sig_function_translated; eauto.
                        - erewrite stacksize_translated; eauto.
                          repeat rewrite Z.add_0_r in ZU. eauto. }
                      { eapply star_refl. }
                      { eauto. }
                    * eauto.
                  + eauto.
                - eauto. }
              { eauto. }
            * eauto. }
        * erewrite (Mem.nextblock_free _ _ _ _ _ ZU); eauto.
          erewrite Mem.nextblock_store; eauto.
        * erewrite (Mem.nextblock_free _ _ _ _ _ ZU); eauto.
          erewrite Mem.nextblock_store; eauto.
        * eapply regs_agree_inject_list; eauto.
          { instantiate (1 := max_reg_function f). intros; eapply max_reg_function_use'; eauto. simpl.
            destruct ros; eauto. eapply in_cons; eauto. }
          { unfold regs_agree; intros. generalize (RES r0); intros [[UR RU] | [UR RU]].
            - left; split; eauto.
              repeat rewrite PMap.gso; eauto; try xomega.
            - right; split; eauto.
              rewrite UNDEF; eauto. }
        * unfold Mem.range_perm in *; intros.
          eapply Mem.perm_free_1; eauto.
          { left. eapply not_eq_sym. eapply STKNOTMAPPED; eauto.
            unfold Genv.symbol_address; rewrite H13. eauto. }
          { eapply Mem.perm_store_1; eauto. }
        * unfold Mem.range_perm in *; intros.
          eapply Mem.perm_free_1; eauto.
          { left. eapply not_eq_sym. eapply SIZENOTMAPPED; eauto.
            unfold Genv.symbol_address; rewrite H13. eauto. }
          { eapply Mem.perm_store_1; eauto. }
        * intros. split.
          { intros. eapply STKRANGE; eauto.
            eapply Mem.perm_store_2; eauto.
            eapply Mem.perm_free_3; eauto. }
          { intros. eapply Mem.perm_free_1; eauto.
            - left. eapply not_eq_sym. eapply STKNOTMAPPED; eauto.
              unfold Genv.symbol_address; rewrite H13. eauto.
            - eapply Mem.perm_store_1; eauto.
              eapply STKRANGE; eauto. }
        * intros. split.
          { intros. eapply SIZERANGE; eauto.
            eapply Mem.perm_store_2; eauto.
            eapply Mem.perm_free_3; eauto. }
          { intros. eapply Mem.perm_free_1; eauto.
            - left. eapply not_eq_sym. eapply SIZENOTMAPPED; eauto.
              unfold Genv.symbol_address; rewrite H13. eauto.
            - eapply Mem.perm_store_1; eauto.
              eapply SIZERANGE; eauto. }
        * clear NEXTBLOCK'. erewrite Mem.nextblock_free; eauto.
        * erewrite Mem.nextblock_free with (m1 := x); eauto.
          erewrite Mem.nextblock_store; eauto.
        * econstructor; eauto. intros. split.
          { unfold Mem.loadv. rewrite H12.
            erewrite Mem.load_free; eauto.
            - erewrite Mem.load_store_same; eauto. fold n. simpl.
              f_equal. f_equal. rewrite repr_sub. f_equal. Psatz.lia.
            - simpl. left. eapply not_eq_sym. eapply SIZENOTMAPPED. unfold Genv.symbol_address in H12.
              unfold Genv.symbol_address. destruct (Genv.find_symbol tge SIZE); inv H12; eauto.
              exact SPINJ. }
          { split; intros.
            - generalize (proj1 (H10 (S depth) sp) H13). intros [HO H15]. split; try eapply pop_length; eauto.
              rewrite <- H15. cutrewrite <- ((Val.add (Genv.symbol_address tge STK (Int.repr (-4 * Z.of_nat depth))) (Vint (Int.repr (4 * (Z.of_nat n - 1))))) = (Val.add (Genv.symbol_address tge STK (Int.repr (-4 * Z.of_nat (S depth)))) (Vint (Int.repr (4 * (Z.of_nat (length (Vptr tsp Int.zero :: map (fun s0 : stackframe => match s0 with | Stackframe _ _ sp0 _ _ => sp0 end) ts)) - 1)))))).
              + destruct STK_exists as [bSTK [U V]].
                unfold Genv.symbol_address. rewrite U. unfold Mem.loadv. simpl.
                erewrite Mem.load_free with (m1 := x); eauto.
                * erewrite Mem.load_store_other; eauto.
                  left. intro. unfold Genv.symbol_address in H12.
                  case_eq (Genv.find_symbol tge SIZE); intros; rewrite H17 in H12; inv H12.
                  generalize (tge.(Senv.find_symbol_injective) STK SIZE U H17). intros.
                  unfold SIZE in H12. eapply Pos.succ_discr; eauto.
                * left. eapply not_eq_sym. eapply STKNOTMAPPED; eauto.
                  unfold Genv.symbol_address; rewrite U. eauto.
              + unfold Genv.symbol_address. destruct (Genv.find_symbol tge STK); simpl; eauto.
                f_equal. repeat rewrite repr_add. f_equal. unfold n. Psatz.lia.
            - destruct H13 as [HO H13]. unfold Genv.symbol_address in H10, H13. destruct STK_exists as [bSTK [LA LA']].
              rewrite LA in H10, H13. simpl in H10, H13.
              erewrite Mem.load_free in H13; eauto.
              + erewrite Mem.load_store_other in H13; eauto.
                * replace (pop depth (map (fun s0 => match s0 with | Stackframe _ _ sp0 _ _ => sp0 end) ts)) with (pop (S depth) (Vptr tsp Int.zero :: map (fun s0 => match s0 with | Stackframe _ _ sp0 _ _ => sp0 end) ts)); try reflexivity.
                  eapply H10. split; try omega. rewrite <- H13; f_equal; auto.
                  rewrite ! repr_add. rewrite ! Int.unsigned_repr_eq.
                  f_equal; eauto. simpl. unfold n. Psatz.lia.
                * left. eapply STK_not_SIZE; eauto.
                  unfold Genv.symbol_address in H12; destruct (Genv.find_symbol tge SIZE); inv H12; auto.
              + left. eapply not_eq_sym. eapply STKNOTMAPPED; eauto.
                unfold Genv.symbol_address; rewrite LA; eauto. }
        * xomega.
        * intros; split; intros.
          { eapply Mem.perm_free_1; eauto.
            - destruct (peq b' tsp); auto. right.
              subst b'. generalize (FLATINJ' _ _ _ H13 SPINJ). intros LOL.
              subst b0. generalize (Mem.perm_free_2 _ _ _ _ _ H2). intros LOL.
              destruct (zlt o 0); auto.
              destruct (zle (fn_stacksize f) o); auto.
              + right; auto. omega.
              + exfalso. eapply LOL; eauto. omega.
            - eapply Mem.perm_store_1; eauto.
              eapply Mem.perm_free_3 in H15; eauto. eapply FLATPERM; eauto. }
          { eapply Mem.perm_free_1; eauto.
            - destruct (peq b0 stk); auto. right.
              subst b0. rewrite SPINJ in H13; inv H13.
              generalize (Mem.perm_free_2 _ _ _ _ _ ZU). intros LOL.
              destruct (zlt o 0); auto.
              destruct (zle (fn_stacksize f) o); auto.
              exfalso. eapply LOL; eauto. omega.
            - eapply Mem.perm_free_3 in H15; eauto.
              eapply Mem.perm_store_2 in H15; eauto. eapply FLATPERM; eauto. }
    - inv H2. generalize (transf_function_spec _ _ _ _ _ _ FUN H). intros [pcs A].
      exploit eval_builtin_args_inject; eauto.
      { unfold not; intros.
        destruct H3 as [H3 | [H3 | H3]].
        - subst id. inv A. eapply H12; eauto.
        - subst id. inv A. eapply H13; eauto.
        - inv H3. }
      { intros. eapply max_reg_function_use'; eauto. }
      intros [tvl [HA HB]].
      exploit external_call_mem_inject_gen'; eauto.
      { instantiate (1 := tge). econstructor; eauto.
        - intros. unfold Senv.public_symbol; simpl.
          symmetry. eapply public_preserved'.
        - repeat split.
          + unfold Senv.find_symbol in H3; simpl in H3.
            exploit Genv.genv_symb_range; eauto.
          + unfold Senv.find_symbol in H3; simpl in H3.
            exploit Genv.genv_symb_range; eauto. intros Q. eapply GINJ in Q.
            rewrite H2 in Q; inv Q. unfold Senv.find_symbol; simpl. eapply symbols_preserved'; eauto.
          + intros. unfold Senv.find_symbol in H3; simpl in H3.
            exploit Genv.genv_symb_range; eauto. intros Q. eapply GINJ in Q.
            exists b1; split; eauto. eapply symbols_preserved'; eauto.
          + intros. unfold Senv.block_is_volatile; simpl.
            unfold Genv.block_is_volatile. case_eq (Genv.find_var_info ge b1); intros.
            * exploit Genv.genv_vars_range; eauto. intros Q. eapply GINJ in Q.
              rewrite H2 in Q; inv Q. exploit varinfo_preserved; eauto. intros Q.
              rewrite Q. auto.
            * case_eq (Genv.find_var_info tge b2); intros; auto.
              generalize TRANSF'; intros TRANSF'.
              exploit Genv.find_var_info_rev_transf_augment; eauto.
              destruct (plt b2 (Genv.genv_next (Genv.globalenv prog))).
              { intros [v [X Y]]. generalize (GINJ' _ _ _ p H2). intros.
                subst b2. unfold ge in H3; congruence. }
              { simpl. intros [X | [X | X]]; inv X; eauto. } }
      intros [j' [tvres [tm' [A1 [A2 [A3 [A4 [A5 [A6 [A7 [A8 [A9 A10]]]]]]]]]]]].
      inv A. eexists; split.
      + eapply plus_one. eapply exec_Ibuiltin; eauto.
      + econstructor.
        * eapply forall_match_stackframes_inject_incr; eauto.
        * eauto.
        * unfold regmap_setres. destruct res; eauto.
          { eapply regs_agree_update; eauto.
            - eapply max_reg_function_def; eauto.
            - eapply regs_agree_inject_incr; eauto. }
          { eapply regs_agree_inject_incr; eauto. }
          { eapply regs_agree_inject_incr; eauto. }
        * intros. generalize (STEP s0 H2). intros [t' S].
          exists (t' ** t). eapply star_right; eauto.
          eapply exec_Ibuiltin_block'; eauto.
        * intros. generalize (STEP' s0 H2). intros [t' S].
          eexists. eapply star_right; eauto.
          eapply exec_Ibuiltin; eauto.
        * intros; unfold regmap_setres; destruct res.
          { generalize (max_reg_function_def f _ _ x H eq_refl). intro.
            rewrite PMap.gso; eauto. xomega. }
          { eauto. }
          { eauto. }
        * eauto.
        * eapply A6; eauto.
        * intros. eapply A6. eapply GINJ; eauto.
        * intros. case_eq (j b); intros.
          { destruct p. generalize (A6 _ _ _ H4). intros XX. rewrite XX in H3; inv H3.
            eapply STKNOTMAPPED; eauto. }
          { generalize (A7 _ _ _ H4 H3). intros [X Y].
            intro; subst b'. unfold Genv.symbol_address in H2.
            case_eq (Genv.find_symbol tge STK); intros; rewrite H5 in H2; inv H2.
            eapply STKPERM in H5. eapply Y. eapply Mem.perm_valid_block.
            eapply H5. instantiate (1 := 0); split; omega. }
        * intros. case_eq (j b); intros.
          { destruct p. generalize (A6 _ _ _ H4). intros XX. rewrite XX in H3; inv H3.
            eapply SIZENOTMAPPED; eauto. }
          { generalize (A7 _ _ _ H4 H3). intros [X Y].
            intro; subst b'. unfold Genv.symbol_address in H2.
            case_eq (Genv.find_symbol tge SIZE); intros; rewrite H5 in H2; inv H2.
            eapply SIZEPERM in H5. eapply Y. eapply Mem.perm_valid_block.
            eapply H5. instantiate (1 := 0); split; omega. }
        * intros. eapply BSTKPLT in H2. eapply external_call_valid_block; eauto.
        * intros. eapply BSIZEPLT in H2. eapply external_call_valid_block; eauto.
        * intros. unfold Mem.range_perm; intros. eapply A5; eauto.
          { unfold loc_out_of_reach. intros. exfalso. eapply STKNOTMAPPED; eauto.
            unfold Genv.symbol_address; rewrite H2; eauto. }
          { eapply BSTKPLT; eauto. }
          { eapply STKPERM; eauto. }
        * intros. unfold Mem.range_perm; intros. eapply A5; eauto.
          { unfold loc_out_of_reach. intros. exfalso. eapply SIZENOTMAPPED; eauto.
            unfold Genv.symbol_address; rewrite H2; eauto. }
          { eapply BSIZEPLT; eauto. }
          { eapply SIZEPERM; eauto. }
        * intros. split.
          { intros. inv A5. eapply unchanged_on_perm in H3.
            - eapply STKRANGE; eauto.
            - unfold loc_out_of_reach. intros. exfalso. eapply STKNOTMAPPED; eauto.
              unfold Genv.symbol_address; rewrite H2; eauto.
            - eapply BSTKPLT; eauto. }
          { intros. inv A5. eapply unchanged_on_perm; eauto.
            - unfold loc_out_of_reach. intros. exfalso. eapply STKNOTMAPPED; eauto.
              unfold Genv.symbol_address; rewrite H2; eauto.
            - eapply BSTKPLT; eauto.
            - eapply STKRANGE in H3; eauto. }
        * intros. split.
          { intros. inv A5. eapply unchanged_on_perm in H3.
            - eapply SIZERANGE; eauto.
            - unfold loc_out_of_reach. intros. exfalso. eapply SIZENOTMAPPED; eauto.
              unfold Genv.symbol_address; rewrite H2; eauto.
            - eapply BSIZEPLT; eauto. }
          { intros. inv A5. eapply unchanged_on_perm; eauto.
            - unfold loc_out_of_reach. intros. exfalso. eapply SIZENOTMAPPED; eauto.
              unfold Genv.symbol_address; rewrite H2; eauto.
            - eapply BSIZEPLT; eauto.
            - eapply SIZERANGE in H3; eauto. }
        * intros. case_eq (j b'); intros.
          { destruct p. generalize (A6 _ _ _ H4); intros.
            rewrite H5 in H3; inv H3. eapply GINJ'; eauto. }
          { generalize (A7 _ _ _ H4 H3). intros [X Y]. exfalso; eapply Y.
            eapply Mem.valid_block_inject_2 with (f := j); eauto. }
        * generalize (external_call_nextblock _ _ _ _ _ _ _ H1). intros; xomega.
        * generalize (external_call_nextblock _ _ _ _ _ _ _ A1). intros; xomega.
        * inv SHADOW. generalize STK_exists. intros [bSTK [X Y]].
          generalize SIZE_exists. intros [bSIZE [XX YY]].
          econstructor. intros. split.
          { destruct H2; auto. unfold Mem.loadv. unfold Genv.symbol_address; rewrite XX; simpl.
            unfold Mem.loadv in H2; unfold Genv.symbol_address in H2; rewrite XX in H2; simpl in H2.
            rewrite <- H2. eapply Mem.load_unchanged_on_1; eauto.
            - eapply Mem.perm_valid_block. eapply SIZEPERM; eauto.
              instantiate (1 := 0); omega.
            - rewrite ! Int.unsigned_zero. simpl. intros.
              unfold loc_out_of_reach; intros. intro. eapply SIZENOTMAPPED.
              + unfold Genv.symbol_address; rewrite XX; eauto.
              + eapply H5.
              + reflexivity. }
          { split; intros.
            - split; try (eapply pop_length; exact H3).
              unfold Genv.symbol_address; rewrite X; simpl.
              destruct H2 as [LU H2]. unfold Mem.loadv in H2; unfold Genv.symbol_address in H2; rewrite X in H2; simpl in H2.
              eapply H2 in H3. destruct H3 as [HO H3].
              rewrite <- H3. eapply Mem.load_unchanged_on_1; eauto.
              + eapply Mem.perm_valid_block. eapply STKPERM; eauto.
                instantiate (1 := 0); omega.
              + unfold loc_out_of_reach; intros. intro. eapply STKNOTMAPPED.
                * unfold Genv.symbol_address; rewrite X; eauto.
                * eapply H5.
                * reflexivity.
            - unfold Genv.symbol_address in H3, H2; rewrite X in H3, H2; simpl in H3, H2.
              destruct H2 as [LU H2]. erewrite Mem.load_unchanged_on_1 in H3; eauto.
              + eapply H2 in H3. eauto.
              + eapply Mem.perm_valid_block. eapply STKPERM; eauto.
                instantiate (1 := 0); omega.
              + unfold loc_out_of_reach; intros. intro. eapply STKNOTMAPPED.
                * unfold Genv.symbol_address; rewrite X; eauto.
                * eapply H5.
                * reflexivity. }
        * eauto.
        * eauto.
        * eauto.
        * eauto.
    - inv H2. generalize (transf_function_spec _ _ _ _ _ _ FUN H). intros [pcs A].
      generalize (regs_agree_inject_list _ _ _ _ args (max_reg_function_use' _ _ _ H) RES). intros X.
      generalize (eval_condition_inject _ X MINJ H0). intros Y.
      inv A. eexists; split.
      + eapply plus_one. eapply exec_Icond; eauto.
      + econstructor; eauto.
        * intros. generalize (STEP s0 H1). intros [t S].
          exists (t ** E0). eapply star_right; eauto.
          eapply exec_Icond_block'; eauto.
        * intros. generalize (STEP' s0 H1). intros [t S].
          exists (t ** E0). eapply star_right; eauto.
          eapply exec_Icond; eauto.
    - inv H2. generalize (transf_function_spec _ _ _ _ _ _ FUN H). intros [pcs A].
      inv A. eexists; split.
      + eapply plus_one. eapply exec_Ijumptable; eauto.
        generalize (max_reg_function_use _ _ _ arg H (or_introl eq_refl)). intros B.
        generalize (RES arg). intros [[C D] | [C D]]; try xomega.
        rewrite H0 in D. inv D. reflexivity.
      + econstructor; eauto.
        * intros. generalize (STEP s0 H2). intros [t S].
          exists (t ** E0). eapply star_right; eauto.
          eapply exec_Ijumptable_block'; eauto.
        * intros. generalize (STEP' s0 H2). intros [t S].
          exists (t ** E0). eapply star_right; eauto.
          eapply exec_Ijumptable; eauto.
          generalize (max_reg_function_use _ _ _ arg H (or_introl eq_refl)). intros B.
          generalize (RES arg). intros [[C D] | [C D]]; try xomega.
          rewrite H0 in D. inv D. reflexivity.
    - inv H1. generalize (transf_function_spec _ _ _ _ _ _ FUN H). intros [pcs A].
      inv SHADOW. destruct H1 as [Z H1]. generalize (proj1 (H1 O _) eq_refl); intros ZZ.
      unfold Mem.loadv in Z.
      case_eq (Genv.symbol_address tge SIZE Int.zero); intros; rewrite H2 in Z; inv Z.
      generalize (Mem.valid_access_store tm Mint32 b (Int.unsigned i) (Vint (Int.sub (Int.repr (4 * (Z.pos (Pos.of_succ_nat (length (map (fun s0 : stackframe => match s0 with | Stackframe _ _ sp _ _ => sp end) ts))) - 1))) (Int.repr 4)))).
      intros ZZZ; destruct ZZZ.
      { unfold Mem.valid_access; split.
        - simpl. unfold Mem.range_perm; intros.
          unfold Genv.symbol_address in H2. case_eq (Genv.find_symbol tge SIZE); intros; rewrite H5 in H2; inv H2.
          eapply SIZEPERM; eauto.
        - unfold Genv.symbol_address in H2. case_eq (Genv.find_symbol tge SIZE); intros; rewrite H3 in H2; inv H2.
          simpl. rewrite Int.unsigned_zero. exists 0. omega. }
      exploit (Mem.store_outside_inject j m tm Mint32 b (Int.unsigned i) (Vint (Int.sub (Int.repr (4 * (Z.pos (Pos.of_succ_nat (length (map (fun s0 : stackframe => match s0 with | Stackframe _ _ sp _ _ => sp end) ts))) - 1))) (Int.repr 4))) x MINJ).
      { intros. eapply SIZENOTMAPPED; eauto. unfold Genv.symbol_address in H2. unfold Genv.symbol_address.
        destruct (Genv.find_symbol tge SIZE); inv H2; eauto. }
      { exact e. } intros YYY.
      generalize (Mem.free_parallel_inject j m x stk 0 (fn_stacksize f) m' tsp 0 YYY H0 SPINJ). intros [tm' [ZU UZ]].
      inv A. inv H8. eexists; split.
      + econstructor.
        * eapply exec_Inop; eauto.
        * eapply star_step.
          { eapply exec_Iload.
            - eauto.
            - simpl. eauto.
            - unfold SIZE in H2.
              rewrite H2; simpl; eauto. }
          { eapply star_step.
            - eapply exec_Iop; eauto.
              simpl. eauto.
            - eapply star_step.
              + eapply exec_Iop; eauto.
                simpl. eauto.
              + eapply star_step.
                * rewrite PMap.gso; eauto. rewrite PMap.gss. rewrite PMap.gss.
                  eapply exec_Istore; eauto.
                  { simpl. eauto. }
                  { simpl. rewrite PMap.gss. unfold Mem.storev.
                    unfold SIZE in H2.
                    rewrite H2. eapply e. }
                * eapply star_step.
                  { eapply exec_Ireturn; eauto. rewrite ! Zplus_0_r in ZU.
                    monadInv FUN. simpl. exact ZU. }
                  { eapply star_refl. }
                  { eauto. }
                * eauto.
              + eauto.
            - eauto. }
          { eauto. }
        * eauto.
      + econstructor; eauto.
        * intros. generalize (STEP s0 H8). intros [t S].
          exists t. eapply star_right; eauto.
          { eapply exec_Ireturn_block'; eauto. }
          { rewrite E0_right; reflexivity. }
        * intros. generalize (STEP' s0 H8). intros [t S].
          eexists. eapply star_trans; eauto.
          { eapply star_step.
            * eapply exec_Inop; eauto.
            * eapply star_step.
              { eapply exec_Iload.
                - eauto.
                - simpl. eauto.
                - unfold SIZE in H2.
                  rewrite H2; simpl; eauto. }
              { eapply star_step.
                - eapply exec_Iop; eauto.
                  simpl. eauto.
                - eapply star_step.
                  + eapply exec_Iop; eauto.
                    simpl. eauto.
                  + eapply star_step.
                    * rewrite PMap.gso; eauto. rewrite PMap.gss. rewrite PMap.gss.
                      eapply exec_Istore; eauto.
                      { simpl. eauto. }
                      { simpl. rewrite PMap.gss. unfold Mem.storev.
                        unfold SIZE in H2.
                        rewrite H2. eapply e. }
                    * eapply star_step.
                      { eapply exec_Ireturn; eauto. rewrite ! Zplus_0_r in ZU.
                        monadInv FUN. simpl. exact ZU. }
                      { eapply star_refl. }
                      { eauto. }
                    * eauto.
                  + eauto.
                - eauto. }
              { eauto. }
            * eauto. }
        * erewrite (Mem.nextblock_free _ _ _ _ _ ZU); eauto.
          erewrite Mem.nextblock_store; eauto.
        * erewrite (Mem.nextblock_free _ _ _ _ _ ZU); eauto.
          erewrite Mem.nextblock_store; eauto.
        * unfold regmap_optget. destruct or; auto.
          generalize (max_reg_function_use' _ _ _ H _ (in_eq _ _)). intros.
          repeat rewrite PMap.gso; eauto; try xomega.
          generalize (RES r0). intros [[P Q] | [P Q]]; try xomega; eauto.
        * unfold Mem.range_perm in *; intros.
          eapply Mem.perm_free_1; eauto.
          { left. eapply not_eq_sym. eapply STKNOTMAPPED; eauto.
            unfold Genv.symbol_address; rewrite H8. eauto. }
          { eapply Mem.perm_store_1; eauto. }
        * unfold Mem.range_perm in *; intros.
          eapply Mem.perm_free_1; eauto.
          { left. eapply not_eq_sym. eapply SIZENOTMAPPED; eauto.
            unfold Genv.symbol_address; rewrite H8. eauto. }
          { eapply Mem.perm_store_1; eauto. }
        * intros; split; intros.
          { eapply STKRANGE; eauto.
            eapply Mem.perm_store_2; eauto.
            eapply Mem.perm_free_3; eauto. }
          { eapply Mem.perm_free_1; eauto.
            - left. eapply not_eq_sym. eapply STKNOTMAPPED; eauto.
              unfold Genv.symbol_address; rewrite H8; eauto.
            - eapply Mem.perm_store_1; eauto.
              eapply STKRANGE; eauto. }
        * intros; split; intros.
          { eapply SIZERANGE; eauto.
            eapply Mem.perm_store_2; eauto.
            eapply Mem.perm_free_3; eauto. }
          { eapply Mem.perm_free_1; eauto.
            - left. eapply not_eq_sym. eapply SIZENOTMAPPED; eauto.
              unfold Genv.symbol_address; rewrite H8; eauto.
            - eapply Mem.perm_store_1; eauto.
              eapply SIZERANGE; eauto. }
        * clear NEXTBLOCK'; erewrite Mem.nextblock_free; eauto.
        * erewrite Mem.nextblock_free with (m1 := x); eauto.
          erewrite Mem.nextblock_store; eauto.
        * econstructor; eauto. intros. split.
          { unfold Mem.loadv. rewrite H2.
            erewrite Mem.load_free; eauto.
            - erewrite Mem.load_store_same; eauto. fold n. simpl.
              f_equal. f_equal. rewrite repr_sub. f_equal. Psatz.lia.
            - simpl. left. eapply not_eq_sym. eapply SIZENOTMAPPED. unfold Genv.symbol_address in H2.
              unfold Genv.symbol_address. destruct (Genv.find_symbol tge SIZE); inv H2; eauto.
              exact SPINJ. }
          { split; intros.
            - generalize (proj1 (H1 (S depth) sp) H8). intros. destruct H14 as [HO H14].
              rewrite <- H14. cutrewrite <- ((Val.add (Genv.symbol_address tge STK (Int.repr (-4 * Z.of_nat depth))) (Vint (Int.repr (4 * (Z.of_nat n - 1))))) = (Val.add (Genv.symbol_address tge STK (Int.repr (-4 * Z.of_nat (S depth)))) (Vint (Int.repr (4 * (Z.of_nat (length (Vptr tsp Int.zero :: map (fun s0 : stackframe => match s0 with | Stackframe _ _ sp0 _ _ => sp0 end) ts)) - 1)))))).
              + destruct STK_exists as [bSTK [U V]].
                unfold Genv.symbol_address. rewrite U. unfold Mem.loadv. simpl.
                erewrite Mem.load_free with (m1 := x); eauto.
                * split; try eapply pop_length; eauto.
                  erewrite Mem.load_store_other; eauto.
                  left. intro. unfold Genv.symbol_address in H2.
                  case_eq (Genv.find_symbol tge SIZE); intros; rewrite H16 in H2; inv H2.
                  generalize (tge.(Senv.find_symbol_injective) STK SIZE U H16). intros.
                  unfold SIZE in H2. eapply Pos.succ_discr; eauto.
                * left. eapply not_eq_sym. eapply STKNOTMAPPED; eauto.
                  unfold Genv.symbol_address; rewrite U. eauto.
              + unfold Genv.symbol_address. destruct (Genv.find_symbol tge STK); simpl; eauto.
                f_equal. repeat rewrite repr_add. f_equal. unfold n. Psatz.lia.
            - unfold Genv.symbol_address in H1, H8. destruct STK_exists as [bSTK [LA LA']].
              rewrite LA in H1, H8. simpl in H1, H8.
              erewrite Mem.load_free in H8; eauto.
              + erewrite Mem.load_store_other in H8; eauto.
                * replace (pop depth (map (fun s0 => match s0 with | Stackframe _ _ sp0 _ _ => sp0 end) ts)) with (pop (S depth) (Vptr tsp Int.zero :: map (fun s0 => match s0 with | Stackframe _ _ sp0 _ _ => sp0 end) ts)); try reflexivity.
                  eapply H1. destruct H8 as [HO H8]. split; try omega. rewrite <- H8; f_equal; auto.
                  rewrite ! repr_add. rewrite ! Int.unsigned_repr_eq.
                  f_equal; eauto. simpl. unfold n. Psatz.lia.
                * left. eapply STK_not_SIZE; eauto.
                  unfold Genv.symbol_address in H2; destruct (Genv.find_symbol tge SIZE); inv H2; auto.
              + left. eapply not_eq_sym. eapply STKNOTMAPPED; eauto.
                unfold Genv.symbol_address; rewrite LA; eauto. }
        * xomega.
        * intros; split; intros.
          { eapply Mem.perm_free_1; eauto.
            - destruct (peq b' tsp); auto. right.
              subst b'. generalize (FLATINJ' _ _ _ H8 SPINJ). intros LOL.
              subst b0. generalize (Mem.perm_free_2 _ _ _ _ _ H0). intros LOL.
              destruct (zlt o 0); auto.
              destruct (zle (fn_stacksize f) o); auto.
              + right; auto. omega.
              + exfalso. eapply LOL; eauto. omega.
            - eapply Mem.perm_store_1; eauto.
              eapply Mem.perm_free_3 in H14; eauto. eapply FLATPERM; eauto. }
          { eapply Mem.perm_free_1; eauto.
            - destruct (peq b0 stk); auto. right.
              subst b0. rewrite SPINJ in H8; inv H8.
              generalize (Mem.perm_free_2 _ _ _ _ _ ZU). intros LOL.
              destruct (zlt o 0); auto.
              destruct (zle (fn_stacksize f) o); auto.
              exfalso. eapply LOL; eauto. omega.
            - eapply Mem.perm_free_3 in H14; eauto.
              eapply Mem.perm_store_2 in H14; eauto. eapply FLATPERM; eauto. }
    - inv H0. monadInv FUN.
      generalize (Mem.alloc_parallel_inject j m tm 0 (fn_stacksize f) m' stk 0 (fn_stacksize f) MINJ H (Zle_refl _) (Zle_refl _)). intros [j' [tm' [tstk [HA [HB [HC [HD HE]]]]]]].
      generalize (transf_function_new_entrypoint _ _ EQ). intros [r [r' [r'' [pc1 [pc2 [pc3 [pc4 [pc5 [pc6 [XA [XB [XC [XD [XE [XF [XG [XH [XI XJ]]]]]]]]]]]]]]]]]].
      inv SHADOW. destruct H0 as [SS1 SS2].
      destruct SIZE_exists as [bSIZE [UW WU]].
      destruct STK_exists as [bSTK [EF FE]].
      unfold Genv.symbol_address in SS1; rewrite UW in SS1; simpl in SS1.
      unfold Genv.symbol_address in SS2; rewrite EF in SS2; simpl in SS2.
      destruct (Mem.valid_access_store tm' Mint32 bSIZE 0 (Vint (Int.add (Int.repr (4 * (Z.of_nat (length (map (fun s0 : stackframe => match s0 with | Stackframe _ _ sp _ _ => sp end) ts)) - 1))) (Int.repr 4)))).
      { eapply Mem.valid_access_alloc_other; eauto.
        unfold Mem.valid_access. split.
        - simpl. eapply SIZEPERM; eauto.
        - exists 0; auto. }
      rename e into LL.
      assert (e: exists x1, Mem.store Mint32 x0 bSTK (Int.unsigned (Int.add (Int.repr (4 * (Z.of_nat (length (map (fun s0 : stackframe => match s0 with | Stackframe _ _ sp _ _ => sp end) ts)) - 1))) (Int.repr 4))) (Vptr tstk Int.zero) = Some x1).
      { destruct (Classical_Prop.classic (exists x1, Mem.store Mint32 x0 bSTK (Int.unsigned (Int.add (Int.repr (4 * (Z.of_nat (length (map (fun s0 : stackframe => match s0 with | Stackframe _ _ sp _ _ => sp end) ts)) - 1))) (Int.repr 4))) (Vptr tstk Int.zero) = Some x1)); auto.
        generalize (init_state_exists'). intros [s0 INIT].
        generalize (STEP' s0 INIT). intros [t S].
        assert (program_behaves (RTL.semantics tprog) (Goes_wrong t)).
        - eapply program_runs; eauto.
          eapply state_goes_wrong.
          + eapply star_trans.
            * eapply S.
            * eapply star_step.
              { eapply exec_function_internal; eauto.
                monadInv EQ; eauto. }
              { eapply star_step.
                - eapply exec_Iload; eauto.
                  + simpl; eauto.
                  + unfold Genv.symbol_address; unfold tge in UW; rewrite UW; simpl.
                    eapply Mem.load_alloc_other; eauto.
                - eapply star_step.
                  + eapply exec_Iop; eauto.
                    simpl. rewrite PMap.gss; eauto.
                  + eapply star_step.
                    * eapply exec_Istore; eauto.
                      { simpl; eauto. }
                      { rewrite PMap.gss. unfold Genv.symbol_address; unfold tge in UW; rewrite UW; simpl.
                        eapply LL. }
                    * eapply star_step.
                      { eapply exec_Iload; eauto.
                        - simpl. unfold Genv.symbol_address; unfold tge in UW; rewrite UW; simpl; reflexivity.
                        - simpl. eapply Mem.load_store_same; eauto. }
                      { eapply star_step.
                        - eapply exec_Iop; eauto.
                          simpl; rewrite Int.add_zero; reflexivity.
                        - eapply star_refl.
                        - eauto. }
                      { eauto. }
                    * eauto.
                  + eauto.
                - eauto. }
              { eauto. }
            * repeat rewrite E0_right. eauto.
          + unfold nostep. unfold not; intros.
            inv H1; try congruence. eapply H0.
            exists m'0. rewrite H10 in XI; inv XI. rewrite PMap.gss in H12.
            simpl in H11. rewrite PMap.gso in H11; auto. rewrite PMap.gss in H11. inv H11.
            unfold Genv.symbol_address in H12; unfold tge in EF; rewrite EF in H12; simpl in H12.
            rewrite Int.add_zero_l in H12; auto.
          + unfold not; intros. inv H1.
        - generalize (DEFSAFE _ H1). intros ARGH. inv ARGH. }
      destruct e as [x1 LL'].
      eexists; split.
      + econstructor.
        * eapply exec_function_internal; eauto.
          monadInv EQ; eauto.
        * eapply star_step.
          { eapply exec_Iload; eauto.
            - simpl. eauto.
            - unfold Genv.symbol_address; rewrite UW; simpl.
              eapply Mem.load_alloc_other; eauto. }
          { eapply star_step.
            - eapply exec_Iop; eauto.
              simpl. rewrite PMap.gss; eauto.
            - eapply star_step.
              + eapply exec_Istore; eauto.
                * simpl. eauto.
                * rewrite PMap.gss. unfold Genv.symbol_address; rewrite UW; simpl.
                  eapply LL.
              + eapply star_step.
                * eapply exec_Iload; eauto.
                  { simpl. unfold Genv.symbol_address; rewrite UW; simpl; reflexivity. }
                  { simpl. eapply Mem.load_store_same; eauto. }
                * eapply star_step.
                  { eapply exec_Iop; eauto.
                    simpl. rewrite Int.add_zero. reflexivity. }
                  { eapply star_step.
                    - eapply exec_Istore; eauto.
                      + simpl. rewrite PMap.gso; try xomega. rewrite PMap.gss. reflexivity.
                      + rewrite PMap.gss. unfold Genv.symbol_address; rewrite EF; simpl.
                        rewrite Int.add_zero_l.
                        exact LL'.
                    - eapply star_one. eapply exec_Inop; eauto.
                    - eauto. }
                  { eauto. }
                * eauto.
              + eauto.
            - eauto. }
          { eauto. }
        * eauto.
      + monadInv EQ; econstructor.
        * eapply forall_match_stackframes_inject_incr; eauto.
        * unfold transf_function; rewrite EQ0; reflexivity.
        * simpl. unfold regs_agree; intros.
          destruct (plt (max_reg_function f) r0).
          { right; split; auto; try xomega.
            rewrite init_regs_spec; eauto.
            intro. eapply max_reg_function_params in H0. xomega. }
          { left; split; auto; try xomega.
            repeat rewrite PMap.gso; try xomega.
            eapply init_regs_inject; eauto. }
        * intros. generalize (STEP s0 H0). intros [t S].
          exists (t ** E0). eapply star_right; eauto.
          simpl. eapply exec_function_internal_block'; eauto.
        * intros. generalize (STEP' s0 H0). intros [t S].
          eexists. eapply star_trans; eauto.
          { eapply star_step.
            * eapply exec_function_internal; eauto.
            * eapply star_step.
              { eapply exec_Iload; eauto.
                - simpl. eauto.
                - unfold Genv.symbol_address; rewrite UW; simpl.
                  eapply Mem.load_alloc_other; eauto. }
              { eapply star_step.
                - eapply exec_Iop; eauto.
                  simpl. rewrite PMap.gss; eauto.
                - eapply star_step.
                  + eapply exec_Istore; eauto.
                    * simpl. eauto.
                    * rewrite PMap.gss. unfold Genv.symbol_address; rewrite UW; simpl.
                      eapply LL.
                  + eapply star_step.
                    * eapply exec_Iload; eauto.
                      { simpl. unfold Genv.symbol_address; rewrite UW; simpl; reflexivity. }
                      { simpl. eapply Mem.load_store_same; eauto. }
                    * eapply star_step.
                      { eapply exec_Iop; eauto.
                        simpl. rewrite Int.add_zero. reflexivity. }
                      { eapply star_step.
                        - eapply exec_Istore; eauto.
                          + simpl. rewrite PMap.gso; try xomega. rewrite PMap.gss. reflexivity.
                          + rewrite PMap.gss. unfold Genv.symbol_address; rewrite EF; simpl.
                            rewrite Int.add_zero_l.
                            exact LL'.
                        - eapply star_one. eapply exec_Inop; eauto.
                        - eauto. }
                      { eauto. }
                    * eauto.
                  + eauto.
                - eauto. }
              { eauto. }
            * eauto. }
        * intros. destruct (in_dec peq r0 (fn_params f)).
          { generalize (max_reg_function_params f r0 i); intros; xomega. }
          { eapply init_regs_spec; eauto. }
        * refine (Mem.store_outside_inject _ _ _ _ _ _ _ _ _ _ LL').
          { refine (Mem.store_outside_inject _ _ _ _ _ _ _ _ HB _ LL).
            intros. destruct (peq stk b').
            - subst b'. rewrite HD in H0.
              exploit Mem.alloc_result; eauto.
              intros. subst tstk. inversion H0.
              subst bSIZE. eapply BSIZEPLT in UW. xomega.
            - rewrite HE in H0; auto. eapply SIZENOTMAPPED; eauto.
              unfold Genv.symbol_address; rewrite UW; eauto. }
          { intros. destruct (peq stk b').
            - subst b'. rewrite HD in H0.
              exploit Mem.alloc_result; eauto.
              intros. subst tstk. inversion H0.
              subst bSTK. eapply BSTKPLT in EF. xomega.
            - rewrite HE in H0; auto. eapply STKNOTMAPPED; eauto.
              unfold Genv.symbol_address; rewrite EF; eauto. }
        * eauto.
        * intros. rewrite HE; eauto.
          generalize (Mem.alloc_result _ _ _ _ _ H). intros. subst stk.
          eapply Plt_ne; xomega.
        * intros. destruct (peq b stk).
          { subst b. rewrite HD in H1.
            exploit Mem.alloc_result; eauto. intros. subst tstk. inversion H1.
            unfold Genv.symbol_address in H0; rewrite EF in H0. inv H0. exploit BSTKPLT; eauto.
            intros. eapply not_eq_sym. eapply Plt_ne; eauto. }
          { eapply STKNOTMAPPED; eauto.
            erewrite <- HE; eauto. }
        * intros. destruct (peq b stk).
          { subst b. rewrite HD in H1.
            exploit Mem.alloc_result; eauto. intros. subst tstk. inversion H1.
            unfold Genv.symbol_address in H0; rewrite UW in H0. inv H0. exploit BSIZEPLT; eauto.
            intros. eapply not_eq_sym. eapply Plt_ne; eauto. }
          { eapply SIZENOTMAPPED; eauto.
            erewrite <- HE; eauto. }
        * intros. eapply BSTKPLT in H0.
          erewrite Mem.nextblock_store with (m1 := x0); eauto.
          erewrite Mem.nextblock_store with (m1 := tm'); eauto.
          exploit Mem.nextblock_alloc; eauto. intros ABC; rewrite ABC; eauto.
          xomega.
        * intros. eapply BSIZEPLT in H0.
          erewrite Mem.nextblock_store with (m1 := x0); eauto.
          erewrite Mem.nextblock_store with (m1 := tm'); eauto.
          exploit Mem.nextblock_alloc; eauto. intros ABC; rewrite ABC; eauto.
          xomega.
        * intros. unfold Mem.range_perm. intros.
          eapply Mem.perm_store_1; eauto.
          eapply Mem.perm_store_1; eauto.
          eapply Mem.perm_alloc_1; eauto.
          eapply STKPERM; eauto.
        * intros. unfold Mem.range_perm. intros.
          eapply Mem.perm_store_1; eauto.
          eapply Mem.perm_store_1; eauto.
          eapply Mem.perm_alloc_1; eauto.
          eapply SIZEPERM; eauto.
        * intros; split; intros.
          { eapply STKRANGE; eauto.
            eapply Mem.perm_alloc_4; eauto.
            - eapply Mem.perm_store_2; eauto.
              eapply Mem.perm_store_2; eauto.
            - exploit Mem.alloc_result; eauto. intros ABC; rewrite ABC.
              eapply BSTKPLT in H0. eapply Plt_ne; eauto. }
          { eapply (STKRANGE _ H0)in H1.
            eapply Mem.perm_store_1; eauto.
            eapply Mem.perm_store_1; eauto.
            eapply Mem.perm_alloc_1; eauto. }
        * intros; split; intros.
          { eapply SIZERANGE; eauto.
            eapply Mem.perm_alloc_4; eauto.
            - eapply Mem.perm_store_2; eauto.
              eapply Mem.perm_store_2; eauto.
            - exploit Mem.alloc_result; eauto. intros ABC; rewrite ABC.
              eapply BSIZEPLT in H0. eapply Plt_ne; eauto. }
          { eapply (SIZERANGE _ H0)in H1.
            eapply Mem.perm_store_1; eauto.
            eapply Mem.perm_store_1; eauto.
            eapply Mem.perm_alloc_1; eauto. }
        * intros. destruct (peq b' stk).
          { subst b'. rewrite HD in H1; inv H1.
            exploit Mem.alloc_result; eauto.
            intros; subst b. xomega. }
          { rewrite HE in H1; eauto. }
        * erewrite Mem.nextblock_alloc; eauto; xomega.
        * erewrite Mem.nextblock_store with (m1 := x0); eauto.
          erewrite Mem.nextblock_store with (m1 := tm'); eauto.
          erewrite Mem.nextblock_alloc; eauto; xomega.
        * econstructor. split.
          { intros. unfold Genv.symbol_address. rewrite UW. simpl.
            erewrite Mem.load_store_other; eauto.
            - erewrite Mem.load_store_same; eauto.
              simpl. f_equal. f_equal. rewrite repr_add.
              f_equal. Psatz.lia.
            - left. unfold not; intros.
              subst bSIZE. assert (SIZE = STK) by (apply (Genv.genv_vars_inj tge _ _ UW EF)).
              unfold SIZE in H0; unfold STK in H0. xomega. }
          { split; intros.
            { destruct depth.
              - simpl in H0. inv H0. simpl.
                unfold Genv.symbol_address; rewrite EF; simpl.
                rewrite Int.add_zero_l. erewrite Mem.load_store_same with (m1 := x0); eauto.
                + instantiate (1 := (Vptr tstk Int.zero)); simpl; split; eauto; omega.
                + rewrite <- LL'.
                  f_equal; eauto. rewrite repr_add.
                  rewrite ! Int.unsigned_repr_eq.
                  f_equal; eauto. Psatz.lia.
              - simpl in H0. simpl. unfold Genv.symbol_address; rewrite EF; simpl.
                generalize (pop_length _ _ _ H0); intros GG.
                generalize (pop_implies _ _ _ H0); intros GG'. destruct GG' as [sp' GG'].
                eapply SS2 in H0. eapply SS2 in GG'. destruct GG' as [GO GG']. destruct H0 as [HO H0].
                erewrite Mem.load_store_other; eauto.
                + erewrite Mem.load_store_other; eauto.
                  * split; try omega. eapply Mem.load_alloc_other; eauto.
                    rewrite <- H0. f_equal; eauto.
                    rewrite ! repr_add. f_equal. f_equal. Psatz.lia.
                  * left. unfold not; intros.
                    subst bSIZE. assert (SIZE = STK) by (apply (Genv.genv_vars_inj tge _ _ UW EF)).
                    unfold SIZE in H1; unfold STK in H1. xomega.
                + right. left. simpl. rewrite ! repr_add.
                  generalize (Mem.load_valid_access _ _ _ _ _ H0). intros ZYF.
                  destruct ZYF as [ZYF ZYF']. unfold Mem.range_perm in ZYF.
                  rewrite ! repr_add in ZYF; simpl in ZYF.
                  exploit (ZYF (Int.unsigned (Int.repr (-4 * Z.of_nat depth + 4 * (Z.of_nat (length (map (fun s0 : stackframe => match s0 with | Stackframe _ _ sp0 _ _ => sp0 end) ts)) - 1))))).
                  * omega.
                  * intros LANM. eapply STKRANGE in LANM; eauto.
                    simpl in GG'. rewrite Int.add_zero_l in GG'.
                    generalize (Mem.load_valid_access _ _ _ _ _ GG'). intros END.
                    destruct END as [END END']. unfold Mem.range_perm in END.
                    exploit (END (Int.unsigned (Int.repr (4 * (Z.of_nat (length (map (fun s0 : stackframe => match s0 with | Stackframe _ _ sp0 _ _ => sp0 end) ts)) - 1))))).
                    { simpl. omega. }
                    { intros LANM'. eapply STKRANGE in LANM'; eauto.
                      erewrite map_length in LANM, LANM', GG. erewrite ! map_length.
                      erewrite <- list_forall2_length; eauto. erewrite <- list_forall2_length in LANM, LANM', GG; eauto.
                      destruct init_state_exists as [s0 INIT].
                      generalize (STEP _ INIT). intros [t S].
                      assert (S': star step_block' ge s0 (t ** E0) (State s f (Vptr stk Int.zero) f.(fn_entrypoint) (init_regs args f.(fn_params)) m')).
                      - eapply star_right; eauto.
                        eapply exec_function_internal_block'; eauto.
                      - eapply FSIM_implies in S'; eauto.
                        rewrite ! Int.unsigned_repr; try Psatz.lia.
                        + replace Int.max_unsigned with 4294967295; try reflexivity.
                          Psatz.lia.
                        + replace Int.max_unsigned with 4294967295; try reflexivity.
                          split; try Psatz.lia. } }
            { destruct depth.
              - simpl. simpl in H0. unfold Genv.symbol_address in H0; rewrite EF in H0; simpl in H0.
                rewrite Int.add_zero_l in H0.
                generalize (Mem.load_store_same _ _ _ _ _ _ LL').
                simpl. intros LA. rewrite <- LA. destruct H0 as [HO H0]. rewrite <- H0.
                f_equal; eauto. rewrite repr_add. rewrite ! Int.unsigned_repr_eq. f_equal.
                Psatz.lia.
              - simpl. eapply SS2; eauto. unfold Genv.symbol_address in H0; rewrite EF in H0; simpl in H0.
                destruct H0 as [HO H0]. split; try omega.
                erewrite Mem.load_store_other in H0; eauto.
                + erewrite Mem.load_store_other in H0; eauto.
                  * rewrite <- H0. erewrite <- Mem.load_alloc_unchanged; eauto.
                    { f_equal; eauto. rewrite ! repr_add.
                      rewrite ! Int.unsigned_repr_eq; f_equal; Psatz.lia. }
                    { eapply BSTKPLT; eauto. }
                  * left. eapply STK_not_SIZE; eauto.
                + right. left. simpl. rewrite ! repr_add.
                  eapply Mem.load_valid_access in H0.
                  destruct H0 as [LA LA']. unfold Mem.range_perm in LA.
                  rewrite ! repr_add in LA.
                  exploit (LA (Int.unsigned (Int.repr (-4 * Z.pos (Pos.of_succ_nat depth) + 4 * (Z.pos (Pos.of_succ_nat (length (map (fun s0 : stackframe => match s0 with | Stackframe _ _ sp0 _ _ => sp0 end) ts))) - 1))))).
                  * simpl; omega.
                  * intros YO. eapply Mem.perm_store_2 in YO; eauto.
                    eapply Mem.perm_store_2 in YO; eauto.
                    eapply Mem.perm_alloc_4 in YO; eauto.
                    { eapply STKRANGE in YO; eauto.
                      rewrite Int.unsigned_repr in YO; try Psatz.lia.
                      - rewrite ! Int.unsigned_repr; try Psatz.lia.
                        + replace Int.max_unsigned with 4294967295; try reflexivity.
                          rewrite map_length; erewrite <- list_forall2_length; eauto; Psatz.lia.
                        + replace Int.max_unsigned with 4294967295; try reflexivity. rewrite map_length; erewrite <- list_forall2_length; eauto; split; try Psatz.lia. rewrite map_length in HO; erewrite <- list_forall2_length in HO; eauto. Psatz.lia.
                      - replace Int.max_unsigned with 4294967295; try reflexivity. rewrite map_length; erewrite <- list_forall2_length; eauto; split; try Psatz.lia. rewrite map_length in HO; erewrite <- list_forall2_length in HO; eauto. Psatz.lia. }
                    { exploit Mem.alloc_result; eauto. intros; subst tstk.
                      eapply BSTKPLT in EF. eapply Plt_ne. xomega. } } }
        * exploit Mem.load_store_same; eauto. simpl. intros LOLO.
          rewrite repr_add in LOLO. eapply Mem.load_valid_access in LOLO; eauto.
          destruct LOLO as [LO1 LO2]. simpl in LO1. generalize (LO1 (Int.unsigned (Int.repr (4 * (Z.of_nat (length (map (fun s0 : stackframe => match s0 with | Stackframe _ _ sp _ _ => sp end) ts)) - 1) + 4)))). intro LOA. exploit LOA.
          { omega. }
          { clear LOA; intro LOA. eapply Mem.perm_store_2 in LOA; eauto. eapply Mem.perm_store_2 in LOA; eauto.
            eapply Mem.perm_alloc_4 in LOA; eauto.
            - eapply STKRANGE in LOA; eauto. rewrite map_length in LOA; erewrite <- list_forall2_length in LOA; eauto.
              rewrite Int.unsigned_repr in LOA; try Psatz.lia.
              replace Int.max_unsigned with 4294967295; try reflexivity. Psatz.lia.
            - exploit Mem.alloc_result; eauto. intros; subst tstk.
              eapply BSTKPLT in EF. eapply Plt_ne. xomega. }
        * intros. destruct (peq b stk).
          { subst b; rewrite HD in H0; inv H0. reflexivity. }
          { rewrite HE in H0; eauto. }
        * intros. destruct (peq b1 stk).
          { destruct (peq b2 stk); subst; eauto.
            rewrite HD in H0. rewrite HE in H1; eauto.
            inv H0. generalize (Mem.alloc_result _ _ _ _ _ HA).
            generalize (Mem.valid_block_inject_2 _ _ _ _ _ _ H1 MINJ). unfold Mem.valid_block; intros.
            subst b. xomega. }
          { destruct (peq b2 stk); subst; eauto.
            - rewrite HD in H1. rewrite HE in H0; eauto.
              inv H1. generalize (Mem.alloc_result _ _ _ _ _ HA).
              generalize (Mem.valid_block_inject_2 _ _ _ _ _ _ H0 MINJ). unfold Mem.valid_block; intros.
              subst b. xomega.
            - rewrite HE in H0; eauto. rewrite HE in H1; eauto. }
        * intros. destruct (peq b stk).
          { subst b; rewrite HD in H0; inv H0. split; intros.
            - eapply Mem.perm_store_1; eauto.
              eapply Mem.perm_store_1; eauto.
              eapply Mem.perm_alloc_3 in H0; eauto.
              generalize (Mem.perm_alloc_2 _ _ _ _ _ HA o k H0).
              intros; eapply Mem.perm_implies; eauto.
              econstructor.
            - eapply Mem.perm_store_2 in H0; eauto.
              eapply Mem.perm_store_2 in H0; eauto.
              eapply Mem.perm_alloc_3 in H0; eauto.
              generalize (Mem.perm_alloc_2 _ _ _ _ _ H o k H0).
              intros; eapply Mem.perm_implies; eauto.
              econstructor. }
          { rewrite HE in H0; eauto. split; intros.
            - eapply Mem.perm_store_1; eauto.
              eapply Mem.perm_store_1; eauto.
              eapply Mem.perm_alloc_4 in H1; eauto.
              eapply Mem.perm_alloc_1; eauto.
              eapply FLATPERM; eauto.
            - eapply Mem.perm_store_2 in H1; eauto.
              eapply Mem.perm_store_2 in H1; eauto.
              eapply Mem.perm_alloc_4 in H1; eauto.
              eapply Mem.perm_alloc_1; eauto.
              eapply FLATPERM; eauto.
              unfold not; intros. subst b'.
              generalize (Mem.alloc_result _ _ _ _ _ HA).
              generalize (Mem.valid_block_inject_2 _ _ _ _ _ _ H0 MINJ). unfold Mem.valid_block; intros.
              subst tstk; xomega. }
    - inv H0. monadInv FUN.
      exploit external_call_mem_inject_gen'; eauto.
      { instantiate (1 := tge). econstructor; eauto.
        - intros. unfold Senv.public_symbol; simpl.
          symmetry. eapply public_preserved'.
        - repeat split.
          + unfold Senv.find_symbol in H1; simpl in H1.
            exploit Genv.genv_symb_range; eauto.
          + unfold Senv.find_symbol in H1; simpl in H1.
            exploit Genv.genv_symb_range; eauto. intros Q. eapply GINJ in Q.
            rewrite H0 in Q; inv Q. unfold Senv.find_symbol; simpl. eapply symbols_preserved'; eauto.
          + intros. unfold Senv.find_symbol in H1; simpl in H1.
            exploit Genv.genv_symb_range; eauto. intros Q. eapply GINJ in Q.
            exists b1; split; eauto. eapply symbols_preserved'; eauto.
          + intros. unfold Senv.block_is_volatile; simpl.
            unfold Genv.block_is_volatile. case_eq (Genv.find_var_info ge b1); intros.
            * exploit Genv.genv_vars_range; eauto. intros Q. eapply GINJ in Q.
              rewrite H0 in Q; inv Q. exploit varinfo_preserved; eauto. intros Q.
              rewrite Q. auto.
            * case_eq (Genv.find_var_info tge b2); intros; auto.
              generalize TRANSF'; intros TRANSF'.
              exploit Genv.find_var_info_rev_transf_augment; eauto.
              destruct (plt b2 (Genv.genv_next (Genv.globalenv prog))).
              { intros [v [X Y]]. generalize (GINJ' _ _ _ p H0). intros.
                subst b2. unfold ge in H1; congruence. }
              { simpl. intros [X | [X | X]]; inv X; eauto. } }
      intros [j' [tvres [tm' [A1 [A2 [A3 [A4 [A5 [A6 [A7 [A8 [A9 A10]]]]]]]]]]]].
      eexists; split.
      + eapply plus_one. eapply exec_function_external; eauto.
      + econstructor.
        * eapply forall_match_stackframes_inject_incr; eauto.
        * intros. generalize (STEP s0 H0). intros [t' S].
          exists (t' ** t). eapply star_right; eauto.
          eapply exec_function_external_block'; eauto.
        * intros. generalize (STEP' s0 H0). intros [t' S].
          exists (t' ** t). eapply star_right; eauto.
          eapply exec_function_external; eauto.
        * assumption.
        * intros; eapply A6; eauto.
        * intros. case_eq (j b); intros.
          { destruct p. generalize (A6 _ _ _ H2). intros XX. rewrite XX in H1; inv H1.
            eapply STKNOTMAPPED; eauto. }
          { generalize (A7 _ _ _ H2 H1). intros [X Y].
            intro; subst b'. unfold Genv.symbol_address in H0.
            case_eq (Genv.find_symbol tge STK); intros; rewrite H3 in H0; inv H0.
            eapply STKPERM in H3. eapply Y. eapply Mem.perm_valid_block.
            eapply H3. instantiate (1 := 0); split; omega. }
        * intros. case_eq (j b); intros.
          { destruct p. generalize (A6 _ _ _ H2). intros XX. rewrite XX in H1; inv H1.
            eapply SIZENOTMAPPED; eauto. }
          { generalize (A7 _ _ _ H2 H1). intros [X Y].
            intro; subst b'. unfold Genv.symbol_address in H0.
            case_eq (Genv.find_symbol tge SIZE); intros; rewrite H3 in H0; inv H0.
            eapply SIZEPERM in H3. eapply Y. eapply Mem.perm_valid_block.
            eapply H3. instantiate (1 := 0); split; omega. }
        * intros. eapply BSTKPLT in H0. eapply external_call_valid_block; eauto.
        * intros. eapply BSIZEPLT in H0. eapply external_call_valid_block; eauto.
        * assumption.
        * intros. unfold Mem.range_perm; intros. eapply A5; eauto.
          { unfold loc_out_of_reach. intros. exfalso. eapply STKNOTMAPPED; eauto.
            unfold Genv.symbol_address; rewrite H0; eauto. }
          { eapply BSTKPLT; eauto. }
          { eapply STKPERM; eauto. }
        * intros. unfold Mem.range_perm; intros. eapply A5; eauto.
          { unfold loc_out_of_reach. intros. exfalso. eapply SIZENOTMAPPED; eauto.
            unfold Genv.symbol_address; rewrite H0; eauto. }
          { eapply BSIZEPLT; eauto. }
          { eapply SIZEPERM; eauto. }
        * intros. split.
          { intros. inv A5. eapply unchanged_on_perm in H1.
            - eapply STKRANGE; eauto.
            - unfold loc_out_of_reach. intros. exfalso. eapply STKNOTMAPPED; eauto.
              unfold Genv.symbol_address; rewrite H0; eauto.
            - eapply BSTKPLT; eauto. }
          { intros. inv A5. eapply unchanged_on_perm; eauto.
            - unfold loc_out_of_reach. intros. exfalso. eapply STKNOTMAPPED; eauto.
              unfold Genv.symbol_address; rewrite H0; eauto.
            - eapply BSTKPLT; eauto.
            - eapply STKRANGE in H1; eauto. }
        * intros. split.
          { intros. inv A5. eapply unchanged_on_perm in H1.
            - eapply SIZERANGE; eauto.
            - unfold loc_out_of_reach. intros. exfalso. eapply SIZENOTMAPPED; eauto.
              unfold Genv.symbol_address; rewrite H0; eauto.
            - eapply BSIZEPLT; eauto. }
          { intros. inv A5. eapply unchanged_on_perm; eauto.
            - unfold loc_out_of_reach. intros. exfalso. eapply SIZENOTMAPPED; eauto.
              unfold Genv.symbol_address; rewrite H0; eauto.
            - eapply BSIZEPLT; eauto.
            - eapply SIZERANGE in H1; eauto. }
        * intros. case_eq (j b'); intros.
          { destruct p. generalize (A6 _ _ _ H2); intros.
            rewrite H3 in H1; inv H1. eapply GINJ'; eauto. }
          { generalize (A7 _ _ _ H2 H1). intros [X Y]. exfalso; eapply Y.
            eapply Mem.valid_block_inject_2 with (f := j); eauto. }
        * generalize (external_call_nextblock _ _ _ _ _ _ _ H). intros; xomega.
        * generalize (external_call_nextblock _ _ _ _ _ _ _ A1). intros; xomega.
        * inv SHADOW. generalize STK_exists. intros [bSTK [X Y]].
          generalize SIZE_exists. intros [bSIZE [XX YY]].
          econstructor. intros. split.
          { destruct H0; auto. unfold Mem.loadv. unfold Genv.symbol_address; rewrite XX; simpl.
            unfold Mem.loadv in H0; unfold Genv.symbol_address in H0; rewrite XX in H0; simpl in H0.
            unfold n. rewrite <- H0. eapply Mem.load_unchanged_on_1; eauto.
            - eapply Mem.perm_valid_block. eapply SIZEPERM; eauto.
              instantiate (1 := 0); omega.
            - rewrite ! Int.unsigned_zero. simpl. intros.
              unfold loc_out_of_reach; intros. intro. eapply SIZENOTMAPPED.
              + unfold Genv.symbol_address; rewrite XX; eauto.
              + eapply H3.
              + reflexivity. }
          { intros. unfold Genv.symbol_address; rewrite X; simpl. split; intros.
            - split; try eapply pop_length; eauto. destruct H0 as [LU H0]. unfold Mem.loadv in H0; unfold Genv.symbol_address in H0; rewrite X in H0; simpl in H0.
              eapply H0 in H1. destruct H1 as [HO H1].
              rewrite <- H1. eapply Mem.load_unchanged_on_1; eauto.
              + eapply Mem.perm_valid_block. eapply STKPERM; eauto.
                instantiate (1 := 0); omega.
              + unfold loc_out_of_reach; intros. intro. eapply STKNOTMAPPED.
                * unfold Genv.symbol_address; rewrite X; eauto.
                * eapply H3.
                * reflexivity.
            - destruct H0 as [LU H0]. unfold Mem.loadv in H0; unfold Genv.symbol_address in H0; rewrite X in H0; simpl in H0.
              eapply H0. destruct H1 as [HO H1]. split; eauto.
              erewrite Mem.load_unchanged_on_1 in H1; eauto.
              + eapply BSTKPLT; eauto.
              + unfold loc_out_of_reach; intros. intro. eapply STKNOTMAPPED.
                * unfold Genv.symbol_address; rewrite X; eauto.
                * eapply H3.
                * reflexivity. }
        * auto.
        * eauto.
        * eauto.
        * eauto.
    - inv H. inv STACKS. inv H1. eexists; split.
      + eapply plus_one. eapply exec_return; eauto.
      + econstructor; eauto.
        * eapply regs_agree_update; eauto.
        * intros. generalize (STEP s0 H). intros [t S].
          exists (t ** E0). eapply star_right; eauto.
          eapply exec_return_block'; eauto.
        * intros. generalize (STEP' s0 H). intros [t S].
          exists (t ** E0). eapply star_right; eauto.
          eapply exec_return; eauto.
        * intros. rewrite PMap.gso; eauto; xomega.
          Grab Existential Variables. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero. eapply Int.zero.
  Qed.

  Theorem progress:
    forall s1 s2,
      match_states s1 s2 ->
      safe (RTL.semantics tprog) s2 ->
      (exists r, final_state s1 r) \/
      (exists t s1', Step (semantics_block' prog) s1 t s1').
Proof.
    intros. generalize H; intros MS. exploit H0.
    - eapply star_refl.
    - intros [[r FIN] | [t [S' STEP]]].
      + left. exists r. inv FIN. inv H. inv STACKS. inv INJV.
        * econstructor.
        * destruct init_state_exists as [s0 INIT].
          destruct (STEP s0 INIT) as [t S].
          generalize (FSIM_implies _ _ _ INIT S); intros S'.
          assert (WRONG: program_behaves (semantics prog) (Goes_wrong t)).
          { econstructor; eauto.
            econstructor; eauto.
            - red. intros. unfold not; intros.
              inv H.
            - unfold not; intros. inv H. }
          eapply SAFE in WRONG. inv WRONG.
      + inv H.
        * right. case_eq ((fn_code f)!pc); intros.
          { exploit transf_function_spec; eauto.
            intros [pcs A]. destruct i; inv A.
            - eexists. eexists. eapply exec_Inop_block; eauto.
            - destruct init_state_exists as [s0 INIT].
              destruct (STEP0 s0 INIT) as [t' S].
              generalize (FSIM_implies _ _ _ INIT S); intros PROGSTEP.
              destruct (Classical_Prop.classic (exists t0 s1', Step (semantics prog) (State s f (Vptr sp Int.zero) pc rs m) t0 s1')).
              + destruct H1 as [t0 [s1' H1]]. inv H1; try congruence.
                eexists. eexists. eapply exec_Iop_block'; eauto.
              + assert (WRONG: program_behaves (semantics prog) (Goes_wrong t')).
                * econstructor; eauto.
                  econstructor; eauto.
                  { red; intros. unfold not; intros. eapply H1; eauto. }
                  { unfold not; intros. inv H2. }
                * eapply SAFE in WRONG; inv WRONG.
            - destruct init_state_exists as [init INIT].
              destruct (STEP0 init INIT) as [t' S].
              generalize (FSIM_implies _ _ _ INIT S); intros PROGSTEP.
              destruct (Classical_Prop.classic (exists t0 s1', Step (semantics prog) (State s f (Vptr sp Int.zero) pc rs m) t0 s1')).
              + destruct H1 as [t0 [s1' H1]]. inv H1; try congruence.
                case_eq (MoreRTL.is_trivial_annotation prog a m0 a0); intros.
                * rewrite H1 in H12. exploit is_trivial_annotation_load_correct.
                  { econstructor; eauto. }
                  { eauto. }
                  { eauto. }
                  { rewrite H in H10; inv H10. eauto. }
                  { rewrite H in H10; inv H10. exact H17. }
                  { intros [vals [HA HC]].
                    eexists. eexists. eapply exec_Iload_block'; eauto.
                    rewrite H in H10; inv H10. eapply H16.
                    rewrite H in H10; inv H10. eauto. destruct (snd a); auto.
                    left; auto. eapply addr_of_annotations_to_annot_sem; eauto. }
                * rewrite H1 in H12.
                  case_eq (is_singleton (snd a)); intros; rename H2 into Hsingleton; rewrite Hsingleton in H12.
                  { exploit (eval_addressing_inj ge tge).
                    { intros. eapply symbol_address_inject; eauto. intros; eapply GINJ_implies; eauto. }
                    { instantiate (1 := Vptr tsp Int.zero). econstructor; eauto. rewrite Int.add_zero. eauto. }
                    { instantiate (1 := trs##args). eapply regs_agree_inject_list; eauto.
                      intros; eapply max_reg_function_use; eauto. }
                    { eauto. }
                    intros [ta [Heval' Hinj]].
                    inv H12; exploit tr_regs_annot_inv_singleton; eauto.
                    { simpl. intros. destruct H12; eauto.
                      eapply match_stackframes_sps_are_ptrs; eauto. }
                    { rewrite H in H10; inv H10.
                      intros. eapply STEP' in H10. destruct H10.
                      eexists. eapply star_trans; eauto.
                      eapply star_step. eapply exec_Inop; eauto.
                      eapply star_step. eapply exec_Iop; eauto.
                      destruct addr; eauto. destruct (Int.eq_dec i Int.zero); simpl; eauto.
                      subst i. simpl in Heval'. rewrite <- Heval'. simpl in H16.
                      destruct (rs##args); inv H16. destruct l; inv H22. destruct (trs##args); inv Heval'.
                      destruct l; inv H16. destruct v0; simpl in H17; inv H17.
                      simpl in Hinj. rewrite Int.add_zero in Hinj. inv Hinj. destruct v1; simpl in H22; try (inv H22; fail).
                      rewrite Int.add_zero in H22. rewrite H22. reflexivity.
                      eapply star_refl. eauto. eauto. }
                    intros [tvals Haddr].
                    exploit addr_of_annotations_singleton_implies; eauto.
                    { simpl. intros. destruct H12; eauto.
                      eapply match_stackframes_sps_are_ptrs; eauto. }
                    { eapply check_annotations_range_inv; eauto. }
                    intros [tvals' [JA [JB JC]]].
                    assert (JD: forall v, In v tvals' -> exists b ofs, v = Vptr b ofs).
                    { eapply (addr_of_annotations_are_ptrs _ _ _ _ _ JA); eauto.
                      simpl. intros. destruct H12; eauto.
                      eapply match_stackframes_sps_are_ptrs; eauto. }
                    exploit addr_of_annotations_singleton_translated'; eauto.
                    { econstructor; eauto.
                      eapply match_stackframes_sps; eauto. }
                    { intros. eapply GINJ. eapply ge.(Genv.genv_symb_range); eauto. }
                    intros [vals [Hvals Hinjvals]].
                    eexists. eexists. eapply exec_Iload_block'; eauto.
                    rewrite H in H10; inv H10; eauto.
                    rewrite H in H10; inv H10; eauto.
                    eapply load_step_singleton; eauto.
                    rewrite H in H10; inv H10; eauto.
                    rewrite H in H10; inv H10; eauto. }
                  exploit (eval_addressing_inj ge tge).
                  { intros. eapply symbol_address_inject; eauto. intros; eapply GINJ_implies; eauto. }
                  { instantiate (1 := Vptr tsp Int.zero). econstructor; eauto. rewrite Int.add_zero. eauto. }
                  { instantiate (1 := trs##args). eapply regs_agree_inject_list; eauto.
                    intros; eapply max_reg_function_use; eauto. }
                  { eauto. }
                  intros [ta [Heval' Hinj]].
                  inv H12; exploit tr_regs_annot_inv; eauto.
                  { simpl. intros. destruct H5; eauto.
                    eapply match_stackframes_sps_are_ptrs; eauto. }
                  { rewrite H in H10; inv H10.
                    intros. eapply STEP' in H5. destruct H5.
                    eexists. eapply star_trans; eauto.
                    eapply star_step. eapply exec_Inop; eauto.
                    eapply star_step. eapply exec_Iop; eauto.
                    destruct addr; eauto. destruct (Int.eq_dec i Int.zero); simpl; eauto.
                    subst i. simpl in Heval'. rewrite <- Heval'.
                    destruct a1; inv H17. inv Hinj. destruct (trs ## args); inv Heval'.
                    destruct l; inv H17. destruct v0; simpl in H23; inv H23.
                    simpl; rewrite Int.add_zero; eauto.
                    eapply star_refl. eauto. eauto. }
                  intros [tvals Haddr].
                  exploit addr_of_annotations_translated'; eauto.
                  { econstructor; eauto.
                    eapply match_stackframes_sps; eauto. }
                  { intros. eapply GINJ. eapply ge.(Genv.genv_symb_range); eauto. }
                  intros [vals [Hvals Hinjvals]].
                  exploit load_step.
                  { eauto. }
                  { eauto. }
                  { econstructor; eauto. }
                  { eauto. }
                  { rewrite H in H10; inv H10; eauto. }
                  { rewrite H in H10; inv H10; eauto. }
                  { rewrite H in H10; inv H10; eauto. }
                  intros [HA HB].
                  eexists. eexists. eapply exec_Iload_block'; eauto.
                  rewrite H in H10; inv H10; eauto.
                  rewrite H in H10; inv H10; eauto.
                  destruct (snd a).
                  { econstructor; auto. }
                  { eapply addr_of_annotations_to_annot_sem; eauto. }
              + assert (WRONG: program_behaves (semantics prog) (Goes_wrong t')).
                * econstructor; eauto.
                  econstructor; eauto.
                  { red; intros. unfold not; intros. eapply H1; eauto. }
                  { unfold not; intros. inv H2. }
                * eapply SAFE in WRONG; inv WRONG.
            - destruct init_state_exists as [init INIT].
              destruct (STEP0 init INIT) as [t' S].
              generalize (FSIM_implies _ _ _ INIT S); intros PROGSTEP.
              destruct (Classical_Prop.classic (exists t0 s1', Step (semantics prog) (State s f (Vptr sp Int.zero) pc rs m) t0 s1')).
              + destruct H1 as [t0 [s1' H1]]. inv H1; try congruence.
                case_eq (MoreRTL.is_trivial_annotation prog a m0 a0); intros.
                * rewrite H1 in H12. exploit is_trivial_annotation_store_correct.
                  { econstructor; eauto. }
                  { eauto. }
                  { eauto. }
                  { rewrite H in H10; inv H10. eauto. }
                  { rewrite H in H10; inv H10. exact H17. }
                  { intros [vals [HA HC]].
                    eexists. eexists. eapply exec_Istore_block'; eauto.
                    rewrite H in H10; inv H10. eauto.
                    rewrite H in H10; inv H10. eauto.
                    destruct (snd a).
                    - constructor; auto.
                    - eapply addr_of_annotations_to_annot_sem; eauto. }
                * rewrite H1 in H12.
                  case_eq (is_singleton (snd a)); intros; rename H2 into Hsingleton; rewrite Hsingleton in H12.
                  { exploit (eval_addressing_inj ge tge).
                    { intros. eapply symbol_address_inject; eauto. intros; eapply GINJ_implies; eauto. }
                    { instantiate (1 := Vptr tsp Int.zero). econstructor; eauto. rewrite Int.add_zero. eauto. }
                    { instantiate (1 := trs##args). eapply regs_agree_inject_list; eauto.
                      intros; eapply max_reg_function_use; eauto. simpl. right; auto. }
                    { eauto. }
                    intros [ta [Heval' Hinj]].
                    inv H12; exploit tr_regs_annot_inv_singleton; eauto.
                    { simpl. intros. destruct H12; eauto.
                      eapply match_stackframes_sps_are_ptrs; eauto. }
                    { rewrite H in H10; inv H10.
                      intros. eapply STEP' in H10. destruct H10.
                      eexists. eapply star_trans; eauto.
                      eapply star_step. eapply exec_Inop; eauto.
                      eapply star_step. eapply exec_Iop; eauto.
                      destruct addr; eauto. destruct (Int.eq_dec i Int.zero); simpl; eauto.
                      subst i. simpl in Heval'. rewrite <- Heval'. simpl in H16.
                      destruct (rs##args); inv H16. destruct l; inv H22. destruct (trs##args); inv Heval'.
                      destruct l; inv H16. destruct v; simpl in H17; inv H17.
                      simpl in Hinj. rewrite Int.add_zero in Hinj. inv Hinj. destruct v0; simpl in H22; try (inv H22; fail).
                      rewrite Int.add_zero in H22. rewrite H22. reflexivity.
                      eapply star_refl. eauto. eauto. }
                    intros [tvals Haddr].
                    exploit addr_of_annotations_singleton_implies; eauto.
                    { simpl. intros. destruct H12; eauto.
                      eapply match_stackframes_sps_are_ptrs; eauto. }
                    { eapply check_annotations_range_inv; eauto. }
                    intros [tvals' [JA [JB JC]]].
                    assert (JD: forall v, In v tvals' -> exists b ofs, v = Vptr b ofs).
                    { eapply (addr_of_annotations_are_ptrs _ _ _ _ _ JA); eauto.
                      simpl. intros. destruct H12; eauto.
                      eapply match_stackframes_sps_are_ptrs; eauto. }
                    exploit addr_of_annotations_singleton_translated'; eauto.
                    { econstructor; eauto.
                      eapply match_stackframes_sps; eauto. }
                    { intros. eapply GINJ. eapply ge.(Genv.genv_symb_range); eauto. }
                    intros [vals [Hvals Hinjvals]].
                    eexists. eexists. eapply exec_Istore_block'; eauto.
                    rewrite H in H10; inv H10; eauto.
                    rewrite H in H10; inv H10; eauto.
                    eapply store_step_singleton; eauto.
                    rewrite H in H10; inv H10; eauto.
                    rewrite H in H10; inv H10; eauto. }
                  exploit (eval_addressing_inj ge tge).
                  { intros. eapply symbol_address_inject; eauto. intros; eapply GINJ_implies; eauto. }
                  { instantiate (1 := Vptr tsp Int.zero). econstructor; eauto. rewrite Int.add_zero. eauto. }
                  { instantiate (1 := trs##args). eapply regs_agree_inject_list; eauto.
                    intros; eapply max_reg_function_use; eauto. simpl; right; auto. }
                  { eauto. }
                  intros [ta [Heval' Hinj]].
                  inv H12; exploit tr_regs_annot_inv; eauto.
                  { simpl. intros. destruct H5; eauto.
                    eapply match_stackframes_sps_are_ptrs; eauto. }
                  { rewrite H in H10; inv H10.
                    intros. eapply STEP' in H5. destruct H5.
                    eexists. eapply star_trans; eauto.
                    eapply star_step. eapply exec_Inop; eauto.
                    eapply star_step. eapply exec_Iop; eauto.
                    destruct addr; eauto. destruct (Int.eq_dec i Int.zero); simpl; eauto.
                    subst i. simpl in Heval'. rewrite <- Heval'.
                    destruct a1; inv H17. inv Hinj. destruct (trs ## args); inv Heval'.
                    destruct l; inv H17. destruct v; simpl in H23; inv H23.
                    simpl; rewrite Int.add_zero; eauto.
                    eapply star_refl. eauto. eauto. }
                  intros [tvals Haddr].
                  exploit addr_of_annotations_translated'; eauto.
                  { econstructor; eauto.
                    eapply match_stackframes_sps; eauto. }
                  { intros. eapply GINJ. eapply ge.(Genv.genv_symb_range); eauto. }
                  intros [vals [Hvals Hinjvals]].
                  exploit store_step.
                  { eauto. }
                  { eauto. }
                  { econstructor; eauto. }
                  { eauto. }
                  { rewrite H in H10; inv H10; eauto. }
                  { rewrite H in H10; inv H10; eauto. }
                  { rewrite H in H10; inv H10; eauto. }
                  intros [HA HB].
                  eexists. eexists. eapply exec_Istore_block'; eauto.
                  rewrite H in H10; inv H10; eauto.
                  rewrite H in H10; inv H10; eauto.
                  destruct (snd a).
                  { constructor; auto. }
                  { eapply addr_of_annotations_to_annot_sem; eauto. }
              + assert (WRONG: program_behaves (semantics prog) (Goes_wrong t')).
                * econstructor; eauto.
                  econstructor; eauto.
                  { red; intros. unfold not; intros. eapply H1; eauto. }
                  { unfold not; intros. inv H2. }
                * eapply SAFE in WRONG; inv WRONG.
            - destruct init_state_exists as [init INIT].
              destruct (STEP0 init INIT) as [t' S].
              generalize (FSIM_implies _ _ _ INIT S); intros PROGSTEP.
              destruct (Classical_Prop.classic (exists t0 s1', Step (semantics prog) (State s f (Vptr sp Int.zero) pc rs m) t0 s1')).
              + destruct H1 as [t0 [s1' H1]]. inv H1; try congruence.
                eexists. eexists. eapply exec_Icall_block'; eauto.
              + assert (WRONG: program_behaves (semantics prog) (Goes_wrong t')).
                * econstructor; eauto.
                  econstructor; eauto.
                  { red; intros. unfold not; intros. eapply H1; eauto. }
                  { unfold not; intros. inv H2. }
                * eapply SAFE in WRONG; inv WRONG.
            - destruct init_state_exists as [init INIT].
              destruct (STEP0 init INIT) as [t' S].
              generalize (FSIM_implies _ _ _ INIT S); intros PROGSTEP.
              destruct (Classical_Prop.classic (exists t0 s1', Step (semantics prog) (State s f (Vptr sp Int.zero) pc rs m) t0 s1')).
              + destruct H1 as [t0 [s1' H1]]. inv H1; try congruence.
                eexists. eexists. eapply exec_Itailcall_block'; eauto.
              + assert (WRONG: program_behaves (semantics prog) (Goes_wrong t')).
                * econstructor; eauto.
                  econstructor; eauto.
                  { red; intros. unfold not; intros. eapply H1; eauto. }
                  { unfold not; intros. inv H2. }
                * eapply SAFE in WRONG; inv WRONG.
            - destruct init_state_exists as [init INIT].
              destruct (STEP0 init INIT) as [t' S].
              generalize (FSIM_implies _ _ _ INIT S); intros PROGSTEP.
              destruct (Classical_Prop.classic (exists t0 s1', Step (semantics prog) (State s f (Vptr sp Int.zero) pc rs m) t0 s1')).
              + destruct H1 as [t0 [s1' H1]]. inv H1; try congruence.
                eexists. eexists. eapply exec_Ibuiltin_block'; eauto.
              + assert (WRONG: program_behaves (semantics prog) (Goes_wrong t')).
                * econstructor; eauto.
                  econstructor; eauto.
                  { red; intros. unfold not; intros. eapply H1; eauto. }
                  { unfold not; intros. inv H2. }
                * eapply SAFE in WRONG; inv WRONG.
            - destruct init_state_exists as [init INIT].
              destruct (STEP0 init INIT) as [t' S].
              generalize (FSIM_implies _ _ _ INIT S); intros PROGSTEP.
              destruct (Classical_Prop.classic (exists t0 s1', Step (semantics prog) (State s f (Vptr sp Int.zero) pc rs m) t0 s1')).
              + destruct H1 as [t0 [s1' H1]]. inv H1; try congruence.
                eexists. eexists. eapply exec_Icond_block'; eauto.
              + assert (WRONG: program_behaves (semantics prog) (Goes_wrong t')).
                * econstructor; eauto.
                  econstructor; eauto.
                  { red; intros. unfold not; intros. eapply H1; eauto. }
                  { unfold not; intros. inv H2. }
                * eapply SAFE in WRONG; inv WRONG.
            - destruct init_state_exists as [init INIT].
              destruct (STEP0 init INIT) as [t' S].
              generalize (FSIM_implies _ _ _ INIT S); intros PROGSTEP.
              destruct (Classical_Prop.classic (exists t0 s1', Step (semantics prog) (State s f (Vptr sp Int.zero) pc rs m) t0 s1')).
              + destruct H1 as [t0 [s1' H1]]. inv H1; try congruence.
                eexists. eexists. eapply exec_Ijumptable_block'; eauto.
              + assert (WRONG: program_behaves (semantics prog) (Goes_wrong t')).
                * econstructor; eauto.
                  econstructor; eauto.
                  { red; intros. unfold not; intros. eapply H1; eauto. }
                  { unfold not; intros. inv H2. }
                * eapply SAFE in WRONG; inv WRONG.
            - destruct init_state_exists as [init INIT].
              destruct (STEP0 init INIT) as [t' S].
              generalize (FSIM_implies _ _ _ INIT S); intros PROGSTEP.
              destruct (Classical_Prop.classic (exists t0 s1', Step (semantics prog) (State s f (Vptr sp Int.zero) pc rs m) t0 s1')).
              + destruct H1 as [t0 [s1' H1]]. inv H1; try congruence.
                eexists. eexists. eapply exec_Ireturn_block'; eauto.
              + assert (WRONG: program_behaves (semantics prog) (Goes_wrong t')).
                * econstructor; eauto.
                  econstructor; eauto.
                  { red; intros. unfold not; intros. eapply H1; eauto. }
                  { unfold not; intros. inv H3. }
                * eapply SAFE in WRONG; inv WRONG. }
          { destruct init_state_exists as [s0 INIT].
            destruct (STEP0 s0 INIT) as [t' S].
            generalize (FSIM_implies _ _ _ INIT S); intros PROGSTEP.
            assert (WRONG: program_behaves (semantics prog) (Goes_wrong t')).
            { econstructor; eauto.
              econstructor; eauto.
              - red. intros. unfold not; intros. inv H1; try congruence.
              - unfold not; intros. inv H1. }
            eapply SAFE in WRONG. inv WRONG. }
        * right. destruct init_state_exists as [s0 INIT].
          destruct (STEP0 s0 INIT) as [t' S].
          generalize (FSIM_implies _ _ _ INIT S); intros PROGSTEP.
          destruct (Classical_Prop.classic (exists t0 s1', Step (semantics prog) (Callstate s f args m) t0 s1')).
          { destruct H as [t0 [s1' H]]. inv H.
            - eexists. eexists. eapply exec_function_internal_block'; eauto.
            - eexists. eexists. eapply exec_function_external_block'; eauto. }
          { assert (WRONG: program_behaves (semantics prog) (Goes_wrong t')).
            - econstructor; eauto.
              econstructor; eauto.
              + red. intros. unfold not; intros. eapply H; eauto.
              + unfold not; intros. inv H1.
            - eapply SAFE in WRONG. inv WRONG. }
        * right. destruct init_state_exists as [s0 INIT].
          destruct (STEP0 s0 INIT) as [t' S].
          generalize (FSIM_implies _ _ _ INIT S); intros PROGSTEP.
          destruct (Classical_Prop.classic (exists t0 s1', Step (semantics prog) (Returnstate s v m) t0 s1')).
          { destruct H as [t0 [s1' H]]. inv H.
            inv STACKS. eexists. eexists. eapply exec_return_block'; eauto. }
          { assert (WRONG: program_behaves (semantics prog) (Goes_wrong t')).
            - econstructor; eauto.
              econstructor; eauto.
              + red. intros. unfold not; intros. eapply H; eauto.
              + unfold not; intros. inv STEP.
                inv STACKS. inv H1.
            - eapply SAFE in WRONG. inv WRONG. }
  Qed.
            
  Lemma final_states_match:
    forall s1 s2 r,
      match_states s1 s2 ->
      final_state s1 r ->
      final_state s2 r.
Proof.
    intros. inv H0. inv H.
    inv INJV; inv STACKS; econstructor.
  Qed.
  
  Theorem bsim:
    backward_simulation (RTL.semantics tprog) (semantics_block' prog).
Proof.
    eapply backward_simulation_plus.
    - eapply public_preserved'; eauto.
    - eapply initial_states_exist.
    - eapply initial_states_match.
    - intros. eapply final_states_match; eauto. eapply H.
    - intros; eapply progress; eauto. eapply H.
    - intros. eapply simulation; eauto.
  Qed.

End PRESERVATION.

Theorem def_program_safe_implies_annotations_correct:
  forall p tp,
    transf_program p = OK tp ->
    (forall beh, program_behaves (RTL.semantics p) beh -> not_wrong beh) ->
    (forall beh, program_behaves (RTL.semantics tp) beh -> not_wrong beh) ->
    forall beh, program_behaves (RTL.semantics_safe p) beh -> not_wrong beh.
Proof.
  intros. exploit backward_simulation_same_safe_behavior; eauto.
  eapply compose_backward_simulation.
  - eapply sr_traces. eapply semantics_safe_receptive.
  - eapply bsim; eauto.
  - eapply BSIM_block'_safe.
Qed.