Module RTLofRTLinjectproof


Require Import
   Coqlib Values Maps Registers
   Traces Errors Globalenvs
   Simulations TSOsimulation
.

Require Import
   Utf8 Classical
   Utils Common
   RTLinject RTLinjectlow RTL
   RTLofRTLinject
   RTLofRTLinjectspec.

Section CORRECT.

  Variable bi : backend_info.
  Hypothesis OK_BI: ok_bi bi.

    Inductive match_fundef : RTLinject.fundefRTL.fundefProp :=
    | MFI sg param ssz c c' ep
        (SIG: ∀t, In t sg.(Ast.sig_args) → t = Ast.Tint)
        (CODE: match_code bi c c')
      : match_fundef
          (Ast.Internal (RTLinject.mkfunction sg param ssz c ep))
          (Ast.Internal (RTL.mkfunction sg (map xO param) ssz c' ep))
    | MFE f
      : match_fundef (Ast.External f) (Ast.External f)
    .

  Remark transl_fundef_correct {f f'} : transl_fundef bi f = OK f' → match_fundef f f'.
Proof.
    unfold transl_fundef, Ast.transf_partial_fundef.
    destruct f. 2: intros; vauto.
    intros H. bi. clarify.
    unfold translate_function in Hbi.
    bi. generalize (check_sig_correct Hbi0).
    generalize (translate_code_correct bi f.(RTLinject.fn_code) (OK (Transcode.init_state (Psucc (max_key f.(RTLinject.fn_code)))))).
    bi. autorw'. destruct f. vauto.
  Qed.

  Definition genv_rel : RTLinject.genvRTL.genvProp :=
    fun x y => Genv.genv_match (fun a b => transl_fundef bi a = Errors.OK b) y x.

  Definition match_prg p p' := transf_program bi p = OK p'.

  Section SIM.

    Variables (ge: RTLinject.genv) (tge: RTL.genv).
    Hypothesis TRANSF: genv_rel ge tge.

    Let lts := mklts thread_labels (rtl_step' ge).
    Let tlts := mklts thread_labels (rtl_step tge).

    Definition match_regset : INJECT.regsetRTL.regsetProp :=
      fun x y =>
        ∀ r, Val.lessdef (x r) (y # (xO r)).

    Definition match_inject_regset : INJECT.regsetRTL.regsetProp :=
      fun x y =>
        ∀ r, Val.lessdef (x r) (y # (xI r)).

    Lemma match_regset_upd rs rs' :
      match_regset rs rs' →
      ∀ v v',
        Val.lessdef v v' →
        ∀ r,
          match_regset (upd rs r v) (rs' # (xO r) <- v').
Proof.
      intros H v v' V r r'.
      unfold upd.
      eq_case. intros ->. now rewrite Regmap.gss.
      intros NE. rewrite Regmap.gso. apply H.
      congruence.
    Qed.

    Lemma match_regset_iupd rs rs' :
      match_regset rs rs' →
      ∀ v v',
        Val.lessdef v v' →
        ∀ r,
          match_regset rs (rs' # (xI r) <- v').
Proof.
      intros H v v' V r r'.
      rewrite Regmap.gso. apply H.
      congruence.
    Qed.

    Lemma match_iregset_upd rs rs' :
      match_inject_regset rs rs' →
      ∀ v v',
        Val.lessdef v v' →
        ∀ r,
          match_inject_regset (INJECT.upd_regset rs r v) (rs' # (xI r) <- v').
Proof.
      intros H v v' V r r'.
      unfold INJECT.upd_regset.
      case (peq r' r). intros ->. now rewrite Regmap.gss.
      intros NE. rewrite Regmap.gso. apply H.
      congruence.
    Qed.
    Hint Resolve match_regset_upd match_regset_iupd match_iregset_upd.

    Lemma match_args_lessdef {rs rs'} :
      match_regset rs rs' →
      ∀args,
        Val.lessdef_list (map rs args) (rs' ## (map xO args)).
Proof.
      intros REGS.
      induction args; simpl; vauto.
    Qed.

    Lemma match_iargs_lessdef {rs rs'} :
      match_inject_regset rs rs' →
      ∀args,
        Val.lessdef_list (map rs args) (rs' ## (map xI args)).
Proof.
      intros REGS.
      induction args; simpl; vauto.
    Qed.

    Lemma match_init_regs :
      ∀ param,
      forall args' args,
        Val.lessdef_list args args' →
        match_regset (reg_upd (fun _ : reg => Vundef) param args)
                     (init_regs args' (map xO param)).
Proof.
      induction param as [|p param IH].
        unfold reg_upd, init_regs. simpl.
        intros ? ? _ r. vauto.
      simpl. intros [|x args];
        intros ? K; inv K; unfold reg_upd; simpl.
        intros r; vauto.
      fold reg_upd.
      intros r. unfold upd. eq_case.
      now intros ->; rewrite Regmap.gss.
      intros K. rewrite Regmap.gso.
      apply IH; auto.
      intros Q; apply K.
      now inv Q.
    Qed.

    Lemma match_find_function {rs rs'} :
      match_regset rs rs' →
      ∀ros fd,
        RTLinject.find_function ge ros rs = Some fd
        ∃fd',
          RTL.find_function tge (match ros with inl f => inl Ast.ident (xO f) | inr f => inr _ f end) rs' = Some fd'
        ∧ match_fundef fd fd'.
Proof.
      destruct TRANSF as (T1 & T3).
      intros REGS [r|s] fd; simpl.
      pose proof (REGS r) as Hr. destruct (rs r); clarify. simpl.
      specialize T3 with p. intros H. rewrite H in T3.
      case_eq (Genv.find_funct_ptr tge p).
        intros fd' H'. rewrite H' in T3. exists fd'. inv Hr. split; auto using @transl_fundef_correct.
      intros K; rewrite K in T3. easy.
      intros H. specialize T1 with s.
      destruct (Genv.find_symbol ge s); simpl in *.
      specialize T3 with p. rewrite H in T3.
      case_eq (Genv.find_funct_ptr tge p).
        intros fd' H'. rewrite H' in T3. exists fd'. rewrite <- T1. split; auto using @transl_fundef_correct.
      intros K; rewrite K in T3. easy.
      now clarify.
    Qed.

    Lemma match_eval_addressing {ad sp v a a'} :
      Val.lessdef_list a a' →
      Op.eval_addressing ge sp ad a = Some v
      Op.eval_addressing tge sp ad a' = Some v.
Proof.
      destruct TRANSF as (T1 & T3).
      induction 1 as [|a a' args args' U V IH].
      destruct ad; simpl; eauto.
      case_eq (Genv.find_symbol ge i). now intros p Hp; rewrite <- T1, Hp.
      case_eq (Genv.find_symbol tge i); clarify.
      destruct args as [|b args]; inv V.
      destruct ad; simpl; destruct a; inv U; vauto.
      case_eq (Genv.find_symbol ge i). intros p Hp; now rewrite <- T1, Hp.
      case_eq (Genv.find_symbol tge i); clarify.
      case_eq (Genv.find_symbol ge i0). now intros p Hp; rewrite <- T1, Hp.
      now case_eq (Genv.find_symbol tge i0); clarify.
      destruct args as [|c args]; inv H3.
      destruct ad; simpl; destruct a; inv U; destruct b; inv H1; clarify;
      destruct p; congruence.
      destruct ad; simpl; destruct a; inv U; destruct b; inv H1; clarify;
        destruct p; congruence.
    Qed.

    Lemma match_eval_op {op args args' sp v} :
      INJECT.ok_op op
      Val.lessdef_list args args' →
      Op.eval_operation ge sp op args = Some v
      ∃v',
        Op.eval_operation tge sp op args' = Some v'
      ∧ Val.lessdef v v'.
Proof.
      destruct op; clarify; intros _; unfold Op.eval_operation.
      destruct args as [|a [|]]; clarify. intros K; inv K. intros K; inv K. inv H3. eexists; intuition.
      destruct args as [|]; clarify. inversion 1. inversion 1.
      eexists; intuition.
      destruct args as [|a [|]]; clarify; destruct a; clarify. inversion 1; inversion 1. inv H4. inv H2. eexists; intuition.
      destruct args as [|a [|]]; clarify; destruct a; clarify. inversion 1; inversion 1. inv H4. inv H2. eexists; intuition.
      destruct args as [|a [|]]; clarify; destruct a; clarify. inversion 1; inversion 1. inv H4. inv H2. eexists; intuition.
      destruct args as [|a [|]]; clarify; destruct a; clarify. inversion 1. intros K. bif2. inv H4. inv H2. eexists; intuition.
      eauto using @match_eval_addressing.
      case_eq (Op.eval_condition c args).
      intros [] H K L; clarify; rewrite (Op.eval_condition_lessdef _ K H); eauto.
      clarify.
    Qed.

    Definition only_int : RTL.regsetProp :=
      fun rs => ∀r, Val.has_type (rs # r) Ast.Tint.

    Lemma only_int_update rs v r :
      only_int rs
      Val.has_type v Ast.Tint
      only_int (rs # r <- v).
Proof.
      intros I V r'.
      case (peq r r'). intros ->. now rewrite Regmap.gss.
      intros K. rewrite Regmap.gso. apply I. congruence.
    Qed.
    Hint Resolve only_int_update.

    Lemma eval_op_int {rs' sp op args v} :
      only_int rs' →
      INJECT.ok_op op
      Op.eval_operation tge sp op (rs' ## args) = Some v
      Val.has_type v Ast.Tint.
Proof.
      intros INTS.
      destruct op; clarify; intros _;
      try now destruct args as [|x [|]]; clarify; simpl; inversion 1.
      destruct args as [|x [|]]; clarify; simpl.
      now destruct (rs' # x); inversion 1.
      now destruct (rs' # x); inversion 1.
      now destruct args as [|x [|]]; clarify; simpl; destruct (rs' # x); inversion 1.
      now destruct args as [|x [|]]; clarify; simpl; destruct (rs' # x); inversion 1.
      destruct args as [|x [|]]; clarify; simpl; destruct (rs' # x); clarify; intros; bif2.
      destruct a; simpl; destruct args as [|? [|? ()]]; simpl; clarify;
      try (now destruct (rs' # p) as [| | |()]; inversion 1);
      try (
      destruct (rs' # p) as [| | |()]; clarify;
      destruct (rs' # p0) as [| | |()]; clarify;
      inversion 1; auto).
      destruct (Genv.find_symbol tge i); inversion 1; auto.
      destruct (rs' # p); clarify.
      destruct (Genv.find_symbol tge i); inversion 1; auto.
      destruct (rs' # p); clarify.
      destruct (Genv.find_symbol tge i0); inversion 1; auto.
      destruct sp; inversion 1; auto.
      destruct c; simpl; destruct args as [|x [|y ()]]; simpl; clarify;
      destruct (rs' # x); simpl; clarify;
      try (destruct (rs' # y); simpl; clarify);
      try (now destruct (Op.eval_compare_null c i) as [()|]; inversion 1; auto);
      try (intros; bif2).
      now destruct (Val.option_bool_of_bool3 (Pointers.Ptr.cmp c p p0)) as [()|]; inversion 1.
      now destruct (Val.option_bool_of_bool3 (Pointers.Ptr.cmpu c p p0)) as [()|]; inversion 1.
    Qed.

    Inductive match_stack_frame : stack_framestackframeProp :=
    | MSF res rs rs' c c' sp pc
        (INTS: only_int rs')
        (REGS: match_regset rs rs')
        (CODE: match_code bi c c')
      : match_stack_frame (mksf res c sp pc rs) (Stackframe (xO res) c' sp pc rs').

    Definition match_stack : stacklist stackframeProp := list_forall2 match_stack_frame.

    Inductive tr_cont (c: RTL.code) (exit: node) (dst: list reg) : INJECT.continuationnodenodeProp :=
    | TKstmt s k ns nk nd
        (TKS: tr_stmt bi c s ns dst exit nk)
        (TKK: tr_cont c exit dst k nk nd)
      : tr_cont c exit dst (INJECT.Kstmt s k) ns nd
    | TKend nd
      : tr_cont c exit dst INJECT.Kend nd nd
    .

    Inductive match_state : RTLinject.intra_stateRTL.stateProp :=
    | MSCS stk stk' f f' args args'
        (STK: match_stack stk stk')
        (FD: match_fundef f f')
        (ARGS: Val.lessdef_list args args')
        (INTS: ∀a, In a args' → Val.has_type a Ast.Tint)
      : match_state (RICallState stk f args) (Callstate stk' f' args')
    | MSBS stk stk' sg
        (STK: match_stack stk stk')
      : match_state (RIBlockedState stk sg) (Blockedstate stk' sg)
    | MSRS stk stk' res res'
        (STK: match_stack stk stk')
        (RES: Val.lessdef res res')
        (INT: Val.has_type res' Ast.Tint)
      : match_state (RIRetState stk res) (Returnstate stk' res')
    | MSS stk stk' c c' sp pc rs rs'
        (STK: match_stack stk stk')
        (CODE: match_code bi c c')
        (REGS: match_regset rs rs')
        (INTS: only_int rs')
      : match_state (RIState stk c sp pc rs) (State stk' c' sp pc rs')
    | MSI stk stk' c c' sp pc pc' rs rs' dst irs is ik nk
        (STK: match_stack stk stk')
        (CODE: match_code bi c c')
        (REGS: match_regset rs rs')
        (IREGS: match_inject_regset irs rs')
        (INTS: only_int rs')
        (TS: tr_stmt bi c' is pc' (map xO dst) pc nk)
        (TK: tr_cont c' pc (map xO dst) ik nk pc)
      : match_state (RIInjectState stk c sp pc rs dst (INJECT.NormalState irs is ik))
                    (State stk' c' sp pc' rs')
    .

    Section M.
     Import INJECT.
     Open Scope nat_scope.

     Fixpoint measure_stmt (stmt: statement) : nat :=
       match stmt with
         | Sskip
         | Sreturn _ => 1
         | Sfreeperm
         | Leak _ _ _
         | Sop _ _ _
         | Sload _ _ _ _
         | Sstore _ _ _ _ _
         | Satomicmem _ _ _ _
         | Sfence false
         | Srequestperm _ _ _
         | Sabort _ false _
         | Sassume _ _
         | Srelease
           => 2
         | Sabort _ true _
         | Sfence true
           => 3
         | Sseq s s'
         | Sbranch s s'
         | Sifthenelse _ _ s s' => 1 + measure_stmt s + measure_stmt s'
         | Satomic _ s
         | Sloop s
         | Swhile _ _ s => 1 + measure_stmt s
         | Srepeat s _ _ => 3 + measure_stmt s + measure_stmt s
       end.

     Fixpoint measure_cont (k: continuation) : nat :=
       match k with
         | Kstmt s k' => measure_stmt s + measure_cont k'
         | Kendatomic _ k' => measure_cont k'
         | Kend => O
       end.

     Definition measure_state (s: state) : nat :=
       match s with
         | NormalState _ s k => measure_stmt s + measure_cont k
         | ReturnState => O
       end.
    End M.

    Definition measure_intra_state (s: RTLinject.intra_state) : nat :=
      match s with
        | RIInjectState _ _ _ _ _ _ is => measure_state is
        | _ => O
      end.

    Definition inject_order : RTLinject.intra_stateRTLinject.intra_stateProp :=
      ltof _ measure_intra_state.

    Lemma inject_order_wf : well_founded inject_order.
Proof.
      now apply well_founded_ltof.
    Qed.

    Lemma begin_inject_inv stk' c' sp :
      forall {nd args param ns},
      tr_init c' ns args param nd
      ∀ rs',
      taustar tlts (State stk' c' sp ns rs')
              (State stk' c' sp nd (fold_left2 (fun q p a => q # (xI p) <- (q # (xO a))) rs' param args)).
Proof.
      induction 1. simpl. intros; left.
      intros rs'. simpl.
      eright. simpl. eapply exec_Iop; eauto. simpl. reflexivity.
      now apply IHtr_init.
    Qed.

    Lemma begin_inject_match_reg rs :
      ∀ args param rs',
      match_regset rs rs' →
      match_regset rs (fold_left2 (fun q p a => q # (xI p) <- (q # (xO a))) rs' param args).
Proof.
      induction args. destruct param; easy.
      intros [|p param]. easy.
      intros rs' H. eapply IHargs.
      intros r. now rewrite Regmap.gso.
    Qed.

    Lemma begin_inject_match_ireg rs :
      ∀ args param rs',
      ∀ acc acc',
      match_regset rs rs' →
      match_regset rs acc' →
      match_inject_regset acc acc' →
      match_inject_regset (fold_left2 upd acc param (map rs args))
                          (fold_left2 (fun q p a => q # (xI p) <- (q # (xO a))) acc' param args).
Proof.
      induction args.
      now intros [|] rs' acc acc' ? ? ?; simpl.
      intros [|p param] rs' acc acc' REGS RS ACC. easy.
      simpl. eapply IHargs. eassumption.
      intros r'. now rewrite Regmap.gso.
      intros r'.
      unfold upd. eq_case. intros ->. rewrite Regmap.gss. auto.
      intros K. rewrite Regmap.gso. auto. congruence.
    Qed.

    Lemma begin_inject_only_int :
      ∀ args param rs',
        only_int rs' →
        only_int (fold_left2 (fun q p a => q # (xI p) <- (q # (xO a))) rs' param args).
Proof.
      induction args. intros []; easy.
      intros [|p param] rs' H. easy.
      simpl. apply IHargs. intros r.
      case (peq r (xI p)). intros ->. rewrite Regmap.gss. apply H.
      intros K. rewrite Regmap.gso. eapply H. exact K.
    Qed.

    Lemma end_inject_inv stk' c' sp :
      forall {ns res dst ne nd},
      resnil
      tr_stmt bi c' (INJECT.Sreturn res) ns dst ne nd
      ∀ rs',
      ∃ t,
        stepr tlts (State stk' c' sp ns rs') Events.TEtau t
      ∧ taustar tlts t
      (State stk' c' sp ne (fold_right2 (fun q p a => q # p <- (q # (xI a))) rs' dst res)).
Proof.
      induction res. clarify.
      intros [|d dst] ne nd _ H rs'; inv H.
      destruct res as [|r res]; inv RET.
      simpl. eexists. split;[|left]. eapply exec_Iop; eauto. simpl. reflexivity.
      simpl.
      assert (r::resnil) as Q by discriminate.
      assert (tr_stmt bi c' (INJECT.Sreturn (r::res)) ns (t::tgtl) ns0 nd) as K by vauto.
      destruct (IHres _ _ _ Q K rs') as (s & Hs & Hss).
      exists s. intuition.
      eapply taustar_trans. eassumption.
      eright. simpl.
      eapply exec_Iop; eauto. simpl. reflexivity.
      left.
    Qed.

    Lemma end_inject_match_reg rs irs rs':
      match_regset rs rs' →
      match_inject_regset irs rs' →
      ∀ res dst,
        match_regset (reg_upd rs dst (map irs res))
                     (fold_right2 (fun q p a => q # p <- (q # (xI a)))
                                  rs' (map xO dst) res).
Proof.
      intros REGS IREGS.
      induction res; intros [|d dst]; simpl; try easy.
      intros r'. unfold reg_upd. simpl. unfold upd at 1.
      eq_case. intros ->. rewrite Regmap.gss.
      clear -IREGS. generalize dependent dst.
      induction res; intros [|d dst]; try easy.
      simpl. rewrite Regmap.gso. intuition. congruence.
      intros K. rewrite Regmap.gso. apply IHres. congruence.
    Qed.

    Lemma end_inject_only_int rs':
      only_int rs' →
      ∀ res dst,
        only_int (fold_right2 (fun q p a => q # p <- (q # (xI a)))
                              rs' (map xO dst) res).
Proof.
      intros INTS.
      induction res; intros [|d dst]; simpl; try assumption.
      intros r'. case (peq r' (xO d)). intros ->.
        rewrite Regmap.gss. apply IHres.
      intros K. rewrite Regmap.gso. apply IHres. exact K.
    Qed.

    Lemma fw_sim : forward_sim_with_undefs2 lts tlts match_state inject_order.
Proof.
      intros s t l s' SSTEP MS.
      inv SSTEP; inv STEP; inv MS; simpl in TE; clarify;
      try pose proof (CODE _ _ PC) as PC'.
      right; right. eexists. split; vauto. eexists; eexists; split. left. split;[|left].
      inv PC'; vauto.
      pose proof (Op.eval_condition_lessdef _ (match_args_lessdef REGS _) COND) as COND'.
      right; right. eexists. split; vauto. eexists; eexists; split. left. split;[|left].
      inv PC'; vauto.
      pose proof (Op.eval_condition_lessdef _ (match_args_lessdef REGS _) COND) as COND'.
      right; right. eexists. split; vauto. eexists; eexists; split. left. split;[|left].
      inv PC'; vauto.

      inv PC'.
      pose proof (match_eval_op OKOP (match_args_lessdef REGS args) OP) as (v' & K1 & K2).
      right; right. eexists. split; vauto. eexists; eexists; split. left. split;[|left]. vauto.
      econstructor; eauto.
      intros r. case (peq r (xO res)). intros ->.
      rewrite Regmap.gss.
      apply (eval_op_int INTS OKOP K1).
      intros K. now rewrite Regmap.gso.
      assert (rs' # (xO fp) = Vptr pfp).
        pose proof (REGS fp) as K; rewrite FP in K. now inv K.
      right. eexists. exists (rs' # (xO arg)::nil). split. vauto.
      split. eexists. eexists. split. left. split;[|left].
      inv PC'; vauto. vauto.

      destruct (match_find_function REGS _ _ FUNC) as (fd' & Hfd' & K). inv K.
      right; right. eexists. split; vauto. eexists; eexists; split. left. split;[|left].
      now inv PC'; vauto. econstructor; vauto. now eapply match_args_lessdef.
      clear -INTS. induction args; simpl. intuition. intros v [<-|H]. apply INTS. intuition.
      right; right. eexists. split; vauto. eexists; eexists; split. left. split;[|left].
      now inv PC'; vauto. econstructor; vauto. now eapply match_args_lessdef.
      clear -INTS. induction args; simpl. intuition. intros v [<-|H]. apply INTS. intuition.

      inv FD.
      right. eexists. split; vauto. eexists; eexists; split. left. split;[|left].
      vauto. econstructor; eauto. now apply match_init_regs.
      simpl. clear -INTS. generalize dependent args'. induction param. intros args' H r. simpl. rewrite Regmap.gi. easy.
      intros [|x args]. simpl. intros _ r; simpl; rewrite Regmap.gi; easy.
      simpl.
      intros H r. case (peq r (xO a)). intros ->. now rewrite Regmap.gss; intuition.
      intros K. rewrite Regmap.gso. apply IHparam. intros y A. apply H. intuition. intuition.

      inv FD.
      right; right. eexists. split; vauto. eexists; eexists; split. left. split;[|left].
      vauto. econstructor; eauto. now apply match_init_regs.
      simpl. clear -INTS. generalize dependent args'. induction param; simpl. intros ? _ r. now rewrite Regmap.gi.
      intros [|x args'] INTS. intros r; now rewrite Regmap.gi.
      intros r. case (peq r (xO a)). intros ->. rewrite Regmap.gss. intuition.
      intros K. rewrite Regmap.gso; intuition. apply IHparam. intros v H. apply INTS. intuition.

      inv FD.
      right. eexists. split; vauto. eexists; eexists; split. left. split;[|left].
      econstructor; eauto.
      clear -ARGS. generalize dependent args'. induction eargs. simpl in *. now inversion 1.
      intros args' ARGS. inv ARGS. simpl. f_equal. now inv H1. now intuition.

      right. eexists. split; vauto. eexists; eexists; split. left. split;[|left].
      econstructor; eauto. destruct sg.(Ast.sig_res); congruence.

      inv STK. inv H1.
      right; right. eexists. split; vauto. eexists; eexists; split. left. split;[|left].
      vauto. simpl. econstructor; eauto.
      inv STK.
      right. eexists. split; vauto. eexists; eexists; split. left. split;[|left].
      vauto.

      right. eexists. split; vauto. eexists; eexists; split. left. split;[|left].
      change (rs' # (xO res)) with (regmap_optget (Some (xO res)) Vundef rs').
      inv PC'. vauto.
      right; right. eexists. split; vauto. eexists; eexists; split. left. split;[|left].
      change (rs' # (xO res)) with (regmap_optget (Some (xO res)) Vundef rs').
      inv PC'. vauto.

      right; right.
      inv PC'.
      pose proof (begin_inject_inv stk' c' sp INIT rs') as INIT'.
      eexists. split. eexists; eexists. split. left.
      split. 2: apply INIT'. vauto.
      econstructor; eauto.
      now apply begin_inject_match_reg.
      eapply begin_inject_match_ireg; eauto. vauto.
      now apply begin_inject_only_int.
      vauto.

      destruct is0.
      inv TS. inv INJECT. 2: inv TK. 2: eelim EV; reflexivity.
      simpl in TE; inv TE. clear EV.
      right; left. split.
      unfold inject_order, ltof. simpl. auto with arith.
      inv TK. vauto.

      inv INJECT. simpl in TE; inv TE; clear EV.
      inv TS.
      right; left. split.
      unfold inject_order, ltof. simpl. auto with arith.
      vauto.
      now elim OK_BI.

      Hint Constructors tr_stmt.
      inv TS. inv INJECT. simpl in TE; inv TE. clear EV.
      destruct (match_eval_op OP (match_iargs_lessdef IREGS args) H6)
               as (v' & Hv' & Hvv').
      right; right. eexists. split.
      eexists; eexists. split. left. split;[|left].
      vauto. econstructor; eauto.
      intros r. case (peq r (xI dst0)). intros ->.
      rewrite Regmap.gss.
      apply (eval_op_int INTS OP Hv').
      intros K. now rewrite Regmap.gso.

      inv TS. inv INJECT. simpl in TE; inv TE. clear EV.
      pose proof (match_eval_addressing (match_iargs_lessdef IREGS args) H8).
      right. eexists. split. eexists; eexists. split. left. split;[|left].
      vauto.
      intros v' Hvv'. eexists. split. simpl. econstructor.
      eapply RTLI_inject_step with (ev := INJECT.TEtso (INJECT.TSOmem (INJECT.MEread ap inbuf a v'))).
      econstructor; vauto.
      destruct v'; trivial; inv Hvv'. solve by inversion.
      congruence. easy. reflexivity.
      econstructor; eauto.

      inv TS. inv INJECT. simpl in TE; inv TE. clear EV.
      pose proof (match_eval_addressing (match_iargs_lessdef IREGS args) H8).
      right. eexists. exists (Events.cast_value_to_chunk Ast.Mint32 (rs' # (xI dst0))).
      split. generalize (IREGS dst0). destruct (irs dst0); inversion 1; clarify.
      split. eexists; eexists. split. left. split;[|left].
      red. red.
      eapply exec_Istore; eauto.
      simpl. generalize (INTS (xI dst0)). now destruct (rs' # (xI dst0)).
      vauto.

      inv TS. inv INJECT. inv ASME; simpl in TE; inv TE; clear EV.
      destruct args as [|q [|r [|s [|]]]]; clarify. simpl in *; clarify.
      right. eexists. split. eexists; eexists. split. left. split;[|left].
      simpl. eapply exec_Iatomic. eassumption. simpl.
      generalize (IREGS q). destruct (irs q); clarify; inversion 1.
      generalize (IREGS r). destruct (irs r); clarify; inversion 1;
      generalize (IREGS s); destruct (irs s); clarify; inversion 1;
      vauto.
      reflexivity. assumption.
      intros v' Hv'. eexists. split. econstructor; eauto. econstructor; eauto.
      econstructor. simpl. rewrite <- H2. eapply INJECT.atomic_statement_mem_event_cas with (v:=v'); eauto.
      reflexivity. destruct v'; clarify. inv Hv'. inv HTv. discriminate. reflexivity.
      econstructor; eauto.


      inv TS. inv INJECT. simpl in TE; inv TE. clear EV.
      right. eexists. split. eexists; eexists. split. left. split;[|left].
      vauto. vauto.
      destruct l; try destruct ev; clarify. right.
      eexists. split. eexists; eexists. split. left. split;[|left].
      vauto. vauto.

      inv TS. inv INJECT; simpl in TE; inv TE; clear EV;
      pose proof (Op.eval_condition_lessdef _ (match_iargs_lessdef IREGS _) H7) as COND'.
      right; right. eexists. split. eexists; eexists. split. left. split;[|left].
      vauto. vauto.
      right; right. eexists. split. eexists; eexists. split. left. split;[|left].
      vauto. vauto.

      inv TS. inv INJECT; simpl in TE; inv TE; clear EV;
      pose proof (Op.eval_condition_lessdef _ (match_iargs_lessdef IREGS _) H6) as COND'.
      right; right. eexists. split. eexists; eexists. split. left. split;[|left].
      vauto. econstructor; eauto. vauto.
      right; right. eexists. split. eexists; eexists. split. left. split;[|left].
      vauto. econstructor; eauto. vauto.

      inv INJECT; simpl in TE; inv TE; clear EV.
      right; left. split.
      unfold inject_order, ltof. simpl. zify. omega.
      inv TS.
      econstructor; eauto.

      inv TS. inv INJECT; simpl in TE; inv TE; clear EV.
      right; left. split.
      unfold inject_order, ltof. simpl. zify. omega.
      vauto.

      inv INJECT. eelim EV; reflexivity.
      simpl in LOW. now apply False_ind.

      inv INJECT.
      eelim EV; reflexivity.
      simpl in TE; clarify.
      simpl in LOW. now apply False_ind.

      inv INJECT; simpl in TE; inv TE.
      right; left. split.
      unfold inject_order, ltof. simpl. auto with arith.
      inv TS. vauto.

      simpl in LOW. now apply False_ind.
      simpl in LOW. now apply False_ind.

      inv INJECT; simpl in TE; inv TE.
      right; left. split.
      unfold inject_order, ltof. simpl. auto with arith.
      inv TS. vauto.

      inv INJECT; simpl in TE; inv TE.
      right; left. split.
      unfold inject_order, ltof. simpl. auto with arith.
      inv TS. vauto.

      inv INJECT; simpl in TE; inv TE.
      right; left. split.
      unfold inject_order, ltof. simpl. auto with arith.
      inv TS. vauto.

      inv INJECT.
      destruct res0 as [|r res].
      right; left. inv TS.
      split. unfold inject_order, ltof. simpl. intuition.
      econstructor; eauto.
      destruct dst; clarify.
      right; right.
      assert (r::resnil) as Q by discriminate.
      pose proof (end_inject_inv stk' c' sp Q TS rs') as (t & Ht).
      eexists. split. eexists; eexists. split. left. apply Ht.
      econstructor; eauto.
      apply end_inject_match_reg; eauto.
      apply end_inject_only_int; eauto.

      left. eapply ev_stuck_or_error_error; vauto.
      left. eapply ev_stuck_or_error_error; vauto.
    Qed.

    Definition bsim_rel := @bsr _ lts tlts match_state.
    Definition bsim_order := @bsc _ tlts.

    Lemma init_sim_succ:
      forall {p vals vals' tinit},
        rtl_init tge p vals = Some tinit ->
        Val.lessdef_list vals' vals
        exists sinit, rtl_inject_init ge p vals' = Some sinit /\ bsim_rel tinit sinit.
Proof.
      unfold rtl_inject_init, rtl_init.
      intros p vals vals' tinit INIT LD.
      destruct TRANSF as (MG & MF). specialize MF with p.
      repeat (destruct Genv.find_funct_ptr; clarify).
      destruct f0.
      2: now inv MF.
      pose proof (transl_fundef_correct MF) as K; inv K; clear MF.
      simpl in *.
      rewrite (lessdef_list_length LD).
      bif2.
      eexists. split. reflexivity.
      econstructor; eauto. split. econstructor; vauto.
      3: left; left.
      generalize (Ast.sig_args sg).
      clear -LD. induction LD.
        induction l; simpl; vauto.
      induction l; simpl; vauto.
      econstructor; eauto. now apply Val.conv_lessdef.
      clear -SIG. generalize dependent SIG. generalize (Ast.sig_args sg). clear sg.
      induction vals. induction l; simpl; intuition. subst; vauto.
      destruct l; simpl. intuition.
      intros SIG v [K|K].
      assert (t = Ast.Tint) as ->. now apply SIG; left.
      destruct a; simpl in K; subst; vauto.
      apply (IHvals l). intuition.
      exact K.
    Qed.

    Lemma init_sim_fail:
      forall p vals vals',
        rtl_init tge p vals = None ->
        Val.lessdef_list vals' vals
        rtl_inject_init ge p vals' = None.
Proof.
      unfold rtl_inject_init, rtl_init.
      intros p vals vals' INIT LD.
      destruct TRANSF as (MG & MF). specialize MF with p.
      repeat (destruct Genv.find_funct_ptr; clarify).
      destruct f0.
      pose proof (transl_fundef_correct MF) as K; inv K; clear MF.
      simpl in *.
      rewrite (lessdef_list_length LD).
      bif2.
      reflexivity.
    Qed.

  End SIM.

Ltac bind_inv :=
  match goal with
    | [H: bind ?f ?g = OK ?y |- _] =>
      destruct (bind_inversion f g H) as
          (? & ?Hbind & ?Hbind' );
      clear H
  end.

 Theorem rtlgen_sim : Sim.sim RtlInjectSem rtl_sem match_prg.
Proof.
  eapply (TSOsim_with_undefs.sim RtlInjectSem rtl_sem genv_rel
    bsim_rel (fun _ => bsim_order));
      unfold match_prg; simpl; intros.
  destruct GENVR as [GR FR]. rewrite GR.
    now rewrite (Ast.transform_partial_program_main _ _ MP).
  eapply Genv.exists_matching_genv_and_mem_rev
      with (match_var := fun a b => a = b), INIT.
    eby eapply Ast.transform_partial_program_match.
  apply (init_sim_succ _ _ GENVR INIT LD).
  apply (init_sim_fail _ _ GENVR _ _ _ INITF LD).

    apply forward_to_backward_sim_with_undefs with (fsc:= inject_order).
    apply rtli_receptive.
    apply rtl_sem.(TSOmachine.SEM_determinate).
    simpl. intros s. destruct (classic (∃l, ∃s', rtl_step' sge s l s')) as [K|K].
    now right. left. intros s' l K'. apply K. exists l; exists s'. assumption.
    apply Events.ldo_samekind_eq.
    apply Events.ldo_not_tau.
    apply Events.ldi_refl.
    split. exact inject_order_wf.
    apply mk_forward_sim_with_undefs.
    exact inject_order_wf.
    now apply fw_sim.
 Qed.

End CORRECT.