Module SimulationByRefines


Require Import Utf8 Coqlib.
Require Import Maps.
Require Import Ast.
Require Import Integers.
Require Import Pointers.
Require Import Values.
Require Import Mem.
Require Import Events.
Require Import Globalenvs.
Require Import Op.
Require Import Registers.
Require Import Libtactics.
Require Import INJECT.
Require Import Utils.
Require Import RTLinject.
Require Import TSOmachine.
Require Import Classical.
Require Import Relations.
Require Import INJECT.
Require Import Permissions Emem MemoryMachine TSOMemoryMachine
 RTLinject RefinesDefs RefinesUtils AllRefinesRulesAux.

Lemma safe_True: forall tid b m, safe tid b m.
Proof.
compute; auto. Qed.
Hint Resolve safe_True.

Section backwardsim_from_RTLinject_smallstep.

Variable ge : genv.

Inductive atrace_inv t : (tsomem * intra_state)%type -> list thread_event -> (tsomem * intra_state)%type -> Prop :=
| atrace_inv_nil : forall s, atrace_inv t s nil s
| atrace_inv_cons : forall s0 m st e m' st' l
   (AT1:intra_step ge t (m, st) e s0)
   (AT2:atrace_inv t s0 l (m', st'))
   (AT3:e<>TEtso TSObeginatomic)
   (AT4:forall f, e<>TEtso (TSOendatomic f))
   (AT5:forall ev, e<>TEend ev),
   atrace_inv t (m,st) (l++e::nil) (m',st').



Inductive trace_inv : RTLinject.state -> list (thread_id * list thread_event) -> RTLinject.state -> Prop :=
| trace_inv_nil : forall s0, trace_inv s0 nil s0
| trace_inv_cons : forall tr s1 e s2 s3
  (HT1: trace_inv s2 tr s3)
  (HT2: astep ge s1 e s2),
  trace_inv s1 (tr++e::nil) s3.

Lemma trace_inv_eq1: forall s1 tr s2,
  trace_inv s1 tr s2 -> forall e s3,
  astep ge s2 e s3 -> trace_inv s1 (e::tr) s3.
Proof.
  induction 1; intros.
  > replace (e::nil) with (nil++e::nil) by auto.
    econstructor; eauto.
    constructor.
  > replace (e0::tr++e::nil) with ((e0::tr)++e::nil) by auto.
    econstructor; eauto.
Qed.

Lemma trace_inv_eq2: forall s1 tr s2,
  trace ge s1 tr s2 -> forall e s0,
  astep ge s0 e s1 -> trace ge s0 (tr++e::nil) s2.
Proof.
  induction 1; intros.
  > simpl.
    econstructor; eauto.
    constructor.
  > simpl.
    econstructor; eauto.
Qed.

Lemma trace_inv_eq: forall s1 tr s2,
  trace ge s1 tr s2 <-> trace_inv s1 tr s2.
Proof.
  split; induction 1; try constructor.
  eapply trace_inv_eq1; eauto.
  eapply trace_inv_eq2; eauto.
Qed.

Lemma trace_step_right : forall s1 tr s2,
  trace ge s1 tr s2 -> forall s0 e,
  astep ge s0 e s1 ->
  trace ge s0 (tr++e::nil) s2.
Proof.
  induction 1; intros; simpl; econstructor; eauto.
  econstructor.
Qed.

Lemma trace_app_inv : forall tr1 s1 tr2 s2,
  trace ge s1 (tr1++tr2) s2 ->
  exists s, trace ge s1 tr2 s /\ trace ge s tr1 s2.
Proof.
  induction tr1; simpl; intros.
  exists s2; repeat (auto; constructor).
  inv H.
  destruct IHtr1 with (1:=HT1) as (s & S1 & S2).
  econstructor; split; eauto.
  econstructor; eauto.
Qed.

Lemma trace_app : forall s2 tr1 s3,
  trace ge s2 tr1 s3 ->
  forall tr2 s1,
  trace ge s1 tr2 s2 ->
  trace ge s1 (tr1++tr2) s3.
Proof.
  induction 1; simpl; intros; auto.
  econstructor; eauto.
Qed.

Definition filter_not_tid {A:Type} tid (l:list (thread_id * A)) : list (thread_id * A) :=
  filter (fun tid_e => negb (peq tid (fst tid_e))) l.
  
Lemma filter_not_tid_app : forall A tid (l1 l2:list (thread_id*A)),
  filter_not_tid tid (l1++l2) = (filter_not_tid tid l1)++(filter_not_tid tid l2).
Proof.
  intros; unfold filter_not_tid.
  rewrite filter_app; auto.
Qed.

Lemma In_filter : forall A f (l:list A) x,
  In x (filter f l) -> f x = true /\ In x l.
Proof.
  induction l; simpl.
  intuition.
  intros x H.
  case_eq (f a); intros Hf; rewrite Hf in *; auto.
  destruct H; subst.
  intuition.
  destruct (IHl x); auto.
  destruct (IHl x); auto.
Qed.

Lemma f_true_In_filter : forall A f (l:list A) x,
  f x = true -> In x l -> In x (filter f l).
Proof.
  induction l; simpl; intuition.
  subst; rewrite H; left; auto.
  destruct (f a); auto with datatypes.
Qed.

Lemma filter_id : forall A (f:A->bool) (l:list A),
  (forall x, In x l -> f x = true) ->
  filter f l = l.
Proof.
  induction l; simpl; auto.
  case_eq (f a); intros; auto.
  rewrite IHl; auto.
  rewrite H0 in H; auto; congruence.
Qed.

Lemma filter_nil : forall A (f:A->bool) (l:list A),
  (forall x, In x l -> f x = false) ->
  filter f l = nil.
Proof.
  induction l; simpl; auto.
  case_eq (f a); intros; auto.
  rewrite H0 in H; auto; congruence.
Qed.

Lemma filter_filter : forall A f (l:list A),
  filter f (filter f l) = filter f l.
Proof.
  intros; rewrite filter_id; auto.
  intros; eelim In_filter; eauto.
Qed.

Lemma app_eq_nil: forall A (l1 l2:list A),
  l1 ++ l2 = nil -> l1 = nil /\ l2 = nil.
Proof.
  induction l1; simpl; intros.
  split; auto.
  inv H.
Qed.

Lemma filter_cons_inv : forall A f (l l2:list A) x,
  filter f l = x :: l2 ->
  exists l1', exists l2',
    l=l1'++x::l2' /\
    (forall y, In y l1' -> f y = false) /\
    l2 = filter f l2'.
Proof.
  induction l; simpl; intros.
  inv H.
  case_eq (f a); intros Ha; rewrite Ha in *.
  > inv H.
    exists nil; exists l; simpl; intuition.
  > elim (IHl _ _ H); intros l1' (l2' & T1 & T2 & T3).
    exists (a::l1'); exists l2'; repeat split; auto.
    > subst; simpl; auto.
    > simpl; destruct 1; subst; auto.
Qed.

Lemma filter_app_inv : forall A f (l l1 l2:list A),
  filter f l = l1++l2 ->
  exists l1', exists l2',
    l=l1'++l2' /\
    l1 = filter f l1' /\
    l2 = filter f l2'.
Proof.
  induction l; simpl; intros.
  assert (l1 = nil /\ l2 = nil) by (eapply app_eq_nil; eauto).
  exists nil; exists nil; simpl; intuition.
  case_eq (f a); intros Ha; rewrite Ha in *.
  > destruct l1.
    > destruct l2; inv H.
      > exists nil; exists (a0::l); split; auto.
        split; auto.
        simpl.
        rewrite Ha.
        congruence.
    > inv H.
      eelim IHl; eauto; intros l1' (l2' & L1 & L2 & L3).
      exists (a0::l1'); exists l2'; split; auto.
      simpl; congruence.
      simpl; rewrite Ha; split; congruence.
  > eelim IHl; eauto; intros l1' (l2' & L1 & L2 & L3).
      exists (a::l1'); exists l2'; split; auto.
      simpl; congruence.
      simpl; rewrite Ha; split; congruence.
Qed.

Lemma filter_not_tid_cons: forall A tid tid' (e:A) tr,
  tid <> tid' ->
  filter_not_tid tid ((tid', e)::tr) = (tid',e) :: filter_not_tid tid tr.
Proof.
  intros; simpl; destruct peq; intuition.
Qed.

Lemma In_filter_not_tid_iff: forall A tid tid' (e:A) tr,
  tid <> tid' ->
  (In (tid', e) tr <-> In (tid',e) (filter_not_tid tid tr)).
Proof.
  induction tr; simpl; intuition.
  inv H3.
  destruct peq; simpl in *; subst; intuition.
  destruct peq; simpl in *; subst; intuition.
  destruct peq; simpl in *; subst; intuition.
Qed.

Lemma filter_not_tid_app_cons : forall A (e:A) tid tid' tr1 tr2 tr,
  tid <> tid' ->
  filter_not_tid tid tr = filter_not_tid tid (tr1 ++ (tid', e) :: tr2) ->
  exists tr1', exists tr2',
    tr = tr1' ++ (tid', e) :: tr2' /\
    filter_not_tid tid tr1 = filter_not_tid tid tr1' /\
    filter_not_tid tid tr2 = filter_not_tid tid tr2'.
Proof.
  intros.
  rewrite filter_not_tid_app in H0.
  unfold filter_not_tid in *.
  eelim filter_app_inv; eauto; intros l1 (l2 & T1 & T2 & T3).
  simpl in T3; destruct peq; simpl in T3; intuition.
  elim filter_cons_inv with (1:=sym_eq T3); intros l1' (l2' & T1' & T2' & T3').
  exists (l1++l1'); exists l2'.
  split.
  subst; simpl; auto with datatypes.
  split.
  rewrite filter_app.
  rewrite T2.
  assert (forall A (l1 l2:list A), l2=nil -> l1 = l1 ++ l2).
    intros; subst; auto with datatypes.
  apply H1.
  apply filter_nil; auto.
  auto.
Qed.

Lemma filter_not_tid_app_cons_eq : forall A (e:A) tid tr,
  filter_not_tid tid (tr ++ (tid, e) :: nil) = filter_not_tid tid tr.
Proof.
  intros; rewrite filter_not_tid_app; simpl.
  destruct peq; simpl; intuition.
Qed.

  

Lemma filter_fullevent_list_nil : forall l,
  (forall e, ~ In (TEext e) l) ->
  filter_fullevent_list l = nil.
Proof.
  induction l; simpl; auto.
  destruct a; intros;
    try (apply IHl; red; intros; eelim H; eauto; fail).
  eelim H; eauto.
Qed.

Lemma filter_not_tid_eq_filter_fullevent : forall tid tr,
  (forall e l, In (tid,l) tr -> ~ In (TEext e) l) ->
  filter_fullevent tr = filter_fullevent (filter_not_tid tid tr).
Proof.
  induction tr; simpl; auto.
  destruct a; simpl; intros.
  destruct peq; simpl; subst.
  rewrite filter_fullevent_list_nil; eauto.
  rewrite IHtr; auto.
Qed.

Variable wf_state: RTLinject.state -> Prop.


Definition almost_high_trace (s1: RTLinject.state) (tr: list (thread_id * list thread_event)) (s2:RTLinject.state) : Prop :=
  trace ge s1 tr s2 /\
  forall id tr1 tr2,
    tr = tr1++(id,TEbegin BeginLow::nil)::tr2 ->
    (forall ev' l, In (id,l) tr1 -> ~ In (TEend ev') l) /\ forall k, In (id,TEbegin k::nil) tr2 -> k = BeginHigh.

Definition refines_smallstep (stmt1 stmt2:statement) : Prop :=
  forall ge sp t m rs tr st stf e,
    Env.trace ge sp t (m,NormalState rs stmt1 Kend) tr st ->
    Env.intra_step ge sp t st (TEend e) stf ->
    exists st',
      Env.trace ge sp t (m,NormalState rs stmt2 Kend) tr st' /\
      Env.intra_step ge sp t st' (TEend e) stf.

Definition ge_correct_wrt_refines (refines:statement->statement->Prop) (ge:genv) : Prop :=
  forall b f,
    Genv.find_funct_ptr ge b = Some (Internal f) ->
    forall pc inj args dst s,
      (fn_code f)!pc = Some (Iinject inj args dst s) ->
      refines inj.(ic_stmt_low) inj.(ic_stmt_high).

Lemma atrace_no_end: forall tid l m s' m' s'',
  atrace ge tid (m, s') l (m', s'') ->
  forall k, ~ In (TEend k) l.
Proof.
  induction l; simpl; intros.
  auto.
  inv H; intros T; destruct T; subst.
  > eelim AT5; eauto.
  > eelim IHl; eauto.
Qed.

Lemma rtl_step_injected_state: forall s e s',
  rtli_step ge s e s' ->
  inject_state s -> inject_state s' \/ (exists ev, e = TEend ev).
Proof.
  intros.
  inv H; simpl in *; eauto.
Qed.

Lemma trace_with_two_begins_aux : forall s1 s2 tr,
  trace ge s1 tr s2 ->
  (forall tr1 id k tr2,
    tr = tr1 ++ (id, TEbegin k::nil) :: tr2 ->
    (forall ev' l, In (id, l) tr1 -> ~ In (TEend ev') l) ->
    let '(tso, st) := s2 in
      match st!id with
        | Some s => inject_state s
        | None => false
      end).
Proof.
  induction 1; intros.
  > generalize (refl_equal (length (tr1 ++ (id, TEbegin k::nil) :: tr2))).
    rewrite <- H at 1; rewrite app_length; simpl.
    by intros; apply False_ind; omega.
  > destruct tr1; inv H0.
    Ltac case_sp := try match goal with
                      | id: _ = match ?sp with
                                  | Some _ => _
                                  | None => _ end |- _ => destruct sp; inversion id; fail
                    end.
    Ltac absurd_inject_step := try match goal with
        | id: INJECT.step _ _ _ _ _ |- _ => inversion H3; congruence
      end.
    > inv HT2.
      > rewrite PTree.gss.
        inv AS1.
        inv ST; simpl; auto; case_sp; congruence.
      > rewrite PTree.gss.
        inv AS5; simpl; auto; case_sp; congruence.
    > exploit IHtrace; eauto with datatypes; clear IHtrace.
      destruct s0 as (m1 & st1).
      destruct s2 as (m2 & st2).
      case_eq (st1!id); try congruence; intros.
      inv HT2; auto; autorw'.
      > rewrite PTree.gsspec; destruct peq; [subst|eauto]; autorw'.
        inv AS1; try congruence.
        > exploit rtl_step_injected_state; eauto.
          destruct 1 as [S|(ev & S)]; auto; subst.
          eelim H1; eauto with datatypes.
        > exploit rtl_step_injected_state; eauto.
          destruct 1 as [S|(ev & S)]; auto; congruence.
      > repeat (rewrite PTree.gsspec; destruct peq; try congruence).
        > inv AS1; try congruence.
          inv ST; simpl; auto; autorw'.
        > rewrite H0; auto.
      > rewrite PTree.gsspec; destruct peq; [subst|eauto]; autorw'.
        inv AS1; try congruence.
        inv ST; simpl; auto; autorw'.
      > rewrite PTree.grspec; destruct peq; [subst|eauto]; autorw'.
        inv AS1; try congruence.
        inv ST; simpl; auto; autorw'.
        inv INJECT.
      > rewrite PTree.gsspec; destruct peq; [subst|eauto]; autorw'.
        inv AS1; try congruence.
        inv AS5; simpl; auto.
Qed.

Lemma atrace_keep_inject_state: forall t l m' s s'' m,
  inject_state s ->
  atrace ge t (m, s) l (m', s'') ->
  inject_state s''.
Proof.
  induction l; simpl; intros.
  inv H0; eauto.
  inv H0.
  exploit IHl; eauto; intros S1.
  inv AT1.
  inv ST; eauto; try (eelim AT5; eauto; fail).
  inv ST; eauto; try (eelim AT5; eauto; fail).
Qed.

Lemma atrace_no_begin: forall tid s l m s' m' s'',
  rtli_step ge s (TEtso TSObeginatomic) s' ->
  atrace ge tid (m, s') l (m', s'') ->
  forall k, ~ In (TEbegin k) l.
Proof.
  induction l; simpl; intros.
  auto.
  inv H0; intros T; destruct T; subst.
  assert (inject_state s').
    inv H; auto; case_sp; congruence.
    exploit atrace_keep_inject_state; eauto.
    destruct st; auto.
    destruct is; auto.
    inv AT1.
    inv ST.
    inv INJECT.
    inv AT1.
    inv ST.
    inv INJECT.
    edestruct IHl; eauto.
Qed.

Lemma trace_with_two_begins : forall tr1 s1 s2 tr,
  trace ge s1 tr s2 ->
  (forall id k tr2,
    tr = tr1 ++ (id, TEbegin k::nil) :: tr2 ->
    (forall ev' l, In (id, l) tr1 -> ~ In (TEend ev') l) ->
    forall k' l, In (id,l) tr1 -> ~ In (TEbegin k') l).
Proof.
  induction tr1.
  intuition.
  red; intros.
  simpl in H2; destruct H2.
  > subst.
    inv H.
    exploit trace_with_two_begins_aux; eauto with datatypes.
    destruct s0.
    inv HT2.
    > rewrite AS3.
      simpl in H3; destruct H3; subst; try (intuition; fail).
      inv AS1.
      inv ST; simpl; auto.
      inv INJECT.
    > simpl in H3; destruct H3; try congruence; try (intuition; fail).
    > simpl in H3; destruct H3; try congruence; try (intuition; fail).
    > simpl in H3; destruct H3; try congruence; try (intuition; fail).
    > simpl in H3; destruct H3; try congruence; try (intuition; fail).
    > exploit atrace_no_begin; simpl; eauto.
      eauto with datatypes.
  > destruct tr; inv H0.
    inv H.
    eelim IHtr1; eauto with datatypes.
Qed.

Lemma filter_not_tid_eq_In : forall tid tid' (x:list thread_event) tr1 tr2,
  filter_not_tid tid tr1 = filter_not_tid tid tr2 ->
  tid <> tid' ->
  In (tid',x) tr1 -> In (tid',x) tr2.
Proof.
  intros.
  assert (In (tid',x) (filter_not_tid tid tr1)).
    unfold filter_not_tid; apply f_true_In_filter; auto.
    simpl; destruct peq; auto.
  rewrite H in H2.
  unfold filter_not_tid in *.
  apply In_filter in H2; destruct H2 ;auto.
Qed.
Hint Resolve filter_not_tid_eq_In.

Lemma atrace_no_ext: forall tid l m s' m' s'',
  inject_state s' ->
  atrace ge tid (m, s') l (m', s'') ->
  forall k, ~ In (TEext k) l.
Proof.
  induction l; simpl; intros.
  auto.
  inv H0; intros T; destruct T; subst.
  exploit atrace_keep_inject_state; eauto; intros.
  inv AT1.
  inv ST; simpl in H0; try congruence.
  inv INJECT.
  edestruct IHl; eauto.
Qed.

Lemma trace_with_pending_begin_no_ext : forall tr1 s1 s2 tr,
  trace ge s1 tr s2 ->
  (forall id k tr2,
    tr = tr1 ++ (id, TEbegin k :: nil) :: tr2 ->
    (forall ev' l, In (id, l) tr1 -> ~ In (TEend ev') l) ->
   forall k' l, In (id,l) tr1 -> ~ In (TEext k') l).
Proof.
  induction tr1.
  intuition.
  red; intros.
  simpl in H2; destruct H2.
  > subst.
    inv H.
    exploit trace_with_two_begins_aux; eauto with datatypes.
    inv HT2.
    > rewrite AS3.
      intros.
      simpl in H3; destruct H3; try (intuition; fail); subst.
      inv AS1.
      inv ST; simpl in H; try congruence.
      inv INJECT.
    > simpl in H3; destruct H3; try (intuition; fail); congruence.
    > simpl in H3; destruct H3; try (intuition; fail); congruence.
    > rewrite AS3; inv AS1.
      inv ST; simpl; try congruence.
      inv INJECT.
    > simpl in H3; destruct H3; try (intuition; fail); congruence.
    > rewrite AS3.
      intros.
      assert (inject_state s').
        inv AS1; auto.
      exploit atrace_no_ext; eauto.
  > destruct tr; simpl in H0; inv H0.
    inv H.
    eelim IHtr1; eauto with datatypes.
Qed.


Variable refines_implies_trace_transformation1: forall st1 tr1 tid tr2 st2 ev,
    wf_state st1 ->
    trace ge st1 ((tid,TEend ev::nil)::tr1++(tid, TEbegin BeginLow::nil)::tr2) st2 ->
    (forall ev' l, In (tid,l) tr1 -> ~ In (TEend ev') l) ->
    exists tr1',
      trace ge st1 ((tid,TEend ev::nil)::tr1'++(tid, TEbegin BeginHigh::nil)::tr2) st2 /\
      (forall ev' l, In (tid,l) tr1'-> ~ In (TEend ev') l) /\
      filter_not_tid tid tr1 = filter_not_tid tid tr1'.

Lemma almost_high_trace_and_one_step : forall s1 tr s2 e s3,
  wf_state s1 ->
  almost_high_trace s1 tr s2 ->
  astep ge s2 e s3 ->
  exists tr',
    almost_high_trace s1 tr' s3 /\ filter_fullevent tr' = filter_fullevent (e::tr).
Proof.
  intros s1 tr s2 e s3 WF Ha Hs.
  destruct Ha as [Ha1 Ha2].
  destruct e as (tid,e).
  destruct (classic (exists k, In (TEend k) e)) as [E|E].
  > destruct E as [k E].
    inv Hs;
      try (simpl in E; destruct E as [E|E]; [congruence|elim E]; fail);
      try (eelim atrace_no_end; eauto; fail).
    simpl in E; destruct E; [subst|intuition; fail].
    clear AS6 AS5 AS2.
    inv AS1.
    clear IS_not_mem.
    destruct (classic (In (tid,TEbegin BeginLow::nil) tr)) as [C|C].
    > exploit @In_eq_app; eauto; intros (tr1 & tr2' & HE); subst; clear C.
      exploit Ha2; eauto; intros (HH1 & HH2).
      elim refines_implies_trace_transformation1 with s1 tr1 tid tr2' (m',st!tid<-s') k;
        auto.
      2: repeat (econstructor; eauto); try congruence.
      clear refines_implies_trace_transformation1 HH1 HH2; intros tr1' (T1 & T2 & T3).
      exists ((tid, TEend k :: nil) :: tr1' ++ (tid, TEbegin BeginHigh :: nil) :: tr2').
      split; auto.
      > split; auto.
        intros is trr1 trr2 He.
        destruct trr1; inv He.
        exploit (eq_app_app _ _ _ _ H1); try congruence.
        clear H1; intros [(l & H1 & H2) | (l & H1 & H2)]; subst.
        > assert (Hdiff:is<>tid).
            intro; subst.
            inv T1.
            rewrite app_ass in HT1.
            exploit trace_app_inv; eauto; clear HT1 HT2.
            intros (ss & Hs1 & Hs2).
            eelim trace_with_two_begins with (1:=Hs1); eauto.
            > simpl; destruct 1.
              inv H; simpl; intuition congruence.
              eapply T2; eauto with datatypes.
            > left; eauto.
            > left; eauto.
          split.
          > simpl; intros ev' l0 HI2; destruct HI2 as [HI2|HI2].
            > inv HI2; intuition.
              > elim filter_not_tid_app_cons with (2:=T3); eauto.
                intros tr1' (tr2'' & T1' & T2' & T3').
                elim Ha2 with is tr1' (tr2'' ++ (tid, TEbegin BeginLow::nil) :: tr2').
                > intros Hn1 Hn2.
                  apply Hn1; auto.
                  rewrite (In_filter_not_tid_iff _ tid); auto.
                  rewrite (In_filter_not_tid_iff _ tid) in HI2; auto.
                  congruence.
                > by subst; repeat (simpl; rewrite app_ass); auto.
          > intros.
            rewrite in_app in H; simpl in H.
            destruct H.
            > destruct (in_split _ _ H) as (l1&l2&L); subst; clear H.
              destruct filter_not_tid_app_cons with (list thread_event) (TEbegin k0::nil) tid is
                (trr1++(is,TEbegin BeginLow::nil) :: l1) l2 tr1
                as (tr4'' & tr2'' & U1 & U2 & U3); eauto.
              repeat (rewrite app_ass; simpl); simpl; eauto.
              subst.
              destruct k0; auto.
              eelim (Ha2 is tr4''); [idtac|repeat (rewrite app_ass; simpl); eauto].
              intros He _.
              inv T1.
              exploit (trace_with_two_begins
                (trr1 ++ (is, TEbegin BeginLow::nil) :: l1) _ _ _ HT1 is BeginLow);
                eauto with datatypes.
              > repeat (rewrite app_ass; simpl); simpl; eauto.
               > intuition.
            > destruct H; [inv H;auto|eauto].
              destruct (in_split _ _ H) as (l1&l2&L); subst; clear H.
              destruct k0; auto.
              destruct Ha2 with is (tr1 ++ (tid, TEbegin BeginLow::nil) :: l1) l2.
              repeat (rewrite app_ass; simpl); simpl; eauto.
              inv T1.
              exploit (trace_with_two_begins
                  ((trr1 ++ (is, TEbegin BeginLow::nil) :: l) ++
                     (tid, TEbegin BeginHigh::nil) :: l1) _ _ _ HT1 is BeginLow);
                  eauto with datatypes.
              > repeat (rewrite app_ass; simpl); simpl; eauto.
              > intros ev' l0 He'.
                apply H.
                rewrite in_app in He'.
                destruct He'; eauto with datatypes.
                simpl in H1; destruct H1; auto with datatypes; congruence.
              > intuition.
        > exploit (Ha2 is (tr1++(tid,TEbegin BeginLow::nil)::l) trr2); eauto.
          rewrite app_ass; simpl; auto.
          clear Ha2.
          intros (V1 & V2).
          assert (Hdiff:is<>tid).
            intro; subst.
            inv T1.
            exploit trace_app_inv; eauto; clear HT1 HT2.
            intros (ss & Hs1 & Hs2).
            rewrite app_comm_cons in Hs1.
            eelim trace_with_two_begins with (1:=Hs1); eauto.
            > simpl; destruct 1.
              inv H; simpl; intuition congruence.
              eapply V1; eauto with datatypes.
            > left; eauto.
            > left; eauto.
          split; auto.
          simpl; intros ev' l0 HI2; destruct HI2 as [HI2|HI2].
          > inv HI2; intuition.
          > rewrite in_app in HI2; simpl in HI2.
            destruct HI2; eauto with datatypes.
            destruct H; try congruence.
            eapply V1; eauto with datatypes.
      > simpl.
        repeat rewrite filter_fullevent_app; try congruence.
        rewrite (filter_not_tid_eq_filter_fullevent tid tr1').
        > rewrite (filter_not_tid_eq_filter_fullevent tid tr1).
          > simpl; congruence.
          > clear T1; eapply trace_with_pending_begin_no_ext; eauto.
            exploit Ha2; eauto; intuition.
        > inv T1; eapply trace_with_pending_begin_no_ext; eauto.
    > exists ((tid,TEend k::nil)::tr); split; auto.
      split.
      > repeat (econstructor; eauto; try congruence).
      > intros id tr1 tr2 He.
        destruct tr1; inv He.
        exploit Ha2; eauto; clear Ha2; intros (T1 & T2).
        assert (id<>tid).
          intro; subst; elim C; eauto with datatypes.
        split; simpl; intros; auto.
        destruct H0; auto; congruence.
  > exists ((tid,e)::tr); split; auto.
    assert (Ht: trace ge s1 ((tid, e) :: tr) s3).
      repeat (econstructor; eauto; try congruence).
    split; auto.
    intros id tr1 tr2 He.
    destruct tr1; inv He.
    > split; simpl; intuition.
      exploit @In_eq_app; eauto; intros (tr1 & tr2' & HE); subst; clear H.
      destruct k; auto.
      exploit Ha2; eauto; clear Ha2; intros (T1 & T2).
      exploit (trace_with_two_begins ((id, TEbegin BeginLow :: nil) :: tr1)); eauto.
      > simpl; eauto.
      > simpl; destruct 1; eauto.
        inv H.
        simpl; intuition congruence.
      > left; eauto.
      > left; eauto.
      > intuition.
    > exploit Ha2; eauto; clear Ha2; intros (T1 & T2).
      split; auto.
      simpl; destruct 1; eauto.
      inv H; intro; eelim E; eauto.
Qed.

Lemma low_code_in_inject_state : forall s1 tr s2,
  trace ge s1 tr s2 ->
  forall id tr1 tr2,
    tr = tr1++(id,TEbegin BeginLow::nil)::tr2 ->
    (forall ev' l, In (id,l) tr1 -> ~ In (TEend ev') l) ->
    exists s, (snd s2)!id = Some s /\ inject_state s.
Proof.
  induction 1; intros.
  > destruct tr1; inv H.
  > destruct tr1; inv H0.
    > inv HT2.
      > simpl; rewrite PTree.gss.
        econstructor; split; eauto.
        inv AS1.
        inv ST; auto; try congruence.
      > simpl; rewrite PTree.gss.
        econstructor; split; eauto.
        inv AS5; auto; try congruence.
    > edestruct IHtrace as (s & S1 & S2); eauto; clear IHtrace.
      intros; eauto with datatypes.
      inv HT2; simpl in *.
      > rewrite PTree.gsspec; destruct peq; subst.
        > econstructor; split; eauto.
          assert (s3=s) by congruence; subst.
          inv AS1.
          inv ST; simpl in *; try congruence; auto.
          eelim H1; eauto with datatypes.
          eelim H1; eauto with datatypes.
          eelim H1; eauto with datatypes.
          inv ST; simpl in S2; try congruence; auto.
        > econstructor; split; eauto.
      > econstructor; split; eauto.
      > repeat (rewrite PTree.gsspec; destruct peq); subst; try congruence.
        > assert (s3=s) by congruence; subst.
          inv AS1.
          inv ST; inv S2.
          inv INJECT.
        > econstructor; split; eauto.
      > rewrite PTree.gsspec; destruct peq; subst.
        > assert (s3=s) by congruence; subst.
          inv AS1.
          inv ST; inv S2.
          inv INJECT.
        > econstructor; split; eauto.
      > rewrite PTree.grspec; destruct peq; subst.
        > assert (s3=s) by congruence; subst.
          inv AS1.
          inv ST; inv S2.
          inv INJECT.
        > econstructor; split; eauto.
      > rewrite PTree.gsspec; destruct peq; subst.
        > econstructor; split; eauto.
          inv AS5; auto; try congruence.
        > econstructor; split; eauto.
Qed.

Lemma refines_implies_almost_backwardsim: forall s1 tr s2,
  wf_state s1 ->
  trace ge s1 tr s2 ->
  exists tr',
    almost_high_trace s1 tr' s2 /\ filter_fullevent tr' = filter_fullevent tr.
Proof.
  induction 2.
  > exists nil; repeat econstructor; eauto.
    > destruct tr1; inv H0.
    > destruct tr1; inv H0.
  > rename s2 into s3; rename s0 into s2.
    destruct IHtrace as (tr' & S1 & S2).
    edestruct almost_high_trace_and_one_step as (tr'' & T1 & T2); eauto.
    exists tr''; split; auto.
    rewrite T2; simpl.
    destruct e; congruence.
Qed.

Lemma refines_implies_backwardsim': forall st1 tr st2,
  wf_state st1 ->
  low_trace ge st1 tr st2 ->
  (forall tid s, (snd st2)!tid = Some s -> inject_state s = false) ->
  exists tr',
    high_trace ge st1 tr' st2 /\ filter_fullevent tr' = filter_fullevent tr.
Proof.
  intros st1 tr st2 WF Hl Hstuck.
  destruct Hl as (Ht & Hl).
  edestruct refines_implies_almost_backwardsim as (tr' & T1 & T2); eauto.
  exists tr'; split; auto.
  destruct T1 as (T1 & T3); split; auto.
  red; intros.
  exploit @In_eq_app; eauto.
  intros (tr1 & tr2 & L); subst; clear H.
  edestruct T3 as (T5 & T4); eauto; clear T3.
  edestruct low_code_in_inject_state as (s & S1 & S2); eauto.
  simpl in *.
  rewrite (Hstuck tid s) in S2; auto; congruence.
Qed.

End backwardsim_from_RTLinject_smallstep.





Module simulation1.
Section simulation1.
Variable ge : genv.
Variable sp: option pointer.
Variable tid: thread_id.


Fixpoint filter_mem (tr:list thread_event) : list mem_event :=
  match tr with
    | nil => nil
    | e::tr =>
      match e with
        | TEtso (TSOunbuf e) => e::(filter_mem tr)
        | TEtso (TSOmem (MEwrite true ap p _)) => (MEperm PErelease)::(MEperm (PEcheck_store ap p))::(filter_mem tr)
        | TEtso (TSOmem (MEwrite false ap p _)) => (MEperm (PEcheck_store ap p))::(filter_mem tr)
        | TEtso (TSOmem (MEread ap false p v)) => (MEread ap false p v)::(filter_mem tr)
        | TEtso (TSOmem (MEread ap true p _)) => (MEperm (PEcheck_load ap p))::(filter_mem tr)
        | TEtso (TSOmem (MErmw r p v i)) => (MErmw r p v i)::(filter_mem tr)
        | TEtso (TSOmem (MEperm pe)) => (MEperm pe)::(filter_mem tr)
        | TEato e => e::(filter_mem tr)
        | _ => filter_mem tr
      end
  end.

Inductive match_state : RTLinject.state -> Env.state -> Prop :=
| R_def1: forall ts m st stack c pc rs regs
    (R1: ts!tid = Some (RIInjectState stack c sp pc rs regs st)),
    match_state (m, ts) (m.(shared_mem),m.(buffers)tid,st).

Fixpoint proj_trace (tr:list (thread_id*list thread_event)) : list (thread_id*list mem_event) :=
  match tr with
    | nil => nil
    | (tid',e)::tr =>
      if peq tid tid'
        then proj_trace tr
        else (tid',filter_mem e):::(proj_trace tr)
  end.

Lemma proj_trace_app : forall tr1 tr2,
  proj_trace (tr1 ++ tr2) = (proj_trace tr1)++(proj_trace tr2).
Proof.
  induction tr1; simpl; auto.
  destruct a; destruct peq; auto.
  intros; rewrite IHtr1; symmetry; auto.
Qed.

Ltac clean_eq_some :=
  match goal with
    | h1: ?X = Some _, h2: ?X = Some _ |- _ => rewrite h2 in h1; inversion h1; subst; clear h1
  end.

Lemma upd_upd_s `{X: Type} `{EqDec X} {Y} (f: XY) p v' v:
  (upd (upd f p v') p v) = upd f p v.
Proof.
  unfold upd.
  apply extensionality; intros.
  eq_case; auto.
Qed.

Lemma tso_step_cast: forall t (m:tsomem) e m',
  tso_step t m e m' ->
  (forall tid', e <> INJECT.TSOstart tid') ->
  tso_step t (Env.cast t (m.(shared_mem), buffers m t)) e (Env.cast t (m'.(shared_mem), buffers m' t)).
Proof.
  intros.
  inv H; simpl; try econstructor; eauto.
  > rewrite BEMP; simpl.
    rewrite upd_s; auto.
  > rewrite <- (upd_upd_s (fun _ => nil) t (bufs t) (upd bufs t b' t)).
    econstructor; eauto.
    repeat rewrite upd_s; auto.
  > rewrite <- (upd_upd_s (fun _ => nil) t (bufs t) (upd bufs t (push_item (WBufItem p v) (bufs t)) t)).
    econstructor; eauto.
    repeat rewrite upd_s; auto.
  > rewrite <- (upd_upd_s (fun _ => nil) t (bufs t) (upd bufs t (push_item (ABufItem p i k) (bufs t)) t)).
    econstructor; eauto.
    repeat rewrite upd_s; auto.
  > rewrite <- (upd_upd_s (fun _ => nil) t (bufs t) (upd bufs t (push_item (FBufItem p k) (bufs t)) t)).
    econstructor; eauto.
    repeat rewrite upd_s; auto.
  > repeat rewrite upd_s; auto.
  > repeat rewrite upd_s; auto.
  > repeat rewrite upd_s; auto.
  > repeat rewrite upd_s; auto.
  > eelim H0; eauto.
Qed.

Lemma atrace_inthemiddle: forall t stack c sp pc regs rs l m' s'' m is2,
  atrace ge t (m, RIInjectState stack c sp pc rs regs is2) l (m', s'') ->
  exists is, s'' = (RIInjectState stack c sp pc rs regs is)
    /\ Env.atrace ge sp t (m,is2) l (m',is).
Proof.
  induction l; simpl; intros.
  inv H.
  repeat econstructor.
  inv H.
  edestruct IHl as (is & S1 & S2); eauto.
  subst.
  inv AT1.
  inv ST; try (eelim AT5; eauto; fail);
  try (subst; repeat (econstructor; eauto); fail).
  inv ST.
  econstructor; split; eauto.
  econstructor; eauto.
  econstructor; eauto.
Qed.

Lemma atrace_trace_mem b : forall t sp l m is m' is',
  Env.atrace ge sp t (m, is) l (m', is') ->
    mem_trace t (safe tid b) m (filter_mem l) m'.
Proof.
  induction l; simpl; intros m is m' is' H.
  > inv H; constructor. vauto.
  > inv H.
    exploit IHl; eauto; clear IHl; intros.
    inv AT1.
    > destruct a; simpl; auto.
      > eelim IS_not_mem; eauto.
      > inv ST.
    > econstructor; eauto.
Qed.

Lemma tso_step_unbuf_mem_step: forall t m e m',
  tso_step t m (TSOunbuf e) m' ->
  mem_step t m e m'.
Proof.
  intros.
  inv H; simpl.
  inv TM4; try econstructor; eauto.
  destruct af; econstructor; eauto.
  inv ESD; auto.
Qed.


Lemma simul: forall st1 st2 st1' e,
  astep ge st1 e st2 ->
  match_state st1 st1' ->
    (exists e', e = (tid, (TEend e')::nil))
    \/
    (match_state st2 st1' /\ fst e = tid)
    \/
    exists st2',
      match_state st2 st2' /\
      exists e', Env.step ge sp tid st1' e' st2' /\
        match e' with
          | None => fst e = tid
          | Some e' => tid<>(fst e) /\ snd e' = filter_mem (snd e) /\ fst e = fst e'
        end.
Proof.
  intros st1 st2 st1' e Hs Hm.
  inv Hs; inv Hm;
  try (destruct (peq tid tid0); [subst tid0; clean_eq_some|idtac]);
  try (left; econstructor; eauto; fail).

  inv AS1; inv ST;
  try (left; eauto; fail);
  try
    (right; right;
     repeat ( (econstructor; eauto)
              || rewrite PTree.gss; eauto)).
  eapply tso_step_cast; eauto.
  intros; inv INJECT; try congruence.

  right; right.
  inv AS1.
  > econstructor; split; [econstructor; rewrite PTree.gso; [eauto|congruence]|idtac].
    exists (Some (tid0,nil)); repeat split; simpl; auto.
    repeat (econstructor; eauto).
    destruct e0; auto.
    > eelim IS_not_mem; eauto.
    > inv ST.
      inv INJECT.
  > econstructor; split; [econstructor; rewrite PTree.gso; [eauto|congruence]|idtac].
    exists (Some (tid0,filter_mem (TEtso e'::nil))); repeat split; auto.
    clear - AS2 ES n ST.
    inv ES.
    > repeat (econstructor; eauto).
    > simpl in *; rewrite upd_o; auto.
      econstructor 1; eauto.
      inv TM4; vauto.
      econstructor; vauto.
      inv ESD; vauto.
    > simpl in *; rewrite upd_o; auto.
      destruct m0.
      destruct r; subst.
      econstructor; trivial. econstructor; eauto. econstructor; vauto.
      econstructor; eauto. econstructor; eauto. vauto. vauto.
    > simpl in *; rewrite upd_o; auto.
      econstructor 1; eauto; econstructor 1; eauto.
    > simpl in *; rewrite upd_o; auto.
      econstructor 1; eauto; econstructor 1; eauto.
    > econstructor 1; eauto; simpl.
      case_eq (addr_in_buf p (bufs tid0)); intro; autorw'; vauto.
      econstructor; eauto. vauto. econstructor.
      destruct ap; econstructor. intuition. vauto.
      econstructor. destruct (d p); auto. symmetry. intuition.
    > econstructor 1; eauto; simpl in *. vauto.
    > econstructor 1; eauto; simpl in *. vauto.
    > inv ST.
      inv INJECT.
    > intuition.
    > econstructor 1; eauto; simpl in *.
      econstructor; eauto.
  > right; right.
    econstructor; split; [econstructor; eauto|idtac].
    simpl.
    destruct (peq tid tid0); subst.
    > exists None; split; auto.
      econstructor 2; eauto.
      econstructor 3; eauto.
      eapply tso_step_cast; eauto.
      congruence.
      congruence.
      congruence.
    > exists (Some (tid0,bi::nil)); split; auto.
      exploit tso_step_unbuf_mem_step; eauto; intros.
      inv AS; simpl.
      rewrite upd_o; auto.
      econstructor 1; eauto.
      econstructor 2; eauto.
      econstructor 1; eauto.
      intuition.
  > inv AS6.
    inv AS1.
    inv ST.
    inv INJECT.

  > right; right.
    econstructor; split.
    econstructor.
    rewrite PTree.gso; try congruence.
    rewrite PTree.gso; try congruence; eauto.
    exists (Some (tid0,nil)); repeat split; simpl; auto.
    inv AS6.
    inv AS1.
    simpl in *; repeat rewrite upd_o; try congruence. vauto.
  > inv AS1.
    inv ST.
    inv INJECT.

  > right; right.
    econstructor; split.
    econstructor.
    rewrite PTree.gso; try congruence; eauto.
    exists (Some (tid0,nil)); repeat split; simpl; auto.
    inv AS1. vauto.

  > inv AS1.
    inv ST.
    inv INJECT.

  > right; right.
    econstructor; split.
    econstructor.
    rewrite PTree.gro; try congruence; eauto.
    exists (Some (tid0,nil)); repeat split; simpl; auto.
    inv AS1. vauto.

  > inv AS1.
    exploit atrace_inthemiddle; eauto.
    intros (is & S1 & S2); subst.
    right; right.
    inv AS5.
    econstructor; split.
    econstructor; eauto.
    rewrite PTree.gss; eauto.
    exists None; split; auto.
    simpl.
    econstructor 3; eauto.
    constructor 2; eauto.
    rewrite AS6.
    econstructor; eauto.
    constructor 2; eauto.
    rewrite AS6.
    econstructor; eauto.

  > inv AS1.
    exploit atrace_inthemiddle; eauto.
    intros (is'' & S1 & S2); subst.
    inv AS5.
    right; right.
    econstructor; split.
    econstructor.
    rewrite PTree.gso; try congruence; eauto.
    exists (Some (tid0, filter_mem l)); split; auto.
    simpl.
    econstructor 1; eauto.
    eapply atrace_trace_mem; eauto.
Qed.

Lemma trace_simul: forall st0 tr st1,
  trace ge st0 tr st1 ->
  (forall ev', ~ In (tid,(TEend ev')::nil) tr) -> forall st0',
  match_state st0 st0' ->
  exists st1',
    Env.trace ge sp tid st0' (proj_trace tr) st1' /\
    match_state st1 st1'.
Proof.
  intros st0 tr st1.
  induction 1; intros.
  exists st0'; repeat econstructor; eauto.
  destruct IHtrace with st0' as (st1' & S1 & S2); auto; clear IHtrace.
  intuition eauto with datatypes.
  edestruct simul as [(e' & H')|[(H' & T)|(st2' & T1 & e' & T2 & T3)]]. 2: eassumption.
  eassumption.
  > eelim H0; subst; simpl; auto.
  > exists st1'; split; auto.
    destruct e; simpl.
    destruct peq.
    > subst; auto.
    > simpl in T; elim n; auto.
  > exists st2'; split; auto.
    destruct e; simpl.
    destruct peq.
    > subst; auto.
      destruct e'.
      > elim T3; simpl; intuition.
      > clear T3; subst p.
        econstructor 3; eauto.
    > destruct e'.
      > destruct T3 as (T3 & T4 & T5); simpl in *; intros; subst.
        destruct p0; simpl in *.
        rewrite <- T4.
        econstructor 2; eauto.
      > elim n; simpl in T3; intuition.
Qed.

Inductive match_state2 : RTLinject.state -> Env.state -> RTLinject.state -> list (thread_id*ext_event) -> Env.state -> Prop :=
| R2_def: forall ts1 ts2 st2 st tr m1 m2 st1 regs rs pc c stack b1 b2
    (R2: ts2!tid = Some (RIInjectState stack c sp pc rs regs st2))
    (R3: forall tid', tid <> tid' -> ts1!tid'=ts2!tid')
    (R4: ts1!tid = Some (RIInjectState stack c sp pc rs regs st1))
    (R6: Env.trace ge sp tid (m2,b2 tid,st2) tr st)
    (R7: forall tid', tid <> tid' -> b1 tid' = b2 tid'),
    match_state2 (TSOMEM m1 b1, ts1) (m2,b2 tid,st2) (TSOMEM m2 b2, ts2) tr st.

Lemma rev_cons' : forall B A (x:B*list A) l,
  rev (x:::l) = (rev l)++x:::nil.
Proof.
  unfold cons'.
  destruct x; simpl.
  destruct l; simpl; auto with datatypes.
Qed.

Lemma proj_trace_rev: forall tr,
  proj_trace (rev tr) = rev (proj_trace tr).
Proof.
  induction tr; simpl; auto.
  destruct a; destruct peq; auto.
  rewrite proj_trace_app; simpl.
  subst; rewrite peq_true.
  rewrite app_nil_r; auto.
  rewrite proj_trace_app; simpl.
  subst; rewrite peq_false; auto.
  rewrite IHtr; auto.
  rewrite (rev_cons' _ _ (p,filter_mem l)); auto.
Qed.

Lemma proj_trace_app_cons : forall tr ev,
  (proj_trace tr ++ ev:::nil) = (rev (ev:::(proj_trace (rev tr)))).
Proof.
  intros; simpl.
  destruct ev; destruct l; unfold cons'; simpl; auto.
  rewrite app_nil_r.
  rewrite proj_trace_rev; rewrite rev_involutive; auto.
  rewrite proj_trace_rev; rewrite rev_involutive; auto.
Qed.

Lemma exists_atrace: forall t stack c sp pc rs regs,
  forall l S S' m m' st st',
    S = RIInjectState stack c sp pc rs regs st ->
    S' = RIInjectState stack c sp pc rs regs st' ->
    Env.atrace ge sp t (m, st) l (m', st') ->
    atrace ge t (m,S) l (m',S').
Proof.
  induction l; intros.
  inv H1.
  constructor 1.
  inv H1; econstructor; eauto.
  inv AT1; econstructor; eauto.
  econstructor; eauto.
  econstructor; eauto.
  congruence.
Qed.

Lemma exists_astep: forall stack c sp pc rs st4 m st f m4 ts ts' regs,
  ts!tid = Some (RIInjectState stack c sp pc rs regs st) ->
  ts' = ts!tid <- (RIInjectState stack c sp pc rs regs st4) ->
  forall st2 l st3 b,
    b tid = nil ->
    Env.atrace ge sp tid (m,st2) l (m4,st3) ->
    Env.intra_step ge sp tid (m, nil, st) (TEtso TSObeginatomic) (m,nil,st2) ->
    Env.intra_step ge sp tid (m4,nil,st3) (TEtso (TSOendatomic f)) (m4, nil, st4) ->
    astep ge (TSOMEM m b,ts) (tid,l) (TSOMEM m4 b,ts').
Proof.
  intros.
  econstructor; eauto.
  inv H3; econstructor; eauto; try congruence.
  eapply exists_atrace; eauto.
  inv H4; econstructor; eauto; congruence.
Qed.

Lemma Env_atrace_no_end: forall ge sp t st1 tr st2,
  Env.atrace ge sp t st1 tr st2 ->
  forall ev, ~ In (TEend ev) tr.
Proof.
  induction 1.
  simpl; auto.
  red; simpl; intros.
  destruct H0.
  subst; eelim AT5; eauto.
  eelim IHatrace; eauto.
Qed.

Lemma upd_comm {X: Type} `{EqDec X} {Y: Type} {t t'} {f: XY} {x x'} :
  t' ≠ t
  upd (upd f t x) t' x' = upd (upd f t' x') t x.
Proof.
  intros T. apply extensionality. intros y.
  unfold upd. repeat eq_case; repeat intros ->; congruence.
Qed.

Lemma tso_step_o : forall bufs m tid tid' b ev m' bufs',
  tid <> tid' ->
  evTSOstart tid
  tso_step tid' (TSOMEM m bufs) ev (TSOMEM m' bufs') ->
  tso_step tid' (TSOMEM m (upd bufs tid b)) ev (TSOMEM m' (upd bufs' tid b)).
Proof.
  intros bufs m tid0 tid' b ev m' bufs' H L K; inv K; vauto;
  (try (rewrite upd_comm;[|easy]; econstructor;eauto)).
  econstructor; eauto. simpl in *. now rewrite upd_o.
  rewrite upd_o; eauto.
  rewrite upd_o; eauto.
  rewrite upd_o; eauto.
  rewrite upd_o; eauto.
  econstructor; eauto. rewrite upd_o; eauto. rewrite upd_o; eauto. rewrite upd_o; eauto.
  econstructor; eauto. rewrite upd_o; eauto.
  rewrite upd_comm.
  vauto.
  congruence.
Qed.

Lemma tso_step_same_buf : forall bufs m tid tid' ev m' bufs',
  tid <> tid' ->
  (forall newtid, ev <> (TSOstart newtid)) ->
  tso_step tid' (TSOMEM m bufs) ev (TSOMEM m' bufs') ->
  bufs tid = bufs' tid.
Proof.
  intros.
  inv H1; auto;
  rewrite upd_o; auto.
  eelim H0; eauto.
Qed.

Lemma upd_upd {X Y} `{EqDec X} {f: XY} {x} :
  upd f x (f x) = f.
Proof.
  apply extensionality. intros y. unfold upd. eq_case; congruence.
Qed.

Lemma upd_inv {X Y} `{EqDec X} {f: XY} {x y y'} :
  upd f x y = upd f x y' → y = y'.
Proof.
  Hint Resolve @upd_s.
  intros K. replace y with (upd f x y x); eauto. rewrite K; eauto.
Qed.

Lemma tso_step_cast2: forall t m e m' b b' bufs,
  tso_step t (Env.cast t (m, b)) e (Env.cast t (m', b')) ->
  bufs t = b ->
  (forall newtid, e <> (TSOstart newtid)) ->
  tso_step t (TSOMEM m bufs) e (TSOMEM m' (upd bufs t b')).
Proof.
  Ltac t := repeat match goal with
              | [H: appcontext[ upd _ ?x _ ?x ] |- _ ] =>
                rewrite upd_s in H
              | [ |- appcontext[ upd _ ?x _ ?x ] ] =>
                rewrite upd_s
              | [H: appcontext[ upd (upd _ ?x _) ?x _ ] |- _ ] =>
                rewrite upd_upd_s in H
              | [H : upd _ _ ?x = upd _ _ ?y |- _ ] =>
                assert (x = y) by exact (upd_inv H);
                  clear H;
                  subst
              | |- appcontext[ upd ?f ?x (?f ?x) ] =>
                  rewrite upd_upd
            end.
  intros t m e m' b b' bufs H K L. inv H; simpl in *; t; vauto.
  congruence.
Qed.

Lemma ptree_set_same: forall A (m:PTree.t A) x v,
  m!x = Some v ->
  m ! x <- v = m.
Proof.
  intros; apply PTree.ext; intros.
  rewrite PTree.gsspec; destruct peq; congruence.
Qed.

Lemma env_step_none: forall ts tid stack c sp pc rs regs s1 s2 m1 b1 m2 b2 b,
  ts ! tid = Some (RIInjectState stack c sp pc rs regs s1) ->
  b1 = b tid ->
  Env.step ge sp tid (m1,b1,s1) None (m2,b2,s2) ->
  exists l,
    astep ge (TSOMEM m1 b,ts) (tid,l)
      (TSOMEM m2 (upd b tid b2),ts!tid <- (RIInjectState stack c sp pc rs regs s2)) /\
    (forall ev, ~ In (TEend ev) l).
Proof.
  intros; subst.
  inv H1.
  > inv ST.
    > econstructor; split.
      econstructor 1; eauto; try congruence.
      assert (Hu1:upd b tid0 (b tid0) = b).
        apply extensionality; unfold upd.
        intros; destruct peq; congruence.
      rewrite Hu1.
      econstructor; eauto.
      econstructor; eauto.
      red; intros; inv ST0; congruence.
      red; intros; inv ST0; congruence.
      simpl; intuition congruence.
    > econstructor; split.
      econstructor 1; eauto.
      econstructor 2; eauto.
      econstructor; eauto.
      eapply tso_step_cast2; eauto.
      red; intros; inv ST0; congruence.
      red; intros; inv ST0; congruence.
      red; intros; inv ST0; congruence.
      simpl; intuition congruence.
    > rewrite ptree_set_same; auto.
      econstructor; split.
      econstructor 2; eauto.
      inv ES.
      rewrite upd_s in TM3.
      econstructor 2; eauto.
      generalize (upd_s (fun _ : positive => nil) tid0 b2).
      rewrite <- H5.
      rewrite upd_s.
      congruence.
      simpl; intuition congruence.
    > inv ST1.
      eelim IS_not_mem; eauto.
      assert (b2=nil).
        inv ST2; try congruence.
        inv ES0; try congruence.
        generalize (upd_s (fun _ : positive => nil) tid0 b2).
        rewrite <- H5.
        rewrite upd_s.
        congruence.
      subst.
      assert ((b tid0) = nil).
        inv ES.
        generalize (upd_s (fun _ : positive => nil) tid0 (b tid0)).
        rewrite H4.
        rewrite upd_s.
        congruence.
      replace (upd b tid0 nil) with b.
      econstructor; split.
      econstructor 6; eauto.
      econstructor; eauto; try congruence.
      assert (m2=m3).
        inv ST2; auto.
        inv ES0; auto.
      subst.
      inv ES.
      eapply exists_atrace; eauto.
      econstructor; eauto.
      inv ST2; try econstructor; eauto.
      congruence.
      intros; eapply Env_atrace_no_end; eauto.
      apply extensionality; unfold upd.
      intros; destruct peq; congruence.
Qed.

Lemma proj_trace_false: forall tid0 e tr,
  tid <> tid0 ->
  proj_trace ((tid0,e)::tr) = (tid0,filter_mem e):::proj_trace tr.
Proof.
  simpl; intros.
  rewrite peq_false; auto.
Qed.


Lemma atrace_filter_mem: forall tid' st e st',
  atrace ge tid' st e st' ->
  filter_mem e = nil -> forall m0,
  atrace ge tid' (m0, snd st) e (m0, snd st').
Proof.
  induction 1; simpl; intros; econstructor; eauto.
  inv AT1; try (econstructor; eauto; fail).
  congruence.
  destruct e; auto; try congruence.
  destruct ev; auto; try congruence.
  destruct ev; auto; try congruence;
  destruct r; auto; try congruence.
Qed.



Lemma Trace_inv_eq: forall ge sp t s1 tr s2,
  Env.trace_inv ge sp t s1 (rev tr) s2 <-> Env.trace ge sp t s1 tr s2.
Proof.
  intros.
  rewrite Env.trace_inv_eq; auto.
  rewrite (rev_involutive tr); intuition.
Qed.

Lemma proj_trace_app_cons' : forall tr ev,
  (proj_trace (tr ++ ev:::nil)) = (rev (proj_trace (ev:::nil) ++ (proj_trace (rev tr)))).
Proof.
  intros; simpl.
  rewrite proj_trace_app.
  rewrite rev_app.
  rewrite proj_trace_rev; rewrite rev_involutive; auto.
  f_equal.
  assert (forall A (a:positive*list A), a:::nil = rev (a:::nil)).
    destruct a; unfold cons'; simpl.
    destruct l; auto.
  destruct ev.
  destruct l; unfold cons'; simpl; auto.
  destruct peq; auto.
Qed.

Lemma buf_step_mem_step: forall t m bi e m',
  buf_step t m bi e m' -> mem_step t m e m'.
Proof.
  intros.
  inv H.
  destruct af; econstructor; auto.
  inv ESD; auto.
  econstructor; eauto.
  econstructor; eauto.
Qed.

Lemma simul3': forall tid' S2 TR st,
  tid' <> tid ->
  Env.trace_inv ge sp tid S2 TR st ->
  forall tr e m2 b1 m1 ts1 b2 st2 st3 regs rs pc c stack ts2,
  S2 = (m2, b2 tid, st2) ->
  TR = ((tid', e) :: proj_trace tr) ->
  ts2 ! tid = Some (RIInjectState stack c sp pc rs regs st2) ->
  (∀tid' : positive, tidtid' → ts1 ! tid' = ts2 ! tid') ->
  (ts1 ! tid = Some (RIInjectState stack c sp pc rs regs st3)) ->
  (∀tid' : positive, tidtid' → b1 tid' = b2 tid') ->
  exists stt1', exists st1', exists stt1'',
    match_state2 (TSOMEM m1 b1,ts1) stt1'' st1' (proj_trace (rev tr)) st /\
    Env.trace ge sp tid (m2,b2 tid,st2) nil stt1' /\
    Env.step ge sp tid stt1' (Some (tid', e)) stt1''.
Proof.
  induction 2; intros; subst.
  > inv H1.
  > destruct e as (tid'',e).
    destruct e.
    > inv HT2.
      inv ES.
      exploit IHtrace_inv; eauto.
    > clear IHtrace_inv.
      inv H2.
      inv HT2.
      exists (m2, b2 tid, st2); exists (TSOMEM m' b2, ts2); exists (m', b2 tid, st2); repeat split; auto.
      econstructor; eauto.
      rewrite <- Trace_inv_eq.
      rewrite <- proj_trace_rev.
      rewrite rev_involutive; auto.
      econstructor 1.
      econstructor; eauto.
    > assert (Hs: exists m', exists b, exists st', s2 = (m', (upd b2 tid b) tid, st')).
        destruct s2.
        destruct p.
        econstructor; econstructor; econstructor; rewrite upd_s; eauto.
      destruct Hs as (m' & b & st' & Hs).
      subst; eelim IHtrace_inv with
        (ts1:=ts1)
        (ts2:=ts2!tid<-(RIInjectState stack c sp pc rs regs st')) (m1:=m1)
        (m2:=m') ; eauto.
      > intros stt1 (st1' & stt1'' & S1 & S2 & S3).
        exists stt1; exists st1'; exists stt1''; repeat split; auto.
        > inv S1; econstructor; eauto.
          intros.
          rewrite <- R7; auto.
          rewrite upd_o; auto.
        > rewrite <- Trace_inv_eq; simpl.
          econstructor 3; eauto.
          rewrite Env.trace_inv_eq; auto.
      > rewrite PTree.gss; eauto.
      > intros.
        rewrite PTree.gso; eauto.
Qed.


Lemma simul3: forall st0 tid' e stt1 st1 tr st,
  tid' <> tid ->
  match_state2 st0 stt1 st1 (proj_trace tr++(tid',e)::nil) st ->
  exists stt1', exists st1', exists stt1'',
    match_state2 st0 stt1'' st1' (proj_trace tr) st /\
    Env.trace ge sp tid stt1 nil stt1' /\
    Env.step ge sp tid stt1' (Some (tid', e)) stt1''.
Proof.
  intros st1 tid' e stt1' stt1 tr st H H0.
  inv H0.
  rewrite <- Trace_inv_eq in R6.
  rewrite rev_app in R6.
  simpl in R6.
  rewrite <- proj_trace_rev in R6.
  eelim simul3' with (m1:=m1); eauto.
  intros stt1 (st1' & stt1'' & S1 & S2 & S3).
  exists stt1; exists st1'; exists stt1''; split; eauto.
  rewrite rev_involutive in S1; auto.
Qed.

Lemma atrace_filter_mem_nil: forall e,
  filter_mem e = nil ->
  forall tid' m s m' s', atrace ge tid' (m, s) e (m', s') ->
    forall m0, atrace ge tid' (m0, s) e (m0, s').
Proof.
  induction e; simpl; intros.
  > inv H0; econstructor 1.
  > inv H0.
    inv AT1.
    econstructor; [idtac|eapply IHe; eauto|auto].
    econstructor 1; eauto.
    destruct a; try congruence.
    destruct ev; try congruence.
    destruct ev; try congruence.
    destruct r; try congruence.
    destruct r; try congruence.
    congruence.
Qed.


Lemma env_trace_nil: forall S1 tr S2,
  Env.trace_inv ge sp tid S1 tr S2 ->
  forall ts stack c pc rs regs s1 s2 m1 b1 m2 b2 b,
    tr = nil ->
    S1 = (m1,b1,s1) ->
    S2 = (m2,b2,s2) ->
    ts ! tid = Some (RIInjectState stack c sp pc rs regs s1) ->
    b1 = b tid ->
    exists tr,
      trace_inv ge (TSOMEM m1 b,ts) tr
      (TSOMEM m2 (upd b tid b2),ts!tid <- (RIInjectState stack c sp pc rs regs s2)) /\
      proj_trace tr = nil /\
      filter_not_tid tid tr = nil /\
      ∀ev : end_event, ∀l : list thread_event, In (tid, l) tr → ¬In (TEend ev) l.
Proof.
  induction 1; intros; subst.
  > exists nil; inv H0; split; auto.
    replace (ts ! tid <- (RIInjectState stack c sp pc rs regs s1)) with ts.
    replace (upd b tid (b tid)) with b.
    econstructor 1.
    unfold upd; apply extensionality; intros; destruct peq; congruence.
    apply PTree.ext; intros; rewrite PTree.gsspec; destruct peq; congruence.
  > destruct e.
    destruct e; inv H0.
    inv HT2.
    inv ES.
    eapply IHtrace_inv; eauto.
  > destruct s2 as ((mm1 & b1) & s1).
    assert (Hb1: b1 = upd b tid b1 tid).
      rewrite upd_s; auto.
    rewrite Hb1 in HT2, H.
    eelim IHtrace_inv with (m3:=m2) (m1:=mm1)
    (ts:=ts!tid<-(RIInjectState stack c sp pc rs regs s1)); eauto.
    2: eapply PTree.gss; eauto.
    clear Hb1.
    intros tr (T1 & T2 & T3 & T4); clear IHtrace_inv.
    rewrite upd_s in HT2.
    eelim env_step_none with (3:=HT2); eauto.
    intros l (Hl1 & Hl2).
    econstructor; split.
    econstructor 2; eauto.
    replace (upd b tid b2) with (upd (upd b tid b1) tid b2).
    replace ((ts ! tid <- (RIInjectState stack c sp pc rs regs s1)) ! tid <-
         (RIInjectState stack c sp pc rs regs s4)) with
    (ts ! tid <- (RIInjectState stack c sp pc rs regs s4)) in T1.
    eapply T1.
    apply PTree.ext; intros; repeat rewrite PTree.gsspec; destruct peq; auto.
    unfold upd; apply extensionality; intros; destruct peq; auto.
    repeat split.
    > rewrite proj_trace_app; rewrite T2; simpl.
      rewrite peq_true; auto.
    > rewrite filter_not_tid_app_cons_eq; auto.
    > intros.
      rewrite in_app in H0.
      destruct H0; eauto.
      simpl in H0; destruct H0.
      inv H0; eauto.
      intuition.
Qed.

Lemma atrace_mem_trace_atrace: forall P tid' e m1 m1' s s' m2 m2',
  atrace ge tid' (m1, s) e (m1', s') ->
  mem_trace tid' P m2 (filter_mem e) m2' ->
  atrace ge tid' (m2, s) e (m2', s').
Proof.
  induction e; intros.
  > inv H; inv H0; econstructor; eauto.
  > inv H.
    inv AT1; simpl in *.
    > destruct a;
      try (econstructor 2; eauto; econstructor 1; eauto).
      > eelim IS_not_mem; eauto.
      > inv H0.
        econstructor 2; eauto.
        inv ST; inv INJECT.
    > inv H0; econstructor 2; eauto.
      econstructor 2; eauto.
Qed.

Lemma simul2: forall st1 tid' e st2 stt1' stt1 tr st,
  (snd st1)!tid<>None ->
  astep ge st1 (tid',e) st2 ->
  tid' <> tid ->
  match_state2 st1 stt1' stt1 (proj_trace (tr++(tid',e)::nil)) st ->
    exists stt2, exists stt2', exists tr',
      match_state2 st2 stt2' stt2 (proj_trace tr) st /\
      trace ge stt1 ((tid',e)::tr') stt2 /\
      proj_trace tr' = nil /\
      filter_not_tid tid tr' = nil /\
      (forall ev l, In (tid,l) tr' -> ~ In (TEend ev) l).
Proof.
  intros st1 tid' e st2 stt1' stt1 tr st Hs H H0 H1.
  rewrite proj_trace_app in H1.
  simpl in H1.
  rewrite peq_false in H1; auto.
  destruct (classic (filter_mem e = nil)) as [E|E].
  > rewrite E in H1.
    unfold cons' in *; simpl in H1.
    rewrite app_nil_r in H1.
    inv H1; inv H.
    > inv AS1.
      > exists (TSOMEM m2 b2, ts2!tid' <- s'); econstructor; exists nil; intuition.
        > econstructor; eauto.
          rewrite PTree.gso; eauto.
          intros; rewrite PTree.gsspec; destruct peq; eauto.
          subst; rewrite PTree.gss; eauto.
          rewrite PTree.gso; eauto.
          rewrite PTree.gso; eauto.
        > econstructor 2; [econstructor 1; eauto|idtac].
          econstructor 1; eauto.
          rewrite <- R3; eauto.
          econstructor 1; eauto.
      > simpl in E.
        destruct e'; try (inv E; fail).
        > destruct ev; try (inv E; fail).
          > destruct r; inv E.
          > destruct r; inv E.
          > destruct m'.
            exists (TSOMEM m2 (upd b2 tid' (push_item (ABufItem p i m) (b2 tid'))), ts2!tid' <- s');
              econstructor; exists nil; intuition.
            > econstructor; eauto.
              rewrite PTree.gso; eauto.
              intros; rewrite PTree.gsspec; destruct peq; eauto.
              subst; rewrite PTree.gss; eauto.
              rewrite PTree.gso; eauto.
              rewrite PTree.gso; eauto.
              rewrite upd_o; auto.
              inv ES; intros.
              unfold upd; destruct peq; auto.
              rewrite R7; auto.
            > econstructor 2; [econstructor 1; eauto|idtac].
              econstructor 1; eauto.
              rewrite <- R3; eauto.
              econstructor 2; eauto.
              econstructor; eauto.
          > destruct m'.
            exists (TSOMEM m2 (upd b2 tid' (push_item (FBufItem p m) (b2 tid'))), ts2!tid' <- s');
              econstructor; exists nil; intuition.
            > econstructor; eauto.
              rewrite PTree.gso; eauto.
              intros; rewrite PTree.gsspec; destruct peq; eauto.
              subst; rewrite PTree.gss; eauto.
              rewrite PTree.gso; eauto.
              rewrite PTree.gso; eauto.
              rewrite upd_o; auto.
              inv ES; intros.
              unfold upd; destruct peq; auto.
              rewrite R7; auto.
            > econstructor 2; [econstructor 1; eauto|idtac].
              econstructor 1; eauto.
              rewrite <- R3; eauto.
              econstructor 2; eauto.
              econstructor; eauto.
        > destruct m'; exists (TSOMEM m2 b2, ts2!tid' <- s'); econstructor; exists nil; intuition.
          > econstructor; eauto.
            rewrite PTree.gso; eauto.
            intros; rewrite PTree.gsspec; destruct peq; eauto.
            subst; rewrite PTree.gss; eauto.
            rewrite PTree.gso; eauto.
            rewrite PTree.gso; eauto.
            inv ES; auto.
          > econstructor 2; [econstructor 1; eauto|idtac].
            econstructor 1; eauto.
            rewrite <- R3; eauto.
            econstructor 2; eauto.
            econstructor; eauto.
            inv ES; simpl in *.
            rewrite <- R7; auto.
        > intuition.
        > destruct m'; exists (TSOMEM m2 b2, ts2!tid' <- s'); econstructor; exists nil; intuition.
          > econstructor; eauto.
            rewrite PTree.gso; eauto.
            intros; rewrite PTree.gsspec; destruct peq; eauto.
            subst; rewrite PTree.gss; eauto.
            rewrite PTree.gso; eauto.
            rewrite PTree.gso; eauto.
            inv ES; auto.
          > econstructor 2; [econstructor 1; eauto|idtac].
            econstructor 1; eauto.
            rewrite <- R3; eauto.
            econstructor 2; eauto.
            econstructor; eauto.
        > inv ST; inv INJECT.
      > inv E.
      > inv AS6; inv AS1.
        exists (TSOMEM m2 (upd b2 tid'0 nil), (ts2!tid' <- s')!tid'0<-init); econstructor; exists nil; intuition.
        > econstructor; eauto.
          rewrite PTree.gso; eauto.
          rewrite PTree.gso; eauto.
          intro; subst; congruence.
          intros; repeat rewrite PTree.gsspec; destruct peq; eauto.
          destruct peq; auto.
          rewrite PTree.gso; eauto.
          rewrite PTree.gso; eauto.
          intro; subst; congruence.
          rewrite upd_o; auto.
          intro; subst; congruence.
          unfold upd; intros; destruct peq; auto.
        > econstructor 2; [econstructor 1; eauto|idtac].
          econstructor 3; eauto.
          rewrite <- R3; eauto.
          econstructor; eauto.
          rewrite <- R3; auto.
          intro; subst; congruence.
          econstructor; eauto.
      > destruct m'; exists (TSOMEM m2 b2, ts2!tid' <- s'); econstructor; exists nil; intuition.
        > econstructor; eauto.
          rewrite PTree.gso; eauto.
          intros; repeat rewrite PTree.gsspec; destruct peq; eauto.
          rewrite PTree.gso; eauto.
          inv AS1; auto.
        > econstructor 2; [econstructor 1; eauto|idtac].
          econstructor 4; eauto.
          rewrite <- R3; eauto.
          econstructor; eauto; try congruence.
          inv AS1; auto.
      > destruct m'; exists (TSOMEM m2 b2, PTree.remove tid' ts2); econstructor; exists nil; intuition.
        > econstructor; eauto.
          rewrite PTree.gro; eauto.
          intros; repeat rewrite PTree.grspec; destruct peq; eauto.
          rewrite PTree.gro; eauto.
          inv AS1; auto.
        > econstructor 2; [econstructor 1; eauto|idtac].
          econstructor 5; eauto.
          rewrite <- R3; eauto.
          inv AS1; econstructor; eauto; try congruence.
      > destruct m'; exists (TSOMEM m2 b2, ts2!tid' <- s'''); econstructor; exists nil; intuition.
        > econstructor; eauto.
          rewrite PTree.gso; eauto.
          intros; repeat rewrite PTree.gsspec; destruct peq; eauto.
          rewrite PTree.gso; eauto.
        > econstructor 2; [econstructor 1; eauto|idtac].
          econstructor 6; eauto.
          rewrite <- R3; eauto.
          rewrite <- R7; auto.
          eapply atrace_filter_mem_nil; eauto.
  > assert (Hf: (tid', filter_mem e) ::: nil = (tid', filter_mem e) :: nil).
      destruct (filter_mem e); try congruence.
      reflexivity.
    rewrite Hf in *; clear Hf.
    exploit simul3; eauto.
    intros (sstt1' & sst1' & sstt1'' & M1 & M2 & M3).
    inv H1.
    destruct sstt1' as ((m4,b4),s4).
    rewrite <- Trace_inv_eq in M2.
    simpl in M2.
    exploit env_trace_nil; eauto.
    intros (tr0 & T1 & T2 & T3 & T4).
    destruct sstt1'' as ((m5,b5),s5).
    destruct st2 as ((m7,b7),ts7).
    exists (TSOMEM m5 (upd b7 tid b5), ts7!tid <- (RIInjectState stack c sp pc rs regs s5)).
    exists ((m5,b5),s5).
    exists tr0; repeat split; auto.
    > pattern b5 at 1; replace b5 with (upd b7 tid b5 tid).
      assert (Hs7: exists s7, ts7 ! tid = Some (RIInjectState stack c sp pc rs regs s7)).
        inv H; try rewrite PTree.gso; eauto.
        rewrite PTree.gso; eauto.
        rewrite PTree.gro; eauto.
      destruct Hs7 as (s7, Hs7).
      econstructor; eauto.
      rewrite PTree.gss; eauto.
      intros; rewrite PTree.gso; auto.
      rewrite upd_s; auto.
      inv M1; auto.
      intros; rewrite upd_o; auto.
      rewrite upd_s; auto.
    > econstructor; eauto.
      > rewrite trace_inv_eq.
        eauto.
      > clear T3 T2 T1 tr0 T4 M1 Hs M2 R6.
        assert (s4=s5).
          inv H; inv M3; auto.
        subst.
        inv H; try (elim E; reflexivity).
        > inv AS1.
          > destruct e0; try (elim E; reflexivity).
            eelim IS_not_mem; eauto.
            inv ST.
            inv INJECT.
            inv ST; simpl in M3; try (elim E; reflexivity).
            destruct e'; try (elim E; reflexivity).
            destruct ev; try (elim E; reflexivity).
            > destruct r.
              > econstructor; eauto.
                rewrite PTree.gso; eauto.
                rewrite <- R3; eauto.
                apply PTree.ext; intros.
                repeat rewrite PTree.gsspec; destruct peq; destruct peq;
                  try (elim H0; congruence; fail); eauto.
                econstructor; eauto.
                econstructor; eauto.
                inv ES.
                inv M3.
                replace (upd (upd b1 tid' (push_item (WBufItem p v) (b1 tid'))) tid b5)
                  with (upd (upd b2 tid b5) tid' (push_item (WBufItem p v) ((upd b2 tid b5) tid'))).
                inv ES. inv TM1. inv TM5.
                inv TM6. inv ESD.
                econstructor; eauto.

                apply extensionality; unfold upd; intros; repeat destruct peq; auto; try congruence.
                rewrite R7; auto.
                rewrite R7; auto.
              > econstructor; eauto.
                rewrite PTree.gso; eauto.
                rewrite <- R3; eauto.
                apply PTree.ext; intros.
                repeat rewrite PTree.gsspec; destruct peq; destruct peq;
                  try (elim H0; congruence; fail); eauto.
                econstructor; eauto.
                econstructor; eauto.
                inv ES.
                inv M3.
                replace (upd (upd b1 tid' (push_item (WBufItem p v) (b1 tid'))) tid b5)
                  with (upd (upd b2 tid b5) tid' (push_item (WBufItem p v) ((upd b2 tid b5) tid'))).
                assert (m4=m5 /\ check_perm_store tid' m4 a p).
                  inv ES.
                  inv TM1; inv TM2; auto.
                  inv ESD; auto.
                destruct H; subst; econstructor; eauto.
                apply extensionality; unfold upd; intros; repeat destruct peq; auto; try congruence.
                rewrite R7; auto.
                rewrite R7; auto.
            > destruct r.
              econstructor; eauto.
              rewrite PTree.gso; eauto. rewrite <- R3; eauto.
              apply PTree.ext; intros.
              repeat rewrite PTree.gsspec; destruct peq; destruct peq;
                try (elim H0; congruence; fail); eauto.
              replace (upd b7 tid b5) with (upd b2 tid b5).
              econstructor; eauto. vauto.
              inv ES. inv M3. inv ES. inv TM1. inv TM0.
              inv ESD. inv ESD0; econstructor.
                rewrite upd_o; eauto. intuition.
                rewrite <- R7; auto.
                rewrite <- R7; auto.
                rewrite <- R7; auto.
              rewrite upd_o; eauto. intuition.
              rewrite <- R7; auto.
              autorw'.
              rewrite <- R7; auto.
              rewrite <- R7; auto.
              apply extensionality; unfold upd; intros; repeat destruct peq; auto; try congruence.
              inv ES.
              rewrite R7; auto.
              econstructor; eauto.
              rewrite PTree.gso; eauto.
              rewrite <- R3; eauto.
              apply PTree.ext; intros.
              repeat rewrite PTree.gsspec; destruct peq; destruct peq;
                try (elim H0; congruence; fail); eauto.
              replace (upd b7 tid b5) with (upd b2 tid b5); eauto.
              econstructor; eauto.
              econstructor; eauto.
              inv ES.
              inv M3.
              inv ES.
              inv TM1.
              inv TM0; econstructor.
              rewrite upd_o. symmetry. apply R7. auto. auto.
              vauto. auto. auto.
              rewrite upd_o. symmetry. apply R7. auto. auto.
              econstructor; auto. auto. auto.
              apply extensionality; unfold upd; intros; repeat destruct peq; auto; try congruence.
              inv ES.
              rewrite R7; auto.
            > econstructor; eauto.
              rewrite PTree.gso; eauto.
              rewrite <- R3; eauto.
              apply PTree.ext; intros.
              repeat rewrite PTree.gsspec; destruct peq; destruct peq;
                try (elim H0; congruence; fail); eauto.
              replace (upd b7 tid b5) with (upd b2 tid b4).
              econstructor; eauto.
              econstructor; eauto.
              inv M3.
              inv ES1.
              inv TM1.
              inv ES.
              econstructor; eauto.
              rewrite upd_o; auto.
              rewrite <- R7; auto.
              apply extensionality; unfold upd; intros; repeat destruct peq; auto; try congruence.
              inv M3; auto.
              inv ES.
              rewrite R7; auto.
            > econstructor; eauto.
              rewrite PTree.gso; eauto.
              rewrite <- R3; eauto.
              apply PTree.ext; intros.
              repeat rewrite PTree.gsspec; destruct peq; destruct peq;
                try (elim H0; congruence; fail); eauto.
              replace (upd b7 tid b5) with (upd b2 tid b4); eauto.
              econstructor; eauto.
              econstructor; eauto.
              inv M3.
              inv ES1.
              inv TM1.
              inv ES.
              econstructor; eauto.
              apply extensionality; unfold upd; intros; repeat destruct peq; auto; try congruence.
              inv M3; auto.
              inv ES.
              rewrite R7; auto.
            > inv INJECT.
        > replace (ts2 ! tid <- (RIInjectState stack c sp pc rs regs s5))
          with (ts7 ! tid <- (RIInjectState stack c sp pc rs regs s5)).
          econstructor 2; eauto.
          inv AS.
          replace (upd (upd b1 tid' b') tid b5) with (upd (upd b2 tid b4) tid' b'); eauto.
          econstructor; eauto.
          rewrite upd_o; auto.
          rewrite <- R7; eauto.
          inv M3.
          inv ES.
          inv TM1.
          inv TM2; inv TM4; subst; try econstructor; eauto.
          econstructor 1; auto.
          apply extensionality; unfold upd; intros; repeat destruct peq; auto; try congruence.
          inv M3; auto.
          rewrite R7; auto.
          apply PTree.ext; intros.
          repeat rewrite PTree.gsspec; destruct peq; eauto.
        > replace (upd b7 tid b5) with (upd b2 tid b4).
          econstructor 6; eauto.
          rewrite PTree.gso; auto.
          rewrite <- R3; auto.
          apply PTree.ext; intros.
          repeat rewrite PTree.gsspec.
          repeat destruct peq; eauto.
          congruence.
          rewrite upd_o; auto.
          rewrite <- R7; auto.
          inv M3.
          eapply atrace_mem_trace_atrace; eauto.
          apply extensionality; unfold upd; intros; repeat destruct peq; auto; try congruence.
          inv M3; auto.
          rewrite R7; auto.
Qed.


Lemma astep_none_none: forall m1 ts1 e m2 ts2,
   astep ge (m1,ts1) e (m2,ts2) ->
   ts1 ! tid <> None ->
   ts2 ! tid <> None \/ e = (tid, TEexit :: nil).
Proof.
  intros.
  inv H; auto;
  try (rewrite PTree.gsspec; destruct peq; auto; left; try congruence).
  rewrite PTree.gsspec; destruct peq; auto; congruence.
  rewrite PTree.grspec; destruct peq; auto.
  right; congruence.
Qed.
  

Lemma simul1: forall st1 e st2 stt1' stt1 tr st,
  astep ge st1 (tid,e) st2 ->
  (forall ev, e <> (TEend ev::nil)) ->
  match_state2 st1 stt1' stt1 (proj_trace tr) st->
  match_state2 st2 stt1' stt1 (proj_trace tr) st.
Proof.
  intros.
  inv H1; inv H; try clean_eq_some.
  inv AS1.
  inv ST.
  econstructor; eauto; intros.
  rewrite PTree.gso; eauto.
  rewrite PTree.gss; eauto.
  eelim H0; eauto.
  eelim H0; eauto.
  eelim H0; eauto.
  inv ST.
  destruct m'; econstructor; eauto; intros.
  rewrite PTree.gso; eauto.
  rewrite PTree.gss; eauto.
  assert (b1 tid' = buffers tid').
    eapply tso_step_same_buf; eauto.
    red; intros; subst; inv INJECT.
  rewrite <- R7; auto; congruence.
  destruct m'; econstructor; eauto; intros.
  assert (b1 tid' = buffers tid').
    eapply tso_step_same_buf; eauto.
    congruence.
  rewrite <- R7; auto; congruence.
  inv AS1.
  inv ST.
  inv INJECT.
  inv AS1.
  inv ST.
  inv INJECT.
   inv AS1.
  inv ST.
  inv INJECT.
  inv AS1.
  edestruct atrace_inthemiddle as (s & S1 & S2); eauto.
  subst; inv AS5.
  econstructor; eauto; intros.
  rewrite PTree.gso; eauto.
  rewrite PTree.gss; eauto.
Qed.

Lemma trace_keep_tid_inject_state: forall st0 tr st1,
  trace ge st0 tr st1 -> forall s,
  (snd st0)!tid = Some s -> inject_state s ->
  (forall ev, ~ In (tid,TEend ev::nil) tr) ->
  exists s, (snd st1)!tid = Some s /\ inject_state s.
Proof.
  induction 1. now intros; eexists; intuition eauto.
  intros s H0 H1 H2.
  inv HT2; simpl in *;
  destruct (IHtrace _ H0 H1 (fun ev K => H2 ev (or_intror _ K))) as (q & Q & QI);
  clear IHtrace.
  2: eexists; eauto.
  rewrite PTree.gsspec. destruct peq. subst. eexists; intuition.
  autorw'. destruct s0; clarify. inv AS1; inv ST; auto; try (eelim H2; left; reflexivity).
  eauto.
  rewrite PTree.gso. 2: intros ->; autorw'.
  rewrite PTree.gsspec. destruct peq. subst. eexists; intuition. autorw'. destruct s0; clarify.
  inv AS1. inv ST. auto.
  eauto.
  rewrite PTree.gsspec. destruct peq. subst. eexists; intuition. autorw'. destruct s0; clarify.
  inv AS1. inv ST. auto.
  eauto.
  rewrite PTree.gro. eauto.
  intros ->. autorw'. destruct s0; clarify. inv AS1. inv ST. inv INJECT.
  rewrite PTree.gsspec. destruct peq. subst. eexists; intuition. autorw'. destruct s0; clarify.
  inv AS1. inv AS5. auto.
  eauto.
Qed.

Lemma trace_simul_final_aux: forall st0 tr st1,
  trace ge st0 tr st1 -> forall tr0 st2 s st0' st
  (Hs: exists s, (snd st0)!tid = Some s /\ inject_state s),
  (forall ev, ~ In (tid,TEend ev::nil) tr) ->
  trace_inv ge st1 tr0 st2 ->
  match_state2 st0 s st0' (proj_trace (tr0++tr)) st ->
  exists st1', exists tr', exists s',
    trace ge st0' tr' st1' /\
    match_state2 st1 s' st1' (proj_trace tr0) st /\
    proj_trace tr = proj_trace tr' /\
    filter_not_tid tid tr = filter_not_tid tid tr' /\
    (forall ev l, In (tid,l) tr' -> ~ In (TEend ev) l).
Proof.
  induction 1; simpl; intros.
  exists st0'; exists nil; exists s; simpl; repeat split; auto.
  constructor.
  rewrite app_nil_r in *; auto.
  destruct e as [tid' e].
  rename s1 into st1.
  rename st2 into st3.
  rename s2 into st2.
  assert (trace_inv ge st1 (tr0++(tid',e)::nil) st3).
    econstructor; eauto.
  replace (tr0++(tid',e)::tr) with ((tr0++(tid',e)::nil)++tr) in *.
  exploit IHtrace; eauto; clear IHtrace.
  red; intros; eelim H0; eauto.
  intros (st1' & tr' & s' & S1 & S2 & S3 & S4 & S5).
  destruct (peq tid' tid); try subst tid'.
  > exploit simul1; eauto.
    red; intros; subst; eelim H0; eauto.
    intros Hm.
    exists st1'; exists tr'; exists s'; repeat split; auto.
    rewrite proj_trace_app in Hm.
    simpl in Hm.
    rewrite peq_true in Hm.
    rewrite app_nil_r in *; auto.
    rewrite peq_true; auto.
    simpl; destruct peq; simpl; intuition.
  > exploit simul2; eauto.
    destruct Hs as (ss & SS1 & SS2).
    exploit (trace_keep_tid_inject_state st0); eauto.
    red; intros.
    eelim H0; eauto.
    intros (sss & SSS1 & SSS2); congruence.
    intros (st2' & s'' & tr'' & T1 & T2 & T3 & T4 & T5).
    exists st2'; exists ((tid',e)::tr''++tr'); exists s''; repeat split; auto.
    replace ((tid', e) :: tr'' ++ tr') with (((tid', e) :: tr'') ++ tr') by auto.
    exploit trace_app; eauto.
    rewrite peq_false; auto.
    simpl.
    rewrite peq_false; auto.
    rewrite proj_trace_app.
    rewrite T3; rewrite S3; simpl; auto.
    simpl; destruct peq; simpl.
    congruence.
    rewrite filter_not_tid_app.
    rewrite T4; simpl; congruence.
    intros ev l He; simpl in He; rewrite in_app in He.
    destruct He.
    > congruence.
    > destruct H4; eauto.
    rewrite app_ass; simpl; auto.
Qed.

Lemma trace_simul_final: forall st1 tr st2,
  trace ge st1 tr st2 -> forall s st1' st,
  (exists s, (snd st1)!tid = Some s /\ inject_state s) ->
  (forall ev, ~ In (tid,TEend ev::nil) tr) ->
  match_state2 st1 s st1' (proj_trace tr) st ->
  exists st2', exists tr', exists s',
    trace ge st1' tr' st2' /\
    match_state2 st2 s' st2' nil st /\
    proj_trace tr = proj_trace tr' /\
    filter_not_tid tid tr = filter_not_tid tid tr' /\
    (forall ev l, In (tid,l) tr' -> ~ In (TEend ev) l).
Proof.
  intros.
  assert (trace_inv ge st2 nil st2) by econstructor.
  exploit trace_simul_final_aux; eauto.
Qed.

End simulation1.

Lemma wf_state_invariant_rtl_step: forall refines ge,
  ge_correct_wrt_refines refines ge ->
  forall s e s',
    rtli_step ge s e s' ->
    wf_intra_state refines s ->
    wf_intra_state refines s'.
Proof.
  intros.
  inv H0; inv H1; econstructor; eauto.
  > intro sf; destruct 1.
    > inv H0; simpl; auto.
    > apply (WFSTK _ H0).
  > unfold find_function in FUNC; intros; subst.
    destruct ros.
    > destruct (rs r); simpl in *; try congruence.
      unfold wf_c; intros.
      eapply (H _ _ FUNC); eauto.
    > destruct (Genv.find_symbol ge i); inv FUNC.
      unfold wf_c; intros.
      eapply (H _ _ H1); eauto.
  > intros sf0 S0; apply WFSTK; auto with datatypes.
  > apply WFSTK; auto with datatypes.
Qed.

Lemma wf_state_invariant_astep: forall refines ge,
  ge_correct_wrt_refines refines ge ->
  forall st1 e st2,
    wf_istate refines st1 ->
    astep ge st1 e st2 ->
    wf_istate refines st2.
Proof.
  intros refines ge H H'; intros.
  inv H1; simpl in *; intros; eauto.
  > rewrite PTree.gsspec in H1; destruct peq; eauto.
    inv H1.
    exploit H0; eauto; clear H0; intros W.
    inv AS1.
    > eapply wf_state_invariant_rtl_step; eauto.
    > inv ST; inv W; econstructor; eauto.
    > rewrite PTree.gsspec in H1; destruct peq.
      > inv H1.
        unfold rtl_inject_init in *.
        case_eq (Genv.find_funct_ptr ge fp); intros; rewrite H1 in *; try congruence.
        destruct f; try congruence.
        destruct beq_nat; inv AS5.
        constructor; auto.
        intro; simpl; intuition.
        unfold wf_c; intros.
        inv H2.
        eapply (H _ _ H1); eauto.
      > rewrite PTree.gsspec in H1; destruct peq; eauto.
        inv H1; inv AS1.
        generalize (H0 _ _ AS3).
        inv ST; intros Hw; inv Hw; econstructor; eauto.
    > rewrite PTree.gsspec in H1; destruct peq; eauto.
      inv H1; inv AS1.
      generalize (H0 _ _ AS3).
      inv ST; intros Hw; inv Hw; econstructor; eauto.
    > rewrite PTree.grspec in H1; destruct PTree.elt_eq; eauto; congruence.
    > rewrite PTree.gsspec in H1; destruct peq; eauto.
      assert (wf_intra_state refines s').
        generalize (H0 _ _ AS3).
        inv AS1; intros T; inv T; constructor; auto.
      assert (forall l m s' m' s'',
        atrace ge tid (m, s') l (m', s'') ->
        wf_intra_state refines s' → wf_intra_state refines s'').
        clear - H.
        induction l; intros.
        > inv H0; auto.
        > inv H0.
          exploit IHl; eauto.
          inv AT1.
          > eapply wf_state_invariant_rtl_step; eauto.
          > eapply wf_state_invariant_rtl_step; eauto.
      exploit H3; eauto; clear H3.
      inv H1; inv AS5; intros T; inv T; constructor; auto.
Qed.

Lemma wf_state_invariant_trace: forall refines ge,
  ge_correct_wrt_refines refines ge ->
  forall st1 tr st2,
    trace ge st1 tr st2 ->
    wf_istate refines st1 ->
    wf_istate refines st2.
Proof.
  induction 2; auto.
  intros; apply wf_state_invariant_astep with (3:=HT2); auto.
Qed.

Lemma atrace_not_TEend : forall ge tid st1 tr st2,
  atrace ge tid st1 tr st2 ->
  forall ev, ~ In (TEend ev) tr.
Proof.
  induction 1; auto with datatypes.
  simpl; red; destruct 1.
  > eelim AT5; eauto.
  > eelim IHatrace; eauto.
Qed.

Lemma refines_implies_trace_transformation1: forall ge st1,
  ge_correct_wrt_refines refines_smallstep ge ->
  wf_istate refines_smallstep st1 ->
  forall tr1 tid tr2 st2 ev,
    trace ge st1 ((tid,TEend ev::nil)::tr1++(tid, TEbegin BeginLow::nil)::tr2) st2 ->
    (forall ev' l, In (tid,l) tr1 -> ~ In (TEend ev') l) ->
    exists tr1',
      trace ge st1 ((tid,TEend ev::nil)::tr1'++(tid, TEbegin BeginHigh::nil)::tr2) st2 /\
      (forall ev' l, In (tid,l) tr1'-> ~ In (TEend ev') l) /\
      filter_not_tid tid tr1 = filter_not_tid tid tr1'.
Proof.
  intros ge st1 H H0 tr1 tid tr2 st2 ev H1 H2.
  inv H1.
  apply trace_app_inv in HT1; destruct HT1 as (st3 & S3 & SS3).
  inv S3.
  inv HT0.
  > inv AS1; clear AS2 AS5 AS6.
    inv ST; clear IS_not_mem; try congruence.
    2: inv INJECT.
    assert (R:refines_smallstep ij.(ic_stmt_low) ij.(ic_stmt_high)).
      assert (W1:wf_istate refines_smallstep (m',st)) by (eapply wf_state_invariant_trace; eauto).
      assert (T:=W1 _ _ AS3).
      inv T.
      apply (WFC _ _ _ _ _ PC).
      elim (trace_simul ge sp tid
        (m', st ! tid <- (RIInjectState stk c sp pc' rs dst (init_low ij (map rs args)))) tr1 s1)
      with (st0':=(m'.(shared_mem),m'.(buffers) tid,init_low ij (map rs args))); auto.
      intros st1' (Htr & Hm).
      assert (He:exists stf, Env.intra_step ge sp tid st1' (TEend ev) stf).
        inv HT2; inv Hm.
        > autorw'.
          inv AS1.
          inv ST.
          exists (m'0.(shared_mem), buffers m'0 tid,st2); constructor 1; try congruence; auto.
          exists (m'0.(shared_mem), buffers m'0 tid,ReturnState); constructor 1; try congruence; auto.
          exists (m'0.(shared_mem), buffers m'0 tid,ReturnState); constructor 1; try congruence; auto.
          exists (m'0.(shared_mem), buffers m'0 tid,ReturnState); constructor 1; try congruence; auto.
          eelim atrace_not_TEend; eauto with datatypes.
      destruct He as (stf & He).
      exploit R; eauto; intros (st' & Ht' & Hs').
      assert (Hm2:match_state2 ge sp tid
        (m', st ! tid <- (RIInjectState stk c sp pc' rs dst (init_low ij (map rs args))))
        ((m'.(shared_mem), buffers m' tid), NormalState (fold_left2 upd (fun _ : reg => Vundef) (ic_params ij) (map rs args)) (ic_stmt_high ij) Kend)
        (m', st ! tid <- (RIInjectState stk c sp pc' rs dst (init_high ij (map rs args))))
        (proj_trace tid tr1) st').
        destruct m' as (m' & bufs').
        econstructor; eauto.
        rewrite PTree.gss; eauto.
        intros; repeat rewrite PTree.gso; eauto.
        rewrite PTree.gss; eauto.
    exploit trace_simul_final; eauto.
    simpl; rewrite PTree.gss; econstructor; econstructor; auto.
    red; intros; eelim H2; eauto with datatypes.
    intros (st2' & tr' & s' & Ht1 & Hm2' & Hp1 & Hf & He1).
    inv Hm2'; inv Hm.
    rewrite <- Trace_inv_eq in R6; simpl in R6.
    destruct st' as ((m'',b'),st').
    exploit env_trace_nil; eauto.
    intros (tr & T1 & T2 & T3 & T4).
    rewrite <- trace_inv_eq in T1.
    exists (tr++tr'); repeat split; auto.
    econstructor.
    eapply trace_app; eauto.
    eapply trace_app; eauto.
    econstructor; eauto.
    econstructor; eauto; try congruence.
    econstructor; eauto; try congruence.
    econstructor; eauto.
    simpl in *.
    autorw'.
    clear - HT2 Hs' He R1 R3 R7.
      inv Hs'; inv He.
      inv HT2; econstructor; eauto; try congruence;
        try (rewrite PTree.gss; eauto).
      apply PTree.ext; intros; repeat rewrite PTree.gsspec; destruct peq; eauto.
      autorw'.
      inv AS1.
      replace (upd b2 tid (b1 tid)) with b1.
      econstructor; eauto.
      inv ST1; econstructor; eauto.
      inv INJECT; inv ST0; try congruence.
      inv INJECT; inv ST0; try congruence.
      inv INJECT; inv ST0; try congruence.
      inv INJECT; inv ST0; try congruence.
      apply extensionality; unfold upd; intros; destruct peq; subst; auto.
      apply PTree.ext; intros; repeat rewrite PTree.gsspec; destruct peq; eauto.
      eelim atrace_not_TEend; eauto with datatypes.
      intros.
      rewrite in_app in H1; destruct H1; auto.
      rewrite filter_not_tid_app; rewrite T3; auto.
      red; intros; eelim H2; eauto with datatypes.
      econstructor; eauto.
      rewrite PTree.gss; eauto.
  > inv AS1; inv AS2.
    inv AT2; inv AT1.
    inv ST.
    inv INJECT0.
Qed.
  
End simulation1.

Section equiv_big_small.

Context {fundef: Type}.
Variable ge: genv.
Variable sp: option pointer.
Variable tid: thread_id.


Lemma env_trace_inv_app: forall ge sp s1 l1 s2,
  Env.trace_inv ge sp tid s1 l1 s2 -> forall s3 l2,
  Env.trace_inv ge sp tid s2 l2 s3 ->
  Env.trace_inv ge sp tid s1 (l1++l2) s3.
Proof.
  induction 1; intros; simpl; eauto.
  rewrite (cons'_app _ _ e).
  econstructor; eauto.
  econstructor; eauto.
Qed.

Lemma env_atrace_inv_app: forall ge sp s1 l1 s2,
  Env.atrace_inv ge sp tid s1 l1 s2 -> forall s3 l2,
  Env.atrace_inv ge sp tid s2 l2 s3 ->
  Env.atrace_inv ge sp tid s1 (l1++l2) s3.
Proof.
  induction 1; intros; simpl; eauto.
  econstructor; eauto.
Qed.

Lemma env_trace_inv_nothing_from_return: forall st1 l st2,
  Env.trace_inv ge sp tid st1 l st2 -> forall m m' rs' stmt k,
    st1 = (m, ReturnState) ->
    st2 = (m', NormalState rs' stmt k) -> False.
Proof.
  induction 1; intros; subst.
  congruence.
  inv HT2; eauto.
  inv HT2.
  inv ST.
  inv ST0; eauto.
  inv ST0; eauto.
  eapply IHtrace_inv; reflexivity.
  inv ST1. eelim IS_not_mem; reflexivity.
  inv ST2. eelim IS_not_mem; reflexivity.
  inv ST.
Qed.

Lemma env_atrace_inv_nothing_from_return: forall st1 l st2,
  Env.atrace_inv ge sp tid st1 l st2 -> forall m m' rs' stmt k,
    st1 = (m, ReturnState) ->
    st2 = (m', NormalState rs' stmt k) -> False.
Proof.
  induction 1; intros; subst.
  congruence.
  inv H0.
  inv AT1.
  inv ST.
  inv ST.
Qed.

Fixpoint app_cont (k1 k2:continuation) : continuation :=
  match k1 with
    | Kstmt s k1 => Kstmt s (app_cont k1 k2)
    | Kendatomic b k1 => Kendatomic b (app_cont k1 k2)
    | Kend => k2
  end.

Lemma in_atomic_app : forall k1 k2 f k,
  in_atomic k1 = Some (f,k) ->
    in_atomic (app_cont k1 k2) = Some (f,app_cont k k2).
Proof.
  induction k1; simpl; auto.
  intros.
  inv H; econstructor; eauto.
  intros; congruence.
Qed.

Lemma in_atomic_app' : forall k1 k2,
  in_atomic k1 = None ->
  in_atomic (app_cont k1 k2) = in_atomic k2.
Proof.
  induction k1; simpl; auto.
  intros; congruence.
Qed.

Lemma env_atrace_incr_cont : forall st1 l st2,
  Env.atrace ge sp tid st1 l st2 -> forall m1 m2 rs1 rs2 body1 body2 k1 k2 k,
 st1 = (m1, NormalState rs1 body1 k1) ->
 st2 = (m2, NormalState rs2 body2 k2) ->

 Env.atrace ge sp tid
   (m1, NormalState rs1 body1 (app_cont k1 k)) l
   (m2, NormalState rs2 body2 (app_cont k2 k)).
Proof.
  induction 1; simpl; intros; subst.
  inv H0; constructor.
  inv H1.
  inv AT1.
  destruct st; try (inv ST; fail).
  exploit IHatrace; eauto; intros HI; clear IHatrace.
  econstructor; try eassumption.
  econstructor; eauto.
  inv ST; try (econstructor; eauto; fail).
  eelim IS_not_mem; eauto.
  eelim IS_not_mem; eauto.
  destruct st; try (inv ST; fail).
  exploit IHatrace; eauto; intros HI; clear IHatrace.
  econstructor; try eassumption.
  econstructor; eauto.
  inv ST; vauto.
Qed.

Lemma env_atrace_inv_incr_cont : forall st1 l st2,
  Env.atrace_inv ge sp tid st1 l st2 -> forall m1 m2 rs1 rs2 body1 body2 k1 k2 k,
 st1 = (m1, NormalState rs1 body1 k1) ->
 st2 = (m2, NormalState rs2 body2 k2) ->
 Env.atrace_inv ge sp tid
   (m1, NormalState rs1 body1 (app_cont k1 k)) l
   (m2, NormalState rs2 body2 (app_cont k2 k)).
Proof.
  induction 1; simpl; intros; subst.
  inv H0; constructor.
  inv H0.
  inv AT1.
  destruct st; try (inv ST; fail).
  exploit IHatrace_inv; eauto; intros HI; clear IHatrace_inv.
  econstructor; try eassumption.
  econstructor; eauto.
  inv ST; intuition; try econstructor; eauto.
  eelim IS_not_mem; eauto.
  eelim IS_not_mem; eauto.
  eelim env_atrace_inv_nothing_from_return with (1:=H); eauto.
  destruct st; try (inv ST; fail).
  exploit IHatrace_inv; eauto; intros HI; clear IHatrace_inv.
  econstructor; try eassumption.
  econstructor; eauto.
  inv ST; vauto.
Qed.


Lemma env_trace_inv_incr_cont: forall st1 l st2,
Env.trace_inv ge sp tid st1 l st2 -> forall k m1 rs1 body1 k1 m2 rs2 body2 k2,
 st1 = (m1, NormalState rs1 body1 k1) ->
 st2 = (m2, NormalState rs2 body2 k2) ->

 Env.trace_inv ge sp tid
   (m1, NormalState rs1 body1 (app_cont k1 k)) l
   (m2, NormalState rs2 body2 (app_cont k2 k)).
Proof.
  induction 1; intros; subst.
  > inv H0; constructor.
  > inv HT2.
    exploit (IHtrace_inv k); eauto; intros HI; clear IHtrace_inv.
    econstructor 2; eauto.
    econstructor; eauto.
  > inv HT2.
    inv ST.
    inv ST0;
    (try (exploit (IHtrace_inv k); eauto; intros HI; clear IHtrace_inv;
         vauto;
      econstructor 3 with (1:=HI); eauto;
      econstructor 2; [econstructor; eauto;econstructor; eauto|idtac|idtac]; congruence));
    try (eelim ST1; reflexivity).
    congruence.

    destruct st'; try (inv ST0; fail).
    exploit (IHtrace_inv k); eauto; intros HI; clear IHtrace_inv;
      econstructor 3 with (1:=HI); eauto.
    econstructor 2; [econstructor; eauto|idtac|idtac]; try congruence.
    inv ST0; econstructor; eauto using in_atomic_app.

    now econstructor; vauto; eauto.

    inv ST2.
    inv ST; try (eelim IS_not_mem; eauto; fail).
    
    destruct st'; try (inv ST; fail).
    constructor 3 with (m', NormalState rs stmt (app_cont cont k)).
    eapply IHtrace_inv; eauto.
    clear IHtrace_inv H.
    inv ST1; try (eelim IS_not_mem; eauto; fail).
    destruct s3; try (inv ST; fail).
    inv ST2.
    assert (Env.intra_step ge sp tid
     (m3, nil, NormalState rs0 stmt0 (app_cont cont0 k))
     (TEtso (TSOendatomic f))
     (m', NormalState rs stmt (app_cont cont k))).
      econstructor 2; eauto.
      inv ST; econstructor; eauto using in_atomic_app.
    econstructor 3.
    2: eapply env_atrace_incr_cont; eauto.
    econstructor; eauto.
    econstructor; eauto.
    eauto.
Qed.


Lemma exec_trace_nil_aux : forall af m l m',
  ext_trace tid af m l m' -> snd m = nil -> l = nil -> m=m'.
Proof.
  induction 1; auto.
  destruct e; destruct l; unfold cons'; simpl; try congruence.
  inv H; auto.
  simpl; subst; intros; inv H.
  elim (app_cons_not_nil b2 nil bi); eauto.
Qed.

Lemma exec_trace_nil : forall af m m',
  ext_trace tid af (m,nil) nil m' -> m'=(m,nil).
Proof.
  intros; exploit exec_trace_nil_aux; eauto.
Qed.

Lemma ext_trace_keep_empty_buffer : forall a st tr st',
  ext_trace tid a st tr st' ->
  snd st = nil -> snd st' = nil.
Proof.
  induction 1; simpl; auto; try congruence.
  simpl in *; auto.
  intros; subst; inv H.
  eelim app_cons_not_nil; eauto.
Qed.

Lemma bigstep_keep_empty_buffer_aux : forall st stmt a tr st',
  Bigstep.bigstep ge sp tid st stmt a tr st' ->
  tr = nil ->
  a = Atomic ->
  no_atomic_in_statement stmt ->
  let '(m,b,rs) := st in
  let '(m',b',rs') := st' in
  b = nil -> b'=nil.
Proof.
  induction 1; intros; subst; try congruence;
  simpl in *;
  unfold is_true in *; try rewrite andb_true_iff in *;
  try (exploit ext_trace_keep_empty_buffer; eauto; fail);
  try destruct st as ((m1,b1),s1);
    intuition.
  destruct st'' as ((m2,b2),s2).
  exploit app_eq_nil; eauto.
  destruct 1; eauto.
  destruct st' as ((m2,b2),s2).
  exploit app_eq_nil; eauto.
  destruct 1; eauto.
  destruct st' as ((m2,b2),s2).
  exploit app_eq_nil; eauto.
  destruct 1; eauto.
Qed.

Lemma bigstep_keep_empty_buffer : forall m rs stmt m' b' rs',
  Bigstep.bigstep ge sp tid (m,nil,rs) stmt Atomic nil (m',b',rs') ->
  no_atomic_in_statement stmt ->
  b'=nil.
Proof.
  intros; exploit bigstep_keep_empty_buffer_aux; eauto; simpl.
Qed.

Lemma bigstep_implies_atrace : forall st stmt a tr st',
  Bigstep.bigstep ge sp tid st stmt a tr st' ->
  tr = nil ->
  a = Atomic ->
  no_atomic_in_statement stmt ->
  let '(m,b,rs) := st in
  b = nil ->
    match st' with
      | (m',b',SIntra rs') => exists l,
        Env.atrace_inv ge sp tid (m,NormalState rs stmt Kend) l (m',NormalState rs' Sskip Kend)
      | (m',b',SAbort) => exists l, exists rs', exists r, exists e, exists k',
        Env.atrace_inv ge sp tid (m,NormalState rs stmt Kend) l (m',NormalState rs' (Sabort Atomic r e) k') /\ in_atomic k' = None
      | (m',b',SReturn v) => exists l, exists st',
        Env.atrace_inv ge sp tid (m,NormalState rs stmt Kend) l (m',st') /\
        INJECT.step ge sp st' (TEend (ReturnEvent v)) ReturnState
    end.
Proof.
  induction 1; simpl; intros Htr Ha T; try elim T; try congruence; subst.
  > econstructor; constructor.
  > repeat (econstructor; eauto; try congruence); congruence.
  > repeat (econstructor; eauto; try congruence); congruence.
  > intros; subst; apply exec_trace_nil in H; inv H.
    econstructor; econstructor; eauto; try congruence.
    econstructor 2; eauto; try congruence.
    repeat (econstructor; eauto; try congruence); congruence.
    repeat (econstructor; eauto; try congruence); congruence.
    congruence.
    econstructor.
    congruence.
  > intros; subst; apply exec_trace_nil in H; inv H.
    econstructor; econstructor; eauto; try congruence.
    econstructor 2; eauto.
    repeat (econstructor; eauto; try congruence); congruence.
    congruence.
    congruence.
    econstructor.
    congruence.
  > intros; subst; apply exec_trace_nil in H; inv H.
    econstructor; econstructor; eauto; try congruence.
    econstructor 2; eauto.
    repeat (econstructor; eauto; try congruence); congruence.
    congruence.
    congruence.
    econstructor.
    congruence.
  > intros; subst; apply exec_trace_nil in H; inv H.
    simpl in *. exists (TEato (MEread ap false a v)::nil).
    econstructor 2; [idtac | econstructor 1 | congruence].
    econstructor 2; eauto.
    vauto.
    congruence.
    congruence.
  > econstructor; econstructor; eauto; try congruence.
    econstructor 2; eauto.
    repeat (econstructor; eauto; try congruence); try congruence.
    congruence.
    congruence.
    repeat (econstructor; eauto; try congruence); congruence.
    congruence.
  > unfold is_true in T; rewrite andb_true_iff in T.
    destruct st; destruct p; destruct r; destruct T; intros Hb; subst.
    > destruct IHbigstep as (l' & rs' & r & e & k' & S1 & S2); auto.
      repeat (econstructor; eauto); congruence.
    > destruct IHbigstep as (l' & st' & S1 & S2); auto.
      repeat (econstructor; eauto); congruence.
    > destruct IHbigstep as (l' & S2); auto.
      repeat (econstructor; eauto); congruence.
  > unfold is_true in T; rewrite andb_true_iff in T.
    destruct st; destruct p; destruct r; destruct T; intros Hb; subst.
    > destruct IHbigstep as (l' & rs' & r & e & k' & S1 & S2); auto.
      repeat (econstructor; eauto); congruence.
    > destruct IHbigstep as (l' & st' & S1 & S2); auto.
      repeat (econstructor; eauto); congruence.
    > destruct IHbigstep as (l' & S2); auto.
      repeat (econstructor; eauto); congruence.
  > assert (l1=nil) by (destruct l1; auto; inv Htr).
    intro.
    subst; simpl in Htr; subst.
    destruct st''; destruct p; destruct r; auto.
    > destruct IHbigstep2 as (l' & rs0' & r & e & k' & S1 & S2); auto.
      exploit bigstep_keep_empty_buffer; eauto.
      destruct IHbigstep1 as (l'' & S4); auto.
      assert
        (Env.atrace_inv ge sp tid (m, NormalState rs body (app_cont Kend (Kstmt (Swhile cond args body) Kend))) l''
          (m', NormalState rs' Sskip (app_cont Kend (Kstmt (Swhile cond args body) Kend)))).
        eapply env_atrace_inv_incr_cont; eauto.
      econstructor; econstructor; econstructor; econstructor; econstructor; split.
      econstructor.
      econstructor.
      econstructor; eauto.
      congruence.
      simpl in H3.
      eapply env_atrace_inv_app with (1:=H3).
      econstructor.
      econstructor.
      econstructor; eauto.
      congruence.
      eauto.
      congruence.
      congruence.
      eauto.
    > destruct IHbigstep2 as (l' & st' & S1 & S2); auto.
      exploit bigstep_keep_empty_buffer; eauto.
      destruct IHbigstep1 as (l'' & S4); auto.
      assert
        (Env.atrace_inv ge sp tid (m, NormalState rs body (app_cont Kend (Kstmt (Swhile cond args body) Kend))) l''
          (m', NormalState rs' Sskip (app_cont Kend (Kstmt (Swhile cond args body) Kend)))).
        eapply env_atrace_inv_incr_cont; eauto.
      simpl in H3.
      econstructor; econstructor; split.
      econstructor.
      econstructor.
      econstructor; eauto.
      congruence.
      eapply env_atrace_inv_app with (1:=H3).
      econstructor.
      econstructor.
      econstructor; eauto.
      congruence.
      eauto.
      congruence.
      congruence.
      eauto.
    > destruct IHbigstep2 as (l' & S1); auto.
      exploit bigstep_keep_empty_buffer; eauto.
      destruct IHbigstep1 as (l'' & S4); auto.
      assert
        (Env.atrace_inv ge sp tid (m, NormalState rs body (app_cont Kend (Kstmt (Swhile cond args body) Kend))) l''
          (m', NormalState rs' Sskip (app_cont Kend (Kstmt (Swhile cond args body) Kend)))).
        eapply env_atrace_inv_incr_cont; eauto.
      simpl in H3.
      econstructor.
      econstructor.
      econstructor.
      econstructor; eauto.
      congruence.
      eapply env_atrace_inv_app with (1:=H3).
      econstructor.
      econstructor.
      econstructor; eauto.
      congruence.
      eauto.
      congruence.
      congruence.
  > destruct st; destruct p; destruct r; auto; intro; subst.
    > destruct IHbigstep as (l' & rs' & r & e & k' & S1 & S2); auto.
      inv S2.
      econstructor; exists rs'; exists r; exists e; exists
          (app_cont k' (Kstmt (Swhile cond args body) Kend)); split.
      econstructor.
      econstructor.
      econstructor; eauto.
      congruence.
      assert (Env.atrace_inv ge sp tid
         (m, NormalState rs body (app_cont Kend (Kstmt (Swhile cond args body) Kend))) l'
         (m0, NormalState rs' (Sabort Atomic r e) (app_cont k' (Kstmt (Swhile cond args body) Kend)))).
        eapply env_atrace_inv_incr_cont; eauto.
      simpl in H2.
      eapply H2.
      congruence.
      rewrite in_atomic_app'; auto.
    > destruct IHbigstep as (l' & st' & S1 & S2); auto.
      inv S2.
      econstructor;
        exists (NormalState rs0 (Sreturn res)
          (app_cont k (Kstmt (Swhile cond args body) Kend))); split.
      econstructor.
      econstructor.
      econstructor; eauto.
      congruence.
      assert (Env.atrace_inv ge sp tid
         (m, NormalState rs body (app_cont Kend (Kstmt (Swhile cond args body) Kend))) l'
         (m0, NormalState rs0 (Sreturn res) (app_cont k (Kstmt (Swhile cond args body) Kend)))).
        eapply env_atrace_inv_incr_cont; eauto.
      simpl in H2.
      eapply H2.
      congruence.
      econstructor; eauto.
      rewrite in_atomic_app'; auto.
    > eelim H1; eauto.
  > econstructor.
    econstructor.
    econstructor.
    eapply INJECT.exec_while_false; eauto.
    congruence.
    econstructor; eauto.
    congruence.
  > destruct st; destruct st'; destruct p; destruct p0. destruct r0; intro; subst.
    exploit IHbigstep; eauto.
    simpl; unfold is_true; rewrite andb_true_iff; intuition.
    intros (tr & rs' & r0 & e & k' & S1 & S2).
    exists (TEtau::tr); exists rs'; exists r0; exists e; exists k'; split; auto.
    inv S2.
    econstructor; eauto; try congruence.
    vauto.
  > exploit IHbigstep; eauto.
    simpl; unfold is_true; rewrite andb_true_iff; intuition.
    intros (tr & st' & S1 & S2).
    exists (TEtau::tr); exists st'; split; auto.
    inv S2.
    econstructor; eauto; try congruence.
    vauto.
  > exploit IHbigstep; eauto.
    simpl; unfold is_true; rewrite andb_true_iff; intuition.
    intros (tr & S1).
    exists (TEtau::tr); auto.
    econstructor; eauto; try congruence.
    vauto.
  > destruct st; destruct st'; destruct p; destruct p0; destruct r0; intros; subst.
    > assert (l1=nil) by (destruct l1; auto; inv Htr).
      subst; simpl in Htr; subst.
      unfold is_true in *; rewrite andb_true_iff in *; destruct T.
      exploit IHbigstep1; eauto; intros (l1 & T1); clear IHbigstep1.
      exploit IHbigstep2; eauto.
      exploit bigstep_keep_empty_buffer; eauto.
      intros (l2 & rs2 & r2 & e2 & k' & T2 & T3); clear IHbigstep2.
      econstructor; econstructor; econstructor; econstructor; econstructor; split; [idtac|eassumption].
      eapply env_atrace_inv_app with (2:=T2).
      assert (
        Env.atrace_inv ge sp tid (m, NormalState r stmt1 (app_cont Kend (Kstmt stmt2 Kend))) l1
           (m', NormalState rs' Sskip (app_cont Kend (Kstmt stmt2 Kend)))).
        eapply env_atrace_inv_incr_cont; eauto.
      simpl in H3.
      econstructor.
      repeat (econstructor; eauto); congruence.
      eapply env_atrace_inv_app with (1:=H4).
      econstructor.
      repeat (econstructor; eauto); congruence.
      econstructor.
      congruence.
      congruence.
    > assert (l1=nil) by (destruct l1; auto; inv Htr).
      subst; simpl in Htr; subst.
      unfold is_true in *; rewrite andb_true_iff in *; destruct T.
      exploit IHbigstep1; eauto; intros (l1 & T1); clear IHbigstep1.
      exploit IHbigstep2; eauto.
      exploit bigstep_keep_empty_buffer; eauto.
      intros (l2 & st2 & T2 & T3); clear IHbigstep2.
      econstructor; econstructor; split; [idtac|eassumption].
      eapply env_atrace_inv_app with (2:=T2).
      assert (
        Env.atrace_inv ge sp tid (m, NormalState r stmt1 (app_cont Kend (Kstmt stmt2 Kend))) l1
           (m', NormalState rs' Sskip (app_cont Kend (Kstmt stmt2 Kend)))).
        eapply env_atrace_inv_incr_cont; eauto.
      simpl in H3.
      econstructor.
      repeat (econstructor; eauto); congruence.
      eapply env_atrace_inv_app with (1:=H4).
      econstructor.
      repeat (econstructor; eauto); congruence.
      econstructor.
      congruence.
      congruence.
    > assert (l1=nil) by (destruct l1; auto; inv Htr).
      subst; simpl in Htr; subst.
      unfold is_true in *; rewrite andb_true_iff in *; destruct T.
      exploit IHbigstep1; eauto; intros (l1 & T1); clear IHbigstep1.
      exploit IHbigstep2; eauto.
      exploit bigstep_keep_empty_buffer; eauto.
      intros (l2 & T2); clear IHbigstep2.
      econstructor.
      eapply env_atrace_inv_app with (2:=T2).
      assert (
        Env.atrace_inv ge sp tid (m, NormalState r stmt1 (app_cont Kend (Kstmt stmt2 Kend))) l1
           (m', NormalState rs' Sskip (app_cont Kend (Kstmt stmt2 Kend)))).
        eapply env_atrace_inv_incr_cont; eauto.
      simpl in H3.
      econstructor.
      repeat (econstructor; eauto); congruence.
      eapply env_atrace_inv_app with (1:=H4).
      econstructor.
      repeat (econstructor; eauto); congruence.
      econstructor.
      congruence.
      congruence.
  > unfold is_true in *; rewrite andb_true_iff in *; destruct T.
    destruct st; destruct st'; destruct p; destruct p0; destruct r0; intros; subst.
    > exploit IHbigstep; eauto; intros (l2 & rs2 & r2 & e & k2 & T2 & T3); clear IHbigstep.
      inv T3.
      econstructor; econstructor; econstructor; econstructor; econstructor; split.
      econstructor.
      repeat (econstructor; eauto); congruence.
      assert (
        Env.atrace_inv ge sp tid (m, NormalState r stmt1 (app_cont Kend (Kstmt stmt2 Kend))) l2
           (m0, NormalState rs2 (Sabort Atomic r2 e) (app_cont k2 (Kstmt stmt2 Kend)))).
        eapply env_atrace_inv_incr_cont; eauto.
      simpl in H3.
      eapply env_atrace_inv_app with (1:=H3).
      econstructor 1.
      congruence.
      rewrite in_atomic_app'; auto.
    > exploit IHbigstep; eauto; intros (l2 & st2 & T2 & T3); clear IHbigstep.
      inv T3.
      econstructor; econstructor; split.
      econstructor.
      repeat (econstructor; eauto); congruence.
      assert (
        Env.atrace_inv ge sp tid (m, NormalState r stmt1 (app_cont Kend (Kstmt stmt2 Kend))) l2
           (m0, NormalState rs (Sreturn res) (app_cont k (Kstmt stmt2 Kend)))).
        eapply env_atrace_inv_incr_cont; eauto.
      simpl in H3.
      eapply env_atrace_inv_app with (1:=H3).
      econstructor 1.
      congruence.
      econstructor.
      rewrite in_atomic_app'; auto.
    > eelim H0; eauto.
  > repeat (econstructor; eauto).
  > intros; econstructor; econstructor; econstructor; econstructor; econstructor; split.
    vauto.
    auto.
  > intros; subst.
    repeat (econstructor; eauto; try congruence); congruence.
  > destruct st; destruct st'; destruct p; destruct p0; destruct r0; intros; subst;
    unfold is_true in *; rewrite andb_true_iff in T; destruct T.
    > exploit IHbigstep; eauto; intros (l2 & rs2 & r2 & e & k2 & T2 & T3); clear IHbigstep.
      econstructor; econstructor; econstructor; econstructor; econstructor; split; eauto.
      econstructor.
      repeat (econstructor; eauto); congruence.
      eapply env_atrace_inv_app with (1:=T2).
      econstructor 1.
      congruence.
    > exploit IHbigstep; eauto; intros (l2 & st2 & T2 & T3); clear IHbigstep.
      inv T3.
      econstructor; econstructor; split.
      econstructor.
      repeat (econstructor; eauto); congruence.
      eapply env_atrace_inv_app with (1:=T2).
      econstructor 1.
      congruence.
      econstructor.
      auto.
    > exploit IHbigstep; eauto; intros (l2 & T3); clear IHbigstep.
      econstructor.
      econstructor.
      repeat (econstructor; eauto); congruence.
      eauto.
      congruence.
  > destruct st; destruct st'; destruct p; destruct p0; destruct r0; intros; subst;
    unfold is_true in *; rewrite andb_true_iff in T; destruct T.
    > exploit IHbigstep; eauto; intros (l2 & rs2 & r2 & e & k2 & T2 & T3); clear IHbigstep.
      econstructor; econstructor; econstructor; econstructor; econstructor; split; eauto.
      econstructor.
      econstructor.
      eapply INJECT.exec_branch_right; eauto.
      congruence.
      eauto.
      congruence.
    > exploit IHbigstep; eauto; intros (l2 & st2 & T2 & T3); clear IHbigstep.
      inv T3.
      econstructor; econstructor; split.
      econstructor.
      econstructor.
      eapply INJECT.exec_branch_right; eauto.
      congruence.
      eauto.
      congruence.
      econstructor.
      auto.
    > exploit IHbigstep; eauto; intros (l2 & T2); clear IHbigstep.
      econstructor.
      econstructor.
      econstructor.
      eapply INJECT.exec_branch_right; eauto.
      congruence.
      eauto.
      congruence.
  > intros; subst; repeat (econstructor; eauto); congruence.
  > destruct st; destruct st'; destruct p; destruct p0; destruct r0; intros; subst.
    exploit app_eq_nil; eauto; destruct 1; clear Htr; subst.
    exploit IHbigstep1; eauto; intros (l1 & T1); clear IHbigstep1.
    exploit IHbigstep2; eauto.
    eapply bigstep_keep_empty_buffer; eauto.
    intros (l2 & rs2 & r2 & e & k2 & T2 & T3); clear IHbigstep2.
    econstructor; econstructor; econstructor; econstructor; econstructor; split; [idtac|eassumption].
    eapply env_atrace_inv_app with (2:=T2).
    assert (
        Env.atrace_inv ge sp tid (m0, NormalState r s (app_cont Kend (Kstmt (Sloop s) Kend))) l1
           (m, NormalState rs Sskip (app_cont Kend (Kstmt (Sloop s) Kend)))).
        eapply env_atrace_inv_incr_cont; eauto.
      simpl in H2.
      econstructor.
      2: eapply env_atrace_inv_app with (1:=H2).
      econstructor.
      econstructor.
      congruence.
      econstructor; eauto.
      2: econstructor 1; eauto.
      econstructor; eauto.
      econstructor; eauto.
      congruence.
      congruence.
      congruence.
    exploit app_eq_nil; eauto; destruct 1; clear Htr; subst.
    exploit IHbigstep1; eauto; intros (l1 & T1); clear IHbigstep1.
    exploit IHbigstep2; eauto.
    eapply bigstep_keep_empty_buffer; eauto.
    intros (l2 & st2 & T2 & T3); clear IHbigstep2.
    econstructor; econstructor; split; [idtac|eassumption].
    eapply env_atrace_inv_app with (2:=T2).
    assert (
        Env.atrace_inv ge sp tid (m0, NormalState r s (app_cont Kend (Kstmt (Sloop s) Kend))) l1
           (m, NormalState rs Sskip (app_cont Kend (Kstmt (Sloop s) Kend)))).
        eapply env_atrace_inv_incr_cont; eauto.
      simpl in H2.
      econstructor.
      2: eapply env_atrace_inv_app with (1:=H2).
      econstructor.
      econstructor.
      congruence.
      econstructor; eauto.
      2: econstructor 1; eauto.
      econstructor; eauto.
      econstructor; eauto.
      congruence.
      congruence.
      congruence.
    exploit app_eq_nil; eauto; destruct 1; clear Htr; subst.
    exploit IHbigstep1; eauto; intros (l1 & T1); clear IHbigstep1.
    exploit IHbigstep2; eauto.
    eapply bigstep_keep_empty_buffer; eauto.
    intros (l2 & T2); clear IHbigstep2.
    econstructor.
    eapply env_atrace_inv_app with (2:=T2).
    assert (
        Env.atrace_inv ge sp tid (m0, NormalState r s (app_cont Kend (Kstmt (Sloop s) Kend))) l1
           (m, NormalState rs Sskip (app_cont Kend (Kstmt (Sloop s) Kend)))).
        eapply env_atrace_inv_incr_cont; eauto.
      simpl in H1.
      econstructor.
      2: eapply env_atrace_inv_app with (1:=H2).
      econstructor.
      econstructor.
      congruence.
      econstructor; eauto.
      2: econstructor 1; eauto.
      econstructor; eauto.
      econstructor; eauto.
      congruence.
      congruence.
      congruence.
  > destruct st; destruct st'; destruct p; destruct p0; destruct r0; intros; subst.
    exploit IHbigstep; eauto; intros (l2 & rs2 & r2 & e & k2 & T2 & T3); clear IHbigstep.
    econstructor; econstructor; econstructor; econstructor; econstructor; split.
    assert (
        Env.atrace_inv ge sp tid (m, NormalState r s (app_cont Kend (Kstmt (Sloop s) Kend))) l2
           (m0, NormalState rs2 (Sabort Atomic r2 e) (app_cont k2 (Kstmt (Sloop s) Kend)))).
        eapply env_atrace_inv_incr_cont; eauto.
      simpl in H1.
      econstructor.
      2: eapply env_atrace_inv_app with (1:=H1).
      econstructor.
      econstructor.
      congruence.
      econstructor; eauto.
      congruence.
    rewrite in_atomic_app'; eauto.
    exploit IHbigstep; eauto; intros (l2 & st2 & T2 & T3); clear IHbigstep.
    inv T3.
    econstructor.
        exists (NormalState rs (Sreturn res)
          (app_cont k (Kstmt (Sloop s) Kend))); split.
    assert (
        Env.atrace_inv ge sp tid (m, NormalState r s (app_cont Kend (Kstmt (Sloop s) Kend))) l2
           (m0, NormalState rs (Sreturn res) (app_cont k (Kstmt (Sloop s) Kend)))).
        eapply env_atrace_inv_incr_cont; eauto.
      simpl in H1.
      econstructor.
      2: eapply env_atrace_inv_app with (1:=H1).
      econstructor.
      econstructor.
      congruence.
      econstructor; eauto.
      congruence.
      econstructor; eauto.
      rewrite in_atomic_app'; auto.
    exploit IHbigstep; eauto; intros (l1 & T1); clear IHbigstep.
    econstructor.
    assert (
        Env.atrace_inv ge sp tid (m, NormalState r s (app_cont Kend (Kstmt (Sloop s) Kend))) l1
           (m0, NormalState r0 Sskip (app_cont Kend (Kstmt (Sloop s) Kend)))).
        eapply env_atrace_inv_incr_cont; eauto.
      simpl in H1.
      econstructor.
      2: eapply env_atrace_inv_app with (1:=H1).
      econstructor.
      econstructor.
      congruence.
      econstructor.
      econstructor.
      econstructor.
      congruence.
      econstructor.
      econstructor.
      eapply INJECT.exec_loop_end; eauto.
      congruence.
      econstructor; eauto.
      congruence.
      congruence.
      congruence.
Qed.


Fixpoint no_atomic_in_continuation (k:continuation) : Prop :=
  match k with
    | Kend => True
    | Kstmt s k => no_atomic_in_statement s /\ no_atomic_in_continuation k
    | Kendatomic _ _ => False
  end.

Lemma no_atomic_in_continuation_in_atomic: forall k1,
  no_atomic_in_continuation k1 ->
  in_atomic k1 = None.
Proof.
  induction k1; simpl.
  destruct 1; eauto.
  intuition.
  auto.
Qed.

Definition no_atomic_in_state (s:INJECT.state) : Prop :=
  match s with
    | ReturnState => True
    | NormalState rs stmt k => no_atomic_in_statement stmt /\ no_atomic_in_continuation k
  end.

Lemma env_atrace_no_atomic: forall ge sp st1 l st2,
  Env.atrace_inv ge sp tid st1 l st2 ->
  no_atomic_in_state (snd st1) ->
  no_atomic_in_state (snd st2).
Proof.
  induction 1; auto; intros.
  simpl in *.
  apply IHatrace_inv; clear IHatrace_inv.
  inv AT1; try inv ST; simpl in *; intuition; try andb; auto;
  unfold is_true in *; autorw';
  eelim IS_not_mem; eauto.
Qed.

Lemma ext_trace_env_trace_inv: forall a m l m',
  ext_trace tid a m l m' -> forall m0 st0 st,
  Env.trace_inv ge sp tid (m', st) nil (m0,st0) ->
  Env.trace_inv ge sp tid (m, st) l (m0,st0).
Proof.
  induction 1; intros; auto.
  econstructor; eauto.
  eapply IHext_trace; eauto.
  econstructor; eauto.
  econstructor 3; eauto.
  eapply IHext_trace; eauto.
  inv H.
  econstructor 2; eauto.
  econstructor 3; eauto.
  unfold Env.cast.
  replace (upd (fun _ : positive => nil) tid b2)
    with (upd (upd (fun _ : positive => nil) tid (b2++bi::nil)) tid b2).
  econstructor; eauto.
  rewrite upd_s; auto.
  apply extensionality; unfold upd; intros; destruct peq; auto.
  congruence.
  congruence.
Qed.


Lemma env_atrace_inv_eq1_aux: forall t S l s0,
  Env.atrace ge sp t S l s0 -> forall e m' st',
  let (m, st) := S in
  (forall ev : end_event, e <> TEend ev) ->
  Env.atomic_intra_step ge sp t (m', st') e (m, st) ->
  Env.atrace ge sp t (m', st') (l ++ e::nil) s0.
Proof.
  induction 1; intros.
  destruct s; intros.
  simpl.
  repeat (econstructor; eauto).
  destruct s0; intros.
  simpl.
  econstructor; eauto.
Qed.

Lemma env_atrace_inv_eq1:
  forall t st l st',
    Env.atrace_inv ge sp t st l st' -> Env.atrace ge sp t st (rev l) st'.
Proof.
  induction 1.
  constructor.
  simpl.
  exploit env_atrace_inv_eq1_aux; eauto.
Qed.

Lemma env_atrace_inv_eq2_aux: forall t S l s0,
  Env.atrace_inv ge sp t s0 l S -> forall e m' st',
  let (m, st) := S in
  (forall ev : end_event, e <> TEend ev) ->
  Env.atomic_intra_step ge sp t (m, st) e (m', st') ->
  Env.atrace_inv ge sp t s0 (l++e::nil) (m', st').
Proof.
  induction 1; intros.
  destruct s; intros.
  simpl.
  repeat (econstructor; eauto).
  destruct s0; intros.
  simpl.
  econstructor; eauto.
Qed.

Lemma env_atrace_inv_eq2:
  forall t st l st',
    Env.atrace ge sp t st l st' -> Env.atrace_inv ge sp t st (rev l) st'.
Proof.
  induction 1.
  constructor.
  simpl.
  exploit env_atrace_inv_eq2_aux; eauto.
Qed.

Lemma no_atomic_in_statement1: forall stmt,
  INJECT.no_atomic_in_statement stmt ->
  no_atomic_in_statement stmt.
Proof.
  induction stmt; simpl; auto.
  unfold is_true in *; rewrite andb_true_iff; intuition.
  unfold is_true in *; rewrite andb_true_iff; intuition.
  intuition.
  unfold is_true in *; rewrite andb_true_iff; intuition.
Qed.
Hint Resolve no_atomic_in_statement1.

Lemma bigstep_implies_smallstep_aux : forall st stmt a tr st',
  Bigstep.bigstep ge sp tid st stmt a tr st' ->
  a = Interleaved ->
  let (m,rs) := st in
    match st' with
      | (m',SIntra rs') => Env.trace_inv ge sp tid (m,NormalState rs stmt Kend) tr (m',NormalState rs' Sskip Kend)
      | (m',SAbort) => exists st',
        Env.trace_inv ge sp tid (m,NormalState rs stmt Kend) tr (m',st') /\
        INJECT.step ge sp st' (TEend FailEvent) ReturnState
      | (m',SReturn v) => exists st',
        Env.trace_inv ge sp tid (m,NormalState rs stmt Kend) tr (m',st') /\
        INJECT.step ge sp st' (TEend (ReturnEvent v)) ReturnState
    end.
Proof.
  induction 1; intros; try congruence; subst.
  > constructor.
  > eapply ext_trace_env_trace_inv; eauto.
    assert (Env.step ge sp tid
      (m'', nil, NormalState rs (Sfence false) Kend) None
      (m'', nil, NormalState rs Sskip Kend)).
      econstructor.
      econstructor 2; eauto.
      econstructor.
      econstructor; eauto.
      simpl; auto.
      rewrite upd_s; auto.
      congruence.
      congruence.
    destruct r.
    > assert (Env.step ge sp tid
      (m', nil, NormalState rs (Sfence true) Kend) None
      (m', nil, NormalState rs Srelease Kend)).
        econstructor.
        econstructor 2; eauto.
        econstructor.
        econstructor; eauto.
        simpl.
        rewrite upd_s; auto.
        congruence.
        congruence.
      econstructor 3; eauto.
      econstructor 3; eauto.
      econstructor 1; eauto.
      econstructor 2; eauto.
      repeat (econstructor; eauto).
      congruence.
      congruence.
    > econstructor 3; eauto.
      econstructor 1.
      econstructor 2; eauto.
      econstructor 2; eauto.
      repeat (econstructor; eauto); try congruence.
      subst; repeat (econstructor; eauto); try congruence.
      simpl; rewrite upd_s; auto.
      congruence.
      congruence.
  > repeat (econstructor; eauto); congruence.
  > clear IHbigstep H2.
    exploit bigstep_implies_atrace; eauto.
    simpl.
    destruct rs''; intros HH1.
    > destruct (HH1 (refl_equal _)) as (l' & rs' & r & e & k' & L1 & L2).
      exists (NormalState rs' (Sabort Interleaved r e) Kend).
      split; eauto.
      2: econstructor; auto.
      assert (Env.atrace_inv ge sp tid
        (m', NormalState rs body (app_cont Kend (Kendatomic fence Kend))) l'
        (m''', NormalState rs' (Sabort Atomic r e) (app_cont k' (Kendatomic fence Kend)))).
        eapply env_atrace_inv_incr_cont; eauto.
      eapply ext_trace_env_trace_inv; eauto.
      simpl in H2.
      econstructor.
      econstructor 1.
      econstructor 3.
      econstructor 2.
      econstructor; eauto; congruence.
      econstructor; eauto; congruence.
      apply env_atrace_inv_eq1.
      eapply H2.
      econstructor 2.
      econstructor; eauto; try congruence.
      rewrite in_atomic_app'; simpl; eauto.
      econstructor.
    > destruct (HH1 (refl_equal _)) as (l' & st' & L1 & L2).
      inv L2.
      exists (NormalState rs0 (Sreturn res) Kend).
      split; eauto.
      2: econstructor; auto.
      assert (Env.atrace_inv ge sp tid
        (m', NormalState rs body (app_cont Kend (Kendatomic fence Kend))) l'
        (m''', NormalState rs0 (Sreturn res) (app_cont k (Kendatomic fence Kend)))).
        eapply env_atrace_inv_incr_cont; eauto.
      eapply ext_trace_env_trace_inv; eauto.
      econstructor.
      econstructor 1.
      econstructor 3.
      econstructor 2.
      econstructor; eauto; congruence.
      econstructor; eauto; congruence.
      simpl in H2.
      apply env_atrace_inv_eq1.
      eapply H2.
      econstructor 2.
      econstructor; eauto; try congruence.
      rewrite in_atomic_app'; simpl; eauto.
      econstructor.
    > eapply ext_trace_env_trace_inv; eauto.
      econstructor; [econstructor|idtac].
      exploit bigstep_implies_atrace; eauto; simpl.
      intros T.
      destruct T as (l' & S3); auto.
      assert (Env.atrace ge sp tid
        (m', NormalState rs body (app_cont Kend (Kendatomic fence Kend))) (rev l')
        (m''', NormalState r Sskip (app_cont Kend (Kendatomic fence Kend)))).
        apply env_atrace_inv_eq1; eauto.
        eapply env_atrace_inv_incr_cont; eauto.
      econstructor 3.
      econstructor 2; eauto.
      econstructor; eauto.
      econstructor; eauto.
      apply H2.
      econstructor 2; eauto.
      econstructor; eauto.
      econstructor; eauto.
  > repeat (econstructor; eauto); try congruence.
  > eapply ext_trace_env_trace_inv; eauto.
    econstructor; [econstructor 1|idtac].
    econstructor 2 with (e:=TEtso (TSOmem (MEperm PEfreeperm))); eauto; try congruence.
    econstructor 2; eauto.
    econstructor; eauto.
    econstructor; eauto.
  > eapply ext_trace_env_trace_inv; eauto.
    econstructor; [econstructor 1|idtac].
    econstructor 2 with (e:=TEtso (TSOmem (MEperm PErelease))); eauto; try congruence.
    econstructor 2; eauto.
    econstructor; eauto.
    econstructor; eauto.
  > eapply ext_trace_env_trace_inv; eauto.
    econstructor; [econstructor 1|idtac].
    econstructor 2 with (e:=TEtso (TSOmem (MEperm (PErequest rp a)))); eauto; try congruence.
    econstructor 2; eauto.
    econstructor; eauto.
    econstructor; eauto.
  > eapply ext_trace_env_trace_inv; eauto. destruct m' as (m' & d').
    econstructor; [econstructor 1|idtac].
    econstructor 2 with (e:=TEtso (TSOmem (MEread ap (addr_in_buf a b') a v))); eauto; try congruence.
    econstructor 2; eauto.
    econstructor ;eauto.
    econstructor; eauto.
    bif2. rewrite upd_s. intuition. rewrite upd_s. assumption.
    rewrite upd_s; reflexivity.
  > eapply ext_trace_env_trace_inv; eauto.
    econstructor; [econstructor 1|idtac].
    econstructor 2; eauto; try congruence.
    econstructor 2; eauto.
    econstructor; eauto.
    unfold Env.cast; simpl.
    replace (upd (fun _ => nil) tid (push_item (WBufItem a (rs src)) b'))
      with (upd (upd (fun _ : positive => nil) tid b') tid (push_item (WBufItem a (rs src)) b')).
    econstructor; eauto.
    rewrite upd_s; auto.
    apply extensionality; intro; unfold upd; destruct peq; auto.
    congruence.
    congruence.
  > eapply ext_trace_env_trace_inv; eauto.
    econstructor; [econstructor 1|idtac].
    econstructor 2; eauto; try congruence.
    econstructor 2; eauto.
    econstructor ;eauto.
    inv H1; econstructor ;eauto.
    rewrite upd_s; auto.
    congruence.
    congruence.
  > destruct st; destruct r; auto.
    > destruct IHbigstep as (st' & S1 & S2); auto.
      econstructor; split; [idtac|eassumption].
      econstructor; [eassumption|idtac].
      econstructor; eauto; [econstructor 1; [econstructor; eauto|idtac]|idtac|idtac];
        try congruence.
    > destruct IHbigstep as (st' & S1 & S2); auto.
      econstructor; split; [idtac|eassumption].
      econstructor; [eassumption|idtac].
      econstructor; eauto; [econstructor 1; [econstructor; eauto|idtac]|idtac|idtac];
        try congruence.
    > econstructor; [eauto|idtac]; auto.
      econstructor; eauto; [econstructor 1; [econstructor; eauto|idtac]|idtac|idtac];
        try congruence.
  > destruct st; destruct r; auto.
    > destruct IHbigstep as (st' & S1 & S2); auto.
      econstructor; split; [idtac|eassumption].
      econstructor; [eassumption|idtac].
      econstructor; eauto; [econstructor 1; [econstructor; eauto|idtac]|idtac|idtac];
        try congruence.
    > destruct IHbigstep as (st' & S1 & S2); auto.
      econstructor; split; [idtac|eassumption].
      econstructor; [eassumption|idtac].
      econstructor; eauto; [econstructor 1; [econstructor; eauto|idtac]|idtac|idtac];
        try congruence.
    > econstructor; [eauto|idtac].
      econstructor; eauto; [econstructor 1; [econstructor; eauto|idtac]|idtac|idtac];
        try congruence.
  > destruct st''; destruct r; auto.
    > destruct IHbigstep2 as (st' & S1 & S2); auto.
      econstructor; split; [idtac|eassumption].
      eapply env_trace_inv_app; eauto.
      econstructor; [idtac|econstructor;
        [econstructor; [econstructor; eauto|idtac]|idtac|idtac]]; try congruence.
      rewrite Env.trace_inv_eq.
      econstructor; [idtac| econstructor;[econstructor;[econstructor 1|idtac]|idtac|idtac]];
        try congruence.
      assert (Env.trace_inv ge sp tid
          (m, b, NormalState rs body (app_cont Kend (Kstmt (Swhile cond args body) Kend)))
          l1
          (m', b', NormalState rs' Sskip (app_cont Kend (Kstmt (Swhile cond args body) Kend)))).
      eapply env_trace_inv_incr_cont; eauto.
      simpl in H3.
      rewrite <- Env.trace_inv_eq; auto.
    > destruct IHbigstep2 as (st' & S1 & S2); auto.
      econstructor; split; [idtac|eassumption].
      eapply env_trace_inv_app; eauto.
      econstructor; [idtac|econstructor;
        [econstructor; [econstructor; eauto|idtac]|idtac|idtac]]; try congruence.
      rewrite Env.trace_inv_eq.
      econstructor; [idtac| econstructor;[econstructor;[econstructor 1|idtac]|idtac|idtac]];
        try congruence.
      assert (Env.trace_inv ge sp tid
          (m, b, NormalState rs body (app_cont Kend (Kstmt (Swhile cond args body) Kend)))
          l1
          (m', b', NormalState rs' Sskip (app_cont Kend (Kstmt (Swhile cond args body) Kend)))).
      eapply env_trace_inv_incr_cont; eauto.
      simpl in H3.
      rewrite <- Env.trace_inv_eq; auto.
    > eapply env_trace_inv_app; eauto.
      econstructor; [idtac|econstructor;
        [econstructor; [econstructor; eauto|idtac]|idtac|idtac]]; try congruence.
      rewrite Env.trace_inv_eq.
      econstructor; [idtac| econstructor;[econstructor;[econstructor 1|idtac]|idtac|idtac]];
        try congruence.
      assert (Env.trace_inv ge sp tid
        (m, b, NormalState rs body (app_cont Kend (Kstmt (Swhile cond args body) Kend)))
        l1
        (m', b', NormalState rs' Sskip (app_cont Kend (Kstmt (Swhile cond args body) Kend)))). eapply env_trace_inv_incr_cont; eauto.
      simpl in H3.
      rewrite <- Env.trace_inv_eq; auto.
  > destruct st; destruct r;auto.
    > destruct IHbigstep as (st' & S1 & S2); auto.
      inv S2.
      exists (NormalState rs0 (Sabort Interleaved r e) (app_cont k (Kstmt (Swhile cond args body) Kend))).
      split.
      econstructor.
      2: econstructor.
      2: econstructor.
      2: eapply INJECT.exec_while_true; eauto.
      replace (Kstmt (Swhile cond args body) Kend) with
        (app_cont Kend (Kstmt (Swhile cond args body) Kend)) by auto.
      eapply env_trace_inv_incr_cont; eauto.
      congruence.
      congruence.
      congruence.
      constructor.
      rewrite in_atomic_app'; eauto.
    > destruct IHbigstep as (st' & S1 & S2); auto.
      inv S2.
      exists (NormalState rs0 (Sreturn res) (app_cont k (Kstmt (Swhile cond args body) Kend))).
      split.
      econstructor.
      2: econstructor.
      2: econstructor.
      2: eapply INJECT.exec_while_true; eauto.
      replace (Kstmt (Swhile cond args body) Kend) with
        (app_cont Kend (Kstmt (Swhile cond args body) Kend)) by auto.
      eapply env_trace_inv_incr_cont; eauto.
      congruence.
      congruence.
      congruence.
      constructor.
      rewrite in_atomic_app'; auto.
    > eelim H1; eauto.
  > econstructor 3.
    econstructor 1.
    repeat econstructor; eauto; congruence.
  > destruct st; destruct st'; destruct r0.
    > destruct IHbigstep as (st' & S1 & S2); auto.
      econstructor; split; eauto.
      econstructor; [idtac|econstructor; eauto].
      2: econstructor; eauto.
      2: econstructor; eauto; try congruence.
      eapply S1.
      congruence.
      congruence.
      congruence.
    > destruct IHbigstep as (st' & S1 & S2); auto.
      econstructor; split; eauto.
      econstructor; [idtac|econstructor; eauto].
      2: econstructor; eauto.
      2: econstructor; eauto; try congruence.
      eapply S1.
      congruence.
      congruence.
      congruence.
    > econstructor; [idtac|econstructor; eauto]; auto.
      econstructor; eauto.
      econstructor; eauto; try congruence.
      congruence.
      congruence.
      congruence.
  > destruct st; destruct st'; destruct r0.
    > destruct IHbigstep2 as (st' & S1 & S2); auto.
      econstructor; split; eauto.
      econstructor; [idtac|econstructor; eauto].
      eapply env_trace_inv_app with (2:=S1).
      2: econstructor; eauto.
      2: econstructor; eauto; try congruence.
      assert (Env.trace_inv ge sp tid (p, NormalState r stmt1 (app_cont Kend (Kstmt stmt2 Kend))) l1
                 (m', b', NormalState rs' Sskip (app_cont Kend (Kstmt stmt2 Kend)))).
        eapply env_trace_inv_incr_cont; eauto.
      simpl in H2.
      replace l1 with (l1++nil) by auto with datatypes.
      eapply env_trace_inv_app with (1:=H2).
      econstructor; [econstructor 1|econstructor].
      econstructor; eauto.
      econstructor; eauto.
      congruence.
      congruence.
      congruence.
      congruence.
      congruence.
      congruence.
    > destruct IHbigstep2 as (st' & S1 & S2); auto.
      econstructor; split; eauto.
      econstructor; [idtac|econstructor; eauto].
      eapply env_trace_inv_app with (2:=S1).
      2: econstructor; eauto.
      2: econstructor; eauto; try congruence.
      assert (Env.trace_inv ge sp tid (p, NormalState r stmt1 (app_cont Kend (Kstmt stmt2 Kend))) l1
                 (m', b', NormalState rs' Sskip (app_cont Kend (Kstmt stmt2 Kend)))).
        eapply env_trace_inv_incr_cont; eauto.
      simpl in H2.
      replace l1 with (l1++nil) by auto with datatypes.
      eapply env_trace_inv_app with (1:=H2).
      econstructor; [econstructor 1|econstructor].
      econstructor; eauto.
      econstructor; eauto.
      congruence.
      congruence.
      congruence.
      congruence.
      congruence.
      congruence.
    > econstructor; [idtac|econstructor; eauto].
      exploit IHbigstep2; eauto; intros IH2.
      eapply env_trace_inv_app with (2:=IH2).
      2: econstructor; eauto.
      2: econstructor; eauto; try congruence.
      assert (Env.trace_inv ge sp tid (p, NormalState r stmt1 (app_cont Kend (Kstmt stmt2 Kend))) l1
                 (m', b', NormalState rs' Sskip (app_cont Kend (Kstmt stmt2 Kend)))).
        eapply env_trace_inv_incr_cont; eauto.
      simpl in H2.
      replace l1 with (l1++nil) by auto with datatypes.
      eapply env_trace_inv_app with (1:=H2).
      econstructor; [econstructor 1|econstructor].
      econstructor; eauto.
      econstructor; eauto.
      congruence.
      congruence.
      congruence.
      congruence.
      congruence.
      congruence.
  > destruct st; destruct st'; destruct r0.
    > destruct IHbigstep as (st' & S1 & S2); auto.
      inv S2.
      exists (NormalState rs (Sabort Interleaved r0 e) (app_cont k (Kstmt stmt2 Kend))); split; [idtac|econstructor].
      econstructor; eauto.
      2: econstructor; eauto.
      2: econstructor; eauto; try congruence.
      2: econstructor; eauto; try congruence.
      assert (Env.trace_inv ge sp tid (p, NormalState r stmt1 (app_cont Kend (Kstmt stmt2 Kend))) l
                 (p0, NormalState rs (Sabort Interleaved r0 e) (app_cont k (Kstmt stmt2 Kend)))).
        eapply env_trace_inv_incr_cont; eauto.
      simpl in H1.
      eapply H1.
      congruence.
      congruence.
      congruence.
      rewrite in_atomic_app'; eauto.
    > destruct IHbigstep as (st' & S1 & S2); auto.
      inv S2.
      exists (NormalState rs (Sreturn res) (app_cont k (Kstmt stmt2 Kend))); split; [idtac|econstructor].
      econstructor; eauto.
      2: econstructor; eauto.
      2: econstructor; eauto; try congruence.
      2: econstructor; eauto; try congruence.
      assert (Env.trace_inv ge sp tid (p, NormalState r stmt1 (app_cont Kend (Kstmt stmt2 Kend))) l
                 (p0, NormalState rs (Sreturn res) (app_cont k (Kstmt stmt2 Kend)))).
        eapply env_trace_inv_incr_cont; eauto.
      simpl in H1.
      eapply H1.
      congruence.
      congruence.
      congruence.
      apply in_atomic_app'; eauto.
    > eelim H0; eauto.
  > econstructor; split.
    2: repeat (econstructor; eauto).
    econstructor; eauto.
    auto.
  > econstructor; split.
    econstructor; eauto.
    econstructor; eauto.
    econstructor 3; eauto.
    econstructor 1.
    repeat (econstructor; eauto); try congruence.
  > destruct st; destruct st'; destruct r0.
    > destruct IHbigstep as (st' & S1 & S2); auto.
      econstructor; split; eauto.
      econstructor; [idtac|econstructor; eauto].
      2: econstructor; eauto.
      2: econstructor; eauto; try congruence.
      eauto.
      congruence.
      congruence.
      congruence.
    > destruct IHbigstep as (st' & S1 & S2); auto.
      econstructor; split; eauto.
      econstructor; [idtac|econstructor; eauto].
      2: econstructor; eauto.
      2: econstructor; eauto; try congruence.
      eauto.
      congruence.
      congruence.
      congruence.
    > econstructor; [idtac|econstructor; eauto]; auto.
      econstructor; eauto.
      econstructor; eauto; try congruence.
      congruence.
      congruence.
      congruence.
  > destruct st; destruct st'; destruct r0.
    > destruct IHbigstep as (st' & S1 & S2); auto.
      econstructor; split; eauto.
      econstructor; [idtac|econstructor; eauto].
      2: econstructor; eauto.
      2: eapply INJECT.exec_branch_right; eauto; try congruence.
      eauto.
      congruence.
      congruence.
      congruence.
    > destruct IHbigstep as (st' & S1 & S2); auto.
      econstructor; split; eauto.
      econstructor; [idtac|econstructor; eauto].
      2: econstructor; eauto.
      2: eapply INJECT.exec_branch_right; eauto; try congruence.
      eauto.
      congruence.
      congruence.
      congruence.
    > econstructor; [idtac|econstructor; eauto].
      eapply IHbigstep; eauto.
      econstructor 1; eauto.
      econstructor; eauto.
      congruence.
      congruence.
      congruence.
  > repeat (econstructor; eauto); congruence.
  > destruct st; destruct st'; destruct r0.
    > destruct IHbigstep2 as (st' & S1 & S2); auto.
      inv S2.
      exists (NormalState rs0 (Sabort Interleaved r0 e) k).
      split.
      eapply env_trace_inv_app.
      econstructor.
      2: econstructor.
      2: econstructor.
      2: eapply INJECT.exec_loop_again; eauto.
      replace (Kstmt (Sloop s) Kend) with
        (app_cont Kend (Kstmt (Sloop s) Kend)) by auto.
      eapply env_trace_inv_incr_cont; eauto.
      congruence.
      congruence.
      congruence.
      simpl.
      econstructor 3; eauto.
      repeat (econstructor; eauto); congruence.
      econstructor; eauto.
    > destruct IHbigstep2 as (st' & S1 & S2); auto.
      inv S2.
      exists (NormalState rs0 (Sreturn res) k).
      split.
      eapply env_trace_inv_app.
      econstructor.
      2: econstructor.
      2: econstructor.
      2: eapply INJECT.exec_loop_again; eauto.
      replace (Kstmt (Sloop s) Kend) with
        (app_cont Kend (Kstmt (Sloop s) Kend)) by auto.
      eapply env_trace_inv_incr_cont; eauto.
      congruence.
      congruence.
      congruence.
      simpl.
      econstructor 3; eauto.
      repeat (econstructor; eauto); congruence.
      econstructor; eauto.
   > assert (
     Env.trace_inv ge sp tid (m,b , NormalState rs Sskip (app_cont Kend (Kstmt (Sloop s) Kend))) tr2
                 (p0, NormalState r0 Sskip Kend)).
     econstructor; eauto.
     repeat (econstructor; eauto); congruence.
     apply env_trace_inv_app with (2:=H2).
     econstructor; eauto.
      eapply env_trace_inv_incr_cont; eauto.
     repeat (econstructor; eauto); congruence.
  > destruct st; destruct st'; destruct r0.
    > destruct IHbigstep as (st' & S1 & S2); auto.
      inv S2.
      exists (NormalState rs (Sabort Interleaved r0 e) (app_cont k (Kstmt (Sloop s) Kend))).
      split; [idtac|econstructor].
      econstructor.
      2: econstructor.
      2: econstructor.
      2: eapply INJECT.exec_loop_again; eauto.
      replace (Kstmt (Sloop s) Kend) with
        (app_cont Kend (Kstmt (Sloop s) Kend)) by auto.
      eapply env_trace_inv_incr_cont; eauto.
      congruence.
      congruence.
      congruence.
      rewrite in_atomic_app'; auto.
    > destruct IHbigstep as (st' & S1 & S2); auto.
      inv S2.
      exists (NormalState rs (Sreturn res) (app_cont k (Kstmt (Sloop s) Kend))).
      split; [idtac|econstructor].
      econstructor.
      2: econstructor.
      2: econstructor.
      2: eapply INJECT.exec_loop_again; eauto.
      replace (Kstmt (Sloop s) Kend) with
        (app_cont Kend (Kstmt (Sloop s) Kend)) by auto.
      eapply env_trace_inv_incr_cont; eauto.
      congruence.
      congruence.
      congruence.
      rewrite in_atomic_app'; auto.
    > eelim H0; eauto.
Qed.


Definition bigstep_with_small_step ge sp tid m rs stmt tr m' e:=
    exists st, Env.trace ge sp tid (m,NormalState rs stmt Kend) tr st
      /\ Env.intra_step ge sp tid st (TEend e) (m',ReturnState).

Lemma refines_smallstep_def2 : forall stmt1 stmt2,
  refines_smallstep stmt1 stmt2 <->
  (forall ge sp tid m rs tr m' e,
    bigstep_with_small_step ge sp tid m rs stmt1 tr m' e ->
    bigstep_with_small_step ge sp tid m rs stmt2 tr m' e).
Proof.
  unfold refines_smallstep, bigstep_with_small_step; split; intros.
  destruct H0 as (st & T1 & T2).
  exploit H; eauto.
  destruct stf.
  assert (s=ReturnState).
    inv H1; auto.
    inv ST; auto.
  subst.
  eelim H; eauto.
Qed.

Definition end_event_of_rstate (s:rstate) : end_event :=
  match s with
    | SReturn v => ReturnEvent v
    | SAbort => FailEvent
    | SIntra _ => ReturnVoid
  end.

Lemma bigstep_implies_smallstep : forall m rs stmt tr m' s',
  bigstep ge sp tid (m,rs) stmt Interleaved tr (m',s') ->
  bigstep_with_small_step ge sp tid m rs stmt (rev tr) m' (end_event_of_rstate s').
Proof.
  intros.
  inv H.
  exploit bigstep_implies_smallstep_aux; eauto; simpl.
  destruct s'; simpl; intros.
  > destruct H as (st' & S1 & S2).
    exists (m'',b'',st'); split.
    rewrite rev_app.
    eapply ext_trace_env_trace; eauto.
    apply Env.trace_inv_eq2; auto.
    econstructor; try congruence.
  > destruct H as (st' & S1 & S2).
    exists (m'',b'',st'); split.
    rewrite rev_app.
    eapply ext_trace_env_trace; eauto.
    apply Env.trace_inv_eq2; auto.
    econstructor; try congruence.
  > rewrite rev_app.
    econstructor; split.
    eapply ext_trace_env_trace; eauto.
    apply Env.trace_inv_eq2; eauto.
    econstructor; try congruence.
    econstructor; try congruence.
Qed.

Lemma bigstep_left_ext : forall tid ge sp st stmt af tr st',
  Bigstep.bigstep ge sp tid st stmt af tr st' ->
  af = Interleaved ->
  forall m' b' s' tr' m'', st = (m',b',s') ->
    safe tid (snd (fst st')) (fst (fst st')) ->
    ext_trace tid Interleaved m'' tr' (m',b') ->
    bigstep ge sp tid (m'',s') stmt Interleaved (tr'++tr) st'.
Proof.
  induction 1; intros Ha m0' b0' s' tr' (m0'',b0'') T Hs; inv T;
    intros; try congruence; try (rewrite app_nil_r); subst;
     try (replace tr' with (nil++tr') by auto with datatypes;
        econstructor; eauto; econstructor; eauto; econstructor; eauto;
          fail); simpl in Hs;
  try (apply bigstep_simpl; eauto; repeat (econstructor; eauto); fail).
  > exploit IHbigstep; eauto; intros IH.
    inv IH; repeat (econstructor; eauto).
  > exploit IHbigstep; eauto; intros IH.
    inv IH.
    econstructor; eauto.
    vauto.
  > exploit IHbigstep1; eauto; intros IH1; clear IHbigstep1.
    inv IH1.
    exploit IHbigstep2; eauto; intros IH2; clear IHbigstep2.
    inv IH2.
    rewrite <- app_ass.
    rewrite <- H10.
    rewrite app_ass; rewrite <- H12.
    rewrite <- app_ass.
    repeat (econstructor; eauto).
  > exploit IHbigstep; eauto; intros IH; clear IHbigstep.
    inv IH.
    econstructor; eauto.
    eapply Bigstep.exec_while_true_abrupt; eauto.
    red; intros.
    inv H3.
    eelim H1; eauto.
  > replace tr' with (nil++tr') by auto with datatypes.
    econstructor; eauto.
    eapply Bigstep.exec_while_false; eauto.
  > exploit IHbigstep; eauto; clear IHbigstep; intros IH.
    inv IH; econstructor; eauto.
    inv H; econstructor; eauto.
  > exploit IHbigstep1; eauto; intros IH1.
    inv IH1.
    exploit IHbigstep2; eauto; intros IH2.
    inv IH2.
    rewrite <- app_ass.
    rewrite <- H10.
    rewrite app_ass; rewrite <- H12.
    rewrite <- app_ass.
    repeat (econstructor; eauto).
  > exploit IHbigstep; eauto; intros IH.
    inv IH.
    econstructor; eauto.
    eapply Bigstep.exec_seq_abrupt; eauto.
    red; intros.
    inv H3.
    eelim H0; eauto.
  > exploit IHbigstep; eauto; intros IH.
    inv IH.
    econstructor; eauto.
    eapply Bigstep.exec_branch_left; eauto.
  > exploit IHbigstep; eauto; intros IH.
    inv IH.
    econstructor; eauto.
    eapply Bigstep.exec_branch_right; eauto.
  > exploit IHbigstep1; eauto; intros IH1.
    inv IH1.
    exploit IHbigstep2; eauto; intros IH2.
    inv IH2.
    rewrite <- app_ass.
    rewrite <- H10.
    rewrite app_ass; rewrite <- H12.
    rewrite <- app_ass.
    repeat (econstructor; eauto).
  > exploit IHbigstep; eauto; intros IH.
    inv IH.
    econstructor; eauto.
    eapply Bigstep.exec_loop_next_abrupt; eauto.
    red; intros.
    inv H3.
    eelim H0; eauto.
Qed.

Lemma bigstep_left_ext' : forall tid ge sp m' b' s' stmt tr st',
  bigstep ge sp tid (m',b',s') stmt Interleaved tr st' ->
  forall tr' m'',
    ext_trace tid Interleaved m'' tr' (m',b') ->
    bigstep ge sp tid (m'',s') stmt Interleaved (tr'++tr) st'.
Proof.
  intros.
  inv H.
  exploit bigstep_left_ext; eauto.
  intros T; inv T.
  rewrite <- app_ass.
  rewrite <- H2.
  rewrite app_ass.
  econstructor; eauto.
Qed.

Inductive bigstep_with_cont :
  (mem*buffer*rstate) -> continuation -> list (thread_id * ext_event) -> (mem*buffer*rstate) -> Prop :=
  | bigstep_with_cont_abrupt_in_atomic: forall k s m st' tr stmt,
    (forall rs, s <> SIntra rs) ->
    bigstep_with_cont (m,s) k tr st' ->
    bigstep_with_cont (m,s) (Kstmt stmt k) tr st'

  | bigstep_with_cont_end: forall m1 m2 s tr,
    ext_trace tid Interleaved m1 tr m2 ->
    bigstep_with_cont (m1,s) Kend tr (m2,s)

  | bigstep_with_cont_stmt: forall stmt tr tr' st' k tr'' m b rs st'',
    bigstep ge sp tid (m,b,rs) stmt Interleaved tr st' ->
    bigstep_with_cont st' k tr' st'' ->
    tr''= tr++tr' ->
    bigstep_with_cont (m,b,SIntra rs) (Kstmt stmt k) tr'' st''

  | bigstep_with_cont_enda: forall st tr st' f k,
    bigstep_with_cont st k tr st' ->
    bigstep_with_cont st (Kendatomic f k) tr st'
.

Lemma bigstep_with_cont_ext: forall m2s k tr st',
    bigstep_with_cont m2s k tr st' -> forall m1 l,
    let (m2,s) := m2s in
    ext_trace tid Interleaved m1 l m2 ->
    bigstep_with_cont (m1,s) k (l++tr) st'.
Proof.
  induction 1; intros; try destruct st;
  try econstructor (eauto; fail).
  destruct st'; destruct m1.
  clear IHbigstep_with_cont.
  subst; rewrite <- app_ass.
  econstructor 3; eauto.
  eapply bigstep_left_ext'; eauto.
Qed.

Lemma bigstep_with_cont_abrupt_prop: forall st k tr st',
    bigstep_with_cont st k tr st' ->
    let '(m,b,s) := st in
    let (m',s') := st' in
      (forall rs, s <> SIntra rs) ->
      safe tid b m ->
      ext_trace tid Interleaved (m,b) tr m' /\ s'=s.
Proof.
  induction 1.
  destruct st'; intros; auto.
  destruct m1; split; auto.
  destruct st''; intros T; eelim T; eauto.
  destruct st; destruct st'; auto.
Qed.

Lemma bigstep_with_cont_end_prop: forall st k tr st',
    bigstep_with_cont st k tr st' ->
    let '(m,b,s) := st in
    let (m',s') := st' in k = Kend ->
      safe tid b m ->
      ext_trace tid Interleaved (m,b) tr m' /\ s'=s.
Proof.
  induction 1; try congruence.
  destruct m; destruct st'; congruence.
  destruct m1; auto.
  destruct st''; congruence.
  destruct st; destruct p; destruct st'; congruence.
Qed.


Hint Constructors bigstep_with_cont.



Lemma bigstep_with_cont_abort_nil : forall k m b,
  safe tid b m ->
  bigstep_with_cont (m, b, SAbort) k nil (m, b, SAbort).
Proof.
  induction k; constructor; eauto.
  congruence.
Qed.
Hint Resolve bigstep_with_cont_abort_nil.

Lemma bigstep_with_cont_return_nil : forall k m b v,
  safe tid b m ->
  bigstep_with_cont (m, b, SReturn v) k nil (m, b, SReturn v).
Proof.
  induction k; constructor; eauto.
  congruence.
Qed.
Hint Resolve bigstep_with_cont_return_nil.

Lemma atrace_same_in_atomic: forall st1 l st2,
  Env.atrace ge sp tid st1 l st2 ->
  match st1, st2 with
    | (_, NormalState _ _ k1),(_, NormalState _ _ k2) => in_atomic k1 = in_atomic k2
    | _ , _ => True
  end.
Proof.
  induction 1.
  destruct s; destruct s; auto.
  destruct s0; destruct s; auto.
  destruct st; destruct st'; auto.
  rewrite IHatrace.
  inv AT1.
  inv ST; auto; try (eelim IS_not_mem; eauto; fail).
  inv ST; auto.
  inv AT1; auto.
  inv ST; eelim AT5; eauto.
  inv ST; eelim AT5; eauto.
Qed.

Lemma in_atomic_bigstep_with_cont_abrupt: forall cont f k tr m' s' m s,
  in_atomic cont = Some (f, k) ->
  (forall rs, s <> SIntra rs) ->
  bigstep_with_cont (m, s) k tr (m',s') ->
  bigstep_with_cont (m, s) cont tr (m',s').
Proof.
  induction cont; simpl; intros.
  constructor; eauto.
  inv H; eauto.
  congruence.
Qed.


Lemma mem_trace_safe_last: forall t' tid b2 m1 e1 m2,
  mem_trace t' (safe tid b2) m1 e1 m2 -> safe tid b2 m2.
Proof.
  induction 1; auto.
Qed.
Hint Resolve mem_trace_safe_last.


Lemma bigstep_with_cont_stmt2 : forall m b rs stmt st' k tr st'',
 bigstep ge sp tid (m, b, rs) stmt Interleaved nil st' ->
 bigstep_with_cont st' k tr st'' ->
 bigstep_with_cont (m, b, SIntra rs) (Kstmt stmt k) tr st''.
Proof.
  intros.
  rewrite <- (app_nil_l tr).
  econstructor 3; eauto.
Qed.

Lemma bigstep_with_cont_skip : forall m2 rs0 tr0 st' cont tr' m3 s'',
  bigstep ge sp tid (m2, rs0) Sskip Interleaved tr0 st' ->
  bigstep_with_cont st' cont tr' (m3, s'') ->
  bigstep_with_cont (m2, SIntra rs0) cont (tr0 ++ tr') (m3, s'').
Proof.
  intros.
  inv H.
  inv H3.
  simpl.
  exploit bigstep_with_cont_ext; eauto.
Qed.

Lemma upd_buff_eq: forall (buff1 buff2:positive->buffer) tid b1 b2,
  upd buff1 tid b1 = upd buff2 tid b2 -> b1 = b2.
Proof.
  intros.
  rewrite <- (upd_s buff1 tid0 b1).
  rewrite H.
  rewrite upd_s.
  reflexivity.
Qed.

Fixpoint cont2stmt (k:continuation) : statement :=
  match k with
    | Kstmt s k => Sseq s (cont2stmt k)
    | Kendatomic _ _ => Sskip
    | Kend => Sskip
  end.

Inductive end_of_atomic_state (rs:regset) : statement -> rstate -> Prop :=
| end_of_atomic_state_normal : end_of_atomic_state rs Sskip (SIntra rs)
| end_of_atomic_state_return : forall res, end_of_atomic_state rs (Sreturn res) (SReturn (map rs res))
| end_of_atomic_state_abort : forall r e, end_of_atomic_state rs (Sabort Interleaved r e) SAbort.

Lemma smallstep_implies_bigstep_atomic : forall st tr st',
  Env.atrace_inv ge sp tid st tr st' ->
  let (m',s') := st' in
  let '(m,s) := st in
    forall f stf,
    Env.intra_step ge sp tid (m', nil, s') (TEtso (TSOendatomic f)) stf ->
    match s with
      | NormalState rs stmt k =>
        match snd stf with
          | NormalState rs' stmt' _ =>
            exists s'',
            Bigstep.bigstep ge sp tid ((m,nil), rs) (Sseq stmt (cont2stmt k)) Atomic nil (m', nil, s'') /\
            end_of_atomic_state rs' stmt' s''
          | _ => False
        end
      | _ => False
    end.
Proof.
  induction 1.
  > destruct s; intros.
    inv H.
    eelim IS_not_mem; eauto.
    inv ST; simpl.
    > econstructor; split.
      2: econstructor.
      replace (@nil (positive*ext_event)) with (nil++@nil (positive*ext_event)) by auto.
      repeat (econstructor; eauto).
    > econstructor; split; econstructor; try congruence.
      econstructor; eauto; try congruence.
    > econstructor; split; econstructor; try congruence.
      apply Bigstep.exec_abort.
  > destruct s0 as (m0,s0).
    intros f stf He; generalize (IHatrace_inv _ _ He); clear IHatrace_inv.
    destruct st; try (intuition; fail).
    destruct stf as ((m1,b1),s1); simpl.
    destruct s1; try (intuition; fail).
    intros (s'' & S1 & S2).
    assert (Hn:st'<>ReturnState).
      destruct st'; try congruence.
      inv AT1; inv ST.
    destruct st'; try congruence; clear Hn.
    exists s''; split; auto.
    Ltac kill_seq_fail := match goal with
        | H1 :Bigstep.bigstep _ _ _ _ Sskip _ _ ?S,
          H2: forall _ _, ?S <> _ |- _ => inversion H1; subst; eelim H2; eauto
        | H1 :Bigstep.bigstep _ _ _ _ Sskip _ _ _ |- _ => inversion H1; subst; clear H1; eauto
        end.
    inv AT1.
    > inv ST; try (eelim IS_not_mem; eauto; fail);
        simpl.
      > replace (@nil (positive*ext_event)) with (nil++@nil (positive*ext_event)) by auto.
        econstructor; eauto.
        econstructor; eauto.
        unfold safe.
      > inv S1; try kill_seq_fail.
        repeat (econstructor; eauto).
      > inv S1; try kill_seq_fail.
        repeat (econstructor; eauto).
      > inv S1; vauto.
      > inv S1; vauto.
      > inv S1; vauto.
        inv H7; vauto.
        rewrite <- app_ass; vauto.
      > inv S1; try kill_seq_fail.
        vauto.
      > inv S1; vauto.
      > inv S1; vauto.
        inv H6; vauto.
        rewrite <- app_ass; vauto.
      > inv S1; try kill_seq_fail.
        vauto.
      > inv S1; vauto.
      > inv S1; vauto.
      > inv S1; try kill_seq_fail.
        vauto.
      > inv S1; vauto.
        inv H6; vauto.
        rewrite <- app_ass; vauto.
    > inv ST.
      > inv S1; try kill_seq_fail.
        econstructor; eauto.
        assert (m'0=m') by (inv ES; congruence); subst.
        econstructor; eauto.
        simpl; auto.
        exploit AIS1; eauto.
        congruence.
      > inv S1; try kill_seq_fail.
        vauto.
      > inv S1; try kill_seq_fail.
        assert (safe tid nil m').
          econstructor 1; econstructor 2.
        repeat (econstructor; eauto).
      > inv S1; try kill_seq_fail.
        inv ASME; exploit AIS2; eauto.
        intuition.
      > inv S1; try kill_seq_fail.
        econstructor; eauto.
        econstructor; eauto.
      > inv S1; try kill_seq_fail.
        econstructor; eauto.
        assert (m'0=m').
          inv ES; inv ESD; try congruence.
        subst.
        econstructor; eauto.
Qed.


Lemma smallstep_implies_bigstep_aux : forall st tr st',
  Env.trace_inv ge sp tid st tr st' ->
  let (m',s') := st' in
  let '(m,b,s) := st in
    forall e stf,
    Env.intra_step ge sp tid (m', s') (TEend e) stf ->
    safe tid b m ->
    match s with
      | NormalState rs stmt k =>
        in_atomic k = None ->
        exists s'',
          bigstep_with_cont (m,b, SIntra rs) (Kstmt stmt k) tr (m', s'') /\
          e = end_event_of_rstate s''
      | _ => False
    end.
Proof.
  induction 1.
  > destruct s0; destruct p; intros.
    inv H.
    inv ST.
    > econstructor; repeat split; eauto.
      econstructor 3; eauto.
      apply bigstep_simpl; auto.
      econstructor.
      auto.
      auto.
    > exists SAbort; split; auto.
      replace (@nil (positive*ext_event)) with (nil++@nil (positive*ext_event)) by auto.
      econstructor 3; eauto.
      replace (@nil (positive*ext_event)) with (nil++@nil (positive*ext_event)) by auto.
      econstructor; eauto.
      econstructor; eauto.
    > econstructor; repeat split; eauto.
      econstructor 3.
      econstructor; eauto.
      econstructor.
      econstructor.
      econstructor 1; auto.
      auto.
      auto.
  > destruct s1 as ((m1 & b1) & s1).
    destruct s2 as ((m2 & b2) & s2).
    destruct s3 as ((m3 & b3) & s3).
    intros e0 stf He.
    generalize (IHtrace_inv _ _ He); clear IHtrace_inv; intros HI.
    inv HT2.
    assert (Hs2:safe tid b2 m2) by eauto.
    destruct s2; try (intuition; fail).
    intros Hs1 Ha.
    destruct HI as (s'' & S1 & S2); subst; auto.
    econstructor;
      repeat split; eauto.
    inv S1.
    eelim H6; eauto.
    assert (E:ext_trace tid Interleaved (m1,b2) ((t',e1):::nil) (m2,b2)).
      econstructor; eauto.
    exploit bigstep_left_ext'; eauto.
    intros Hb; clear E ES H7.
    econstructor 3; eauto.
    rewrite (cons'_app _ _ (t',e1)); auto.
    rewrite (cons'_app _ _ (t',e1)); auto.
  > destruct s1 as ((m1 & b1) & s1).
    destruct s2 as ((m2 & b2) & s2).
    destruct s3 as ((m3 & b3) & s3).
    intros e0 stf He.
    generalize (IHtrace_inv _ _ He); clear IHtrace_inv; intros HI.
    intros Hs.
    assert (Hs2:safe tid b2 m2) by auto.
    destruct s2; try (elim HI; auto; fail).
    assert (s1<>ReturnState).
      inv HT2.
      > inv ST; try congruence.
        > inv ST0; try congruence.
        > inv ST0; try congruence.
      > inv ST1; try congruence.
        inv ST; try congruence.
    destruct s1; try (elim H0; reflexivity; fail); clear H0.
    intros Ha.
    destruct HI as (s'' & S1 & S2 ); auto; subst; clear H.
    > inv HT2.
      > inv ST; try congruence.
        > inv ST0; simpl in Ha; auto; congruence.
        > inv ST0; simpl in Ha; auto; congruence.
      > inv ST1.
        eelim IS_not_mem; eauto.
        inv ST.
        inv ST2.
        eelim IS_not_mem; eauto.
        exploit atrace_same_in_atomic; eauto.
        inv ST; simpl; congruence.
    inv S1.
    eelim H5; eauto.
    inv HT2.
    > inv ST.
      > inv ST0; try (eelim IS_not_mem; eauto; fail); exists s''; split; auto;
        try (eapply bigstep_with_cont_stmt2;
               [apply bigstep_simpl; [econstructor; eauto|auto|auto]; fail
               |try(econstructor 3; eauto; fail);
                try(eapply bigstep_with_cont_skip; eauto; fail)]; fail).
        > econstructor 3; eauto.
          inv H6; econstructor; eauto.
          econstructor; eauto.
        > econstructor 3; eauto.
          inv H6; econstructor; eauto.
          vauto.
        > inv H7.
          > destruct s; try (eelim H2; eauto; fail).
            > econstructor 3; eauto.
              inv H6; econstructor; eauto.
              eapply Bigstep.exec_while_true_abrupt; eauto; congruence.
            > econstructor 3; eauto.
              inv H6; econstructor; eauto.
              eapply Bigstep.exec_while_true_abrupt; eauto; congruence.
          > rewrite <- app_ass; econstructor 3; eauto.
            inv H6.
            exploit bigstep_left_ext'; eauto; clear H13 H1; intros Hg.
            inv Hg.
            rewrite app_ass; rewrite <- H7.
            rewrite <- app_ass; econstructor; eauto.
            vauto.
        > econstructor 3; eauto.
          inv H6; econstructor; eauto.
          inv H9; vauto.
        > econstructor 3; eauto.
          inv H6; econstructor; eauto.
          vauto.
        > inv H7.
          econstructor 3; eauto.
          inv H6; econstructor; eauto.
          eapply Bigstep.exec_seq_abrupt; eauto; congruence.
        > rewrite <- app_ass; econstructor 3; eauto.
          inv H6.
          exploit bigstep_left_ext'; eauto; clear H1 H12; intros Hg.
          inv Hg.
          rewrite app_ass; rewrite <- H6.
          rewrite <- app_ass; econstructor; eauto.
          eapply Bigstep.exec_seq; eauto.
        > econstructor 3; eauto.
          inv H6; econstructor; eauto.
          vauto.
        > econstructor 3; eauto.
          inv H6; econstructor; eauto.
          vauto.
        > inv H7.
          > destruct s; try (eelim H2; eauto; fail).
            > econstructor 3; eauto.
              inv H6; econstructor; eauto.
              eapply Bigstep.exec_loop_next_abrupt; eauto; congruence.
            > econstructor 3; eauto.
              inv H6; econstructor; eauto.
              eapply Bigstep.exec_loop_next_abrupt; eauto; congruence.
          > rewrite <- app_ass; econstructor 3; eauto.
            inv H6.
            exploit bigstep_left_ext'; eauto; clear H12 H1; intros Hg.
            inv Hg.
            rewrite app_ass; rewrite <- H6.
            rewrite <- app_ass; econstructor; eauto.
            vauto.
      > inv ST0; exists s''; split; auto.
        > inv ES.
          apply upd_buff_eq in H4; subst.
          econstructor 3; eauto.
        > inv H6; econstructor 3; eauto.
          inv H8.
          inv ES.
          apply upd_buff_eq in H8; subst.
          clear ST1 ST2 Hs2.
          econstructor; eauto.
          rewrite upd_s in TM2.
          econstructor; eauto.
          simpl; auto.
          destruct (addr_in_buf a b'); auto.
          rewrite upd_s in TM4; assumption.
        > inv H6; econstructor 3; eauto.
          inv H9.
          econstructor; eauto.
          inv ES.
          apply upd_buff_eq in H9; subst.
          econstructor; eauto. destruct (rs src); vauto; inv HTv.
          rewrite upd_s; auto.
        > inv H6; econstructor 3; eauto.
          inv H9.
          inv ES; econstructor; eauto.
          apply upd_buff_eq in H5; subst.
          econstructor; eauto.
        > inv H6; econstructor 3; eauto.
          econstructor; eauto.
          inv H8.
          inv ASME; inv ES.
          apply upd_buff_eq in H10; subst.
          rewrite upd_s in TM1; subst.
          econstructor; eauto.
          rewrite <- H1.
          econstructor; eauto.
        > inv H6; econstructor 3; eauto.
          inv H8.
          inv ES; econstructor; eauto.
          apply upd_buff_eq in H2; subst.
          unfold Env.cast in *; simpl in *.
          rewrite upd_s in BEMP; subst.
          econstructor; eauto.
        > inv H6; econstructor 3; eauto.
          inv H8.
          inv ES; econstructor; eauto.
          apply upd_buff_eq in H2; subst.
          simpl in BEMP; rewrite upd_s in BEMP; subst.
          exploit ext_trace_keep_empty_buffer; eauto.
          simpl; intros; subst.
          econstructor; eauto.
        > inv ES.
          apply upd_buff_eq in H5; subst.
          econstructor 3; eauto.
          destruct st'; eapply in_atomic_bigstep_with_cont_abrupt; eauto.
          inv H6.
          inv H8; try congruence.
        > congruence.
        > intuition.
        > econstructor 3; eauto.
          inv H6; inv ES.
          apply upd_buff_eq in H4; subst.
          econstructor; eauto.
          inv H8; econstructor; eauto.
        > econstructor 3; eauto.
          inv H6; inv ES.
          apply upd_buff_eq in H4; subst.
          inv H8; econstructor; eauto.
          econstructor; eauto.
          inv TM1; inv ESD; eauto.
          generalize TM1; intros.
          inv TM1; inv ESD; eauto.
    > exists s''; split; auto.
      econstructor 3; eauto.
      inv ES.
      apply upd_buff_eq in H4; subst.
      rewrite upd_s in TM3; subst.
      rewrite <- (app_nil_l tr0).
      eapply bigstep_left_ext'; eauto.
      econstructor 3.
      2: econstructor 1; auto.
      econstructor; eauto.
    > inv ST1.
      eelim IS_not_mem; eauto.
      inv ES.
      apply upd_buff_eq in H3; subst.
      inv ST.
      exists s''; split; auto.
      assert (s0<>ReturnState).
        destruct s0; try congruence.
        inv ST2; inv ST.
      destruct s0; try congruence.
      assert (cont = cont0).
        exploit atrace_same_in_atomic; eauto; simpl; intros.
        inv ST2; try (eelim IS_not_mem; eauto).
        inv ST; try congruence.
        inv H0; reflexivity.
      subst.
      generalize ST2; intros ST3.
      inv ST2.
      eelim IS_not_mem; eauto.
      inv ES.
      apply upd_buff_eq in H8; subst.

      inv ST.
      > inv H6.
        econstructor 3; eauto.
        inv H10; econstructor; eauto.
        econstructor; eauto.
        apply env_atrace_inv_eq2 in ST0.
        exploit smallstep_implies_bigstep_atomic; eauto.
        simpl.
        intros T; destruct (T _ _ ST3) as (s0 & S1 & S2); clear T; inv S2.
        inv S1.
        inv H8; rewrite app_nil_r; auto.
        eelim H9; eauto.
      > inv H6.
        econstructor 3; eauto.
        inv H11; econstructor; eauto.
        econstructor; eauto.
        apply env_atrace_inv_eq2 in ST0.
        exploit smallstep_implies_bigstep_atomic; eauto.
        simpl.
        intros T; destruct (T _ _ ST3) as (s0 & S1 & S2); clear T; inv S2.
        inv S1.
        inv H9.
        auto.
      > inv H6.
        econstructor 3; eauto.
        inv H11; econstructor; eauto.
        econstructor; eauto.
        apply env_atrace_inv_eq2 in ST0.
        exploit smallstep_implies_bigstep_atomic; eauto.
        simpl.
        intros T; destruct (T _ _ ST3) as (s0 & S1 & S2); clear T; inv S2.
        inv S1.
        inv H9.
        auto.
Qed.


Lemma smallstep_implies_bigstep : forall m b rs stmt tr m' e,
  bigstep_with_small_step ge sp tid (m,b) rs stmt (rev tr) m' e ->
  safe tid b m ->
  exists s', e = end_event_of_rstate s' /\
    bigstep ge sp tid (m,b,rs) stmt Interleaved tr (m',s').
Proof.
  intros.
  destruct H as (st & S1 & S2).
  apply Env.trace_inv_eq1 in S1.
  rewrite rev_involutive in S1.
  exploit smallstep_implies_bigstep_aux; eauto.
  destruct st; simpl; intros.
  edestruct H as (s'' & T1 & T2); eauto; clear H.
  exists s''; split; auto.
  inv T1.
  > eelim H6; eauto.
  > inv H8.
    assert (p=m') by (inv S2; auto); subst.
    destruct m'; inv H7.
    rewrite app_ass; econstructor; eauto.
Qed.

End equiv_big_small.

Lemma refines_implies_refines_smallstep: forall stmt1 stmt2,
  refines stmt1 stmt2 ->
  refines_smallstep stmt1 stmt2.
Proof.
  unfold refines, refines_smallstep; intros.
  destruct m as (m,b).
  destruct stf as (m',s').
  assert (s'=ReturnState).
    inv H1.
    inv ST; auto.
  subst.
  assert (bigstep_with_small_step ge sp t (m,b) rs stmt1 tr m' e).
    econstructor; split; eauto.
  clear H0 H1.
  rewrite <- (rev_involutive tr) in H2.
  apply smallstep_implies_bigstep in H2.
  destruct H2 as (s'' & S1 & S2); subst.
  apply H in S2.
  exploit bigstep_implies_smallstep; eauto.
  rewrite rev_involutive.
  intros (st' & S1 & S3).
  econstructor; split; eauto.
  auto.
Qed.

Section WEAKEN.
  Context {P Q: statementstatementProp}.
  Hypothesis W: ∀ s1 s2, P s1 s2Q s1 s2.

  Lemma wf_c_weak c : wf_c P cwf_c Q c.
Proof.
intros H tid body args dst succ H0. eauto. Qed.

  Lemma wf_stack_weak stk : wf_stack P stkwf_stack Q stk.
Proof.
intros H K. pose proof (H K). auto using wf_c_weak. Qed.

  Lemma wf_intra_state_weak s : wf_intra_state P swf_intra_state Q s.
Proof.
    Hint Resolve wf_c_weak wf_stack_weak.
    induction 1; econstructor; eauto.
  Qed.

  Lemma wf_istate_weak s : wf_istate P swf_istate Q s.
Proof.
destruct s. intros H a b c. exact (wf_intra_state_weak _ (H a b c)). Qed.

  Lemma ge_correct_wrt_weak ge : ge_correct_wrt_refines P gege_correct_wrt_refines Q ge.
Proof.
unfold ge_correct_wrt_refines. eauto. Qed.

End WEAKEN.


Lemma refines_implies_backwardsim_smallstep:
    ∀ ge st1 tr st2,
      ge_correct_wrt_refines refines_smallstep ge
      wf_istate refines_smallstep st1 ->
      low_trace ge st1 tr st2 ->
      (∀ tid s, (snd st2)!tid = Some s -> inject_state s = false) ->
      ∃ tr',
        high_trace ge st1 tr' st2filter_fullevent tr' = filter_fullevent tr.
Proof.
  intros ge st1 tr st2 H H1 H2.
  destruct st1; destruct st2.
  eapply (refines_implies_backwardsim' ge ); eauto.
  intros.
  eapply simulation1.refines_implies_trace_transformation1; eauto.
Qed.

Theorem refines_implies_backwardsim:
    ∀ ge st1 tr st2,
      ge_correct_wrt_refines refines ge
      wf_istate refines st1 ->
      low_trace ge st1 tr st2 ->
      (∀ tid s, (snd st2)!tid = Some s -> inject_state s = false) ->
      ∃ tr',
        high_trace ge st1 tr' st2filter_fullevent tr' = filter_fullevent tr.
Proof.
  intros ge st1 tr st2 H' K' H2.
  pose proof (ge_correct_wrt_weak refines_implies_refines_smallstep ge H') as H; clear H'.
  pose proof (wf_istate_weak refines_implies_refines_smallstep _ K') as K; clear K'.
  auto using refines_implies_backwardsim_smallstep.
Qed.