Module RefinesRules2

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 Classical.
Require Import Utils.
Require Import Emem Permissions MemoryMachine TSOMemoryMachine RefinesDefs RefinesUtils.
Require Import RefinesRules AllRefinesRulesAux.

Import Bigstep.

Lemma atomic_empty' : forall stmt ge sp tid st st' l af,
  bigstep ge sp tid st stmt af l st' ->
  af = Atomic
  snd (fst st) = empty_buffer
  snd (fst st') = empty_buffer.
Proof.
  induction 1; simpl; trivial; repeat intros ->;
  (try now inv H); simpl in *;
  intros; apply IHbigstep2; trivial; apply IHbigstep1; trivial.
Qed.
Corollary atomic_empty : forall stmt ge sp tid m m' b rs rs' l,
  bigstep ge sp tid (m, empty_buffer, rs) stmt Atomic l (m', b, rs') ->
  b = empty_buffer.
Proof.
intros. exploit atomic_empty'; eauto. Qed.


  Definition release_before_load t' d' a s : perm_map :=
    fun x =>
      if Ptr.eq_dec x a then
        match d' a with
          | FrozenBy q => FrozenBy (if Rset.mem t' s then q else Rset.remove t' q)
          | HiddenBy _ => empty_perm
        end
      else d' x.
  Lemma release_case {t t' d a d' s} :
    t <> t' ->
    d a = FrozenBy s ->
    release t (upd_perm d a (FrozenBy (Rset.add t' s))) d' ->
    release t d (release_before_load t' d' a s).
Proof.
    intros TID Hda ESP.
    unfold release in ESP.
      intros p. unfold release_before_load.
      generalize (ESP p). unfold upd_perm.
      destruct (Ptr.eq_dec p a). 2: now trivial.
        subst. intros K; inv K. rewrite Hda.
        rewrite Rset.remove_comm.
        case_eq (Rset.mem t' s); intros Hm.
          rewrite Rset.mem_add_nop. vauto. auto.
        rewrite Rset.remove_add. vauto. intros c; autorw'.
  Qed.

    Lemma release_case' {t t' d a d' s} :
    t <> t' ->
    d a = FrozenBy s ->
    release t (upd_perm d a (FrozenBy (Rset.add t' s))) d' ->
      upd_read_perm_set (release_before_load t' d' a s) a t' d'.
Proof.
      unfold release, release_before_load.
      intros TID Hda ESP.
      generalize (ESP a). unfold upd_perm.
      case_eq (Ptr.eq_dec a a); intros ? K. 2: congruence.
      case_eq (d' a). intros ? ? Q. inv Q.
      intros s' Hs' Q. inv Q.
      econstructor; eauto. autorw'.
    apply extensionality.
    intros x.
    unfold upd_perm. case_eq (Ptr.eq_dec x a). 2: intros; autorw'; trivial.
    intros. autorw'. f_equal.
    case_eq (Rset.mem t' s); intros Hm.
      rewrite Rset.mem_add_nop. 2: assumption.
      symmetry.
      apply Rset.mem_add_nop.
      rewrite Rset.mem_rmo; auto.
    rewrite Rset.add_remove.
    assert (L: Rset.mem t' (Rset.remove t (Rset.add t' s))).
    2: rewrite (Rset.mem_add_nop L); reflexivity.
    rewrite Rset.mem_rmo.
    apply Rset.add_mem.
    congruence.
    Qed.

Lemma pfrup t d r a s t' :
  d a = FrozenBy s ->
  range_has_store_perm t (upd_perm d a (FrozenBy (Rset.add t' s))) r ->
  range_has_store_perm t d r.
Proof.
  intros Ha (HR & ESF).
  split. exact HR.
  intros p' Hp'; generalize (ESF p' Hp').
  unfold has_store_perm.
  unfold upd_perm. destruct (Ptr.eq_dec p' a); trivial. autorw'.
  intros H. destruct (Rset.subset_singleton _ _ H). eelim (Rset.add_not_empty); eassumption.
  destruct (Rset.add_singleton H0). autorw'.
Qed.

Ltac ptr :=
  match goal with
    | [H : context [Ptr.eq_dec ?a ?b ] |- _ ] => destruct (Ptr.eq_dec a b);[subst|]
    | [|- context [Ptr.eq_dec ?a ?b ] ] => destruct (Ptr.eq_dec a b);[subst|]
  end.

Lemma localread_leftmover_mem_step: forall t m2 e m3,
  mem_step t m2 e m3 ->
  forall t' a v inbuf,
    t <> t' ->
    mem_step t' m2 (MEread Local inbuf a v) m2 ->
    mem_step t' m3 (MEread Local inbuf a v) m3.
Proof.
  intros t m2 e m3 ESTEP t' a v inbuf TID TSTEP.
  inv TSTEP.
  inv ESTEP.
  econstructor; eauto.
  inv ESD; trivial.
  > unfold has_store_perm in *.
    inv ESP.
    case (eq_dec a p). intros ->. autorw'. apply False_ind.
    destruct (Rset.subset_singleton _ _ ESD0); subst. eelim (Rset.empty_not_mem); eassumption.
    elim TID. symmetry. eapply Rset.mem_singleton. eassumption.
    intros. econstructor. rewrite perm_gso; eauto.
    eassumption.
  > inv ESD0.
    destruct (Ptr.eq_dec a p).
    > econstructor 1 with (Rset.add t s); eauto.
      unfold upd_perm; destruct Ptr.eq_dec; intuition.
      inv ESP; try congruence.
      assert (s=s0) by congruence; subst.
      rewrite Rset.add_mem_o; auto.
    > inv ESP.
      > econstructor 1; eauto.
        unfold upd_perm; destruct Ptr.eq_dec; intuition.
  > inv ESP.
    > econstructor 1 with (Rset.remove t s); eauto.
      generalize (ESP0 a); intros.
      inv H; try congruence.
      rewrite Rset.mem_rmo; auto.
  destruct (Ptr.eq_dec p a).
  > subst; inv ESP; congruence.
  > vauto.
    econstructor eauto. erewrite load_store_old; eauto.
    destruct released; try congruence.
    generalize (ESP0 a); intros T; inv T; inv ESP; try congruence.
    constructor 1 with (Rset.remove t s); auto.
    replace s0 with s in * by congruence.
    rewrite Rset.mem_rmo; auto.
  constructor; auto.
  assert (p <> a).
    intros contra; subst.
    destruct released; subst.
    > inv ESP; generalize (ESP0 a); intros T; inv T; try congruence.
      inv ESD. autorw'.
      exploit (@Rset.mem_rmo s t' t); auto. intros K. autorw'.
      case (Rset.subset_singleton _ _ ALONE); intros H; rewrite H in K.
      apply (Rset.empty_not_mem K).
      elim TID. symmetry. apply @Rset.mem_singleton. assumption.
    > inv ESP; try congruence.
      inv ESD. autorw'.
      case (Rset.subset_singleton _ _ ALONE); intros ->. apply (Rset.empty_not_mem RP2).
      elim TID. symmetry. apply @Rset.mem_singleton. assumption.
  constructor; auto.
  erewrite <- load_store_old in ESL; try eassumption.
  destruct released; subst; auto.
  inv ESP; generalize (ESP0 a); intros T; inv T; try congruence.
  replace s0 with s in * by congruence.
  constructor 1 with (Rset.remove t s); auto.
  rewrite Rset.mem_rmo; auto.
  constructor; auto.
  assert (p <> a).
    intros contra; subst.
    inv ESP; (destruct r; [generalize (ESP0 a); intros T; inv T|subst]);
    unfold empty_perm in *; try congruence.
    > assert (s0=s) by congruence; subst.
      assert (Rset.remove t s = Rset.empty) by congruence.
      assert (Rset.mem t' (Rset.remove t s)=true).
        rewrite Rset.mem_rmo; auto.
      rewrite H1 in *; rewrite mem_empty in *; congruence.
    > assert (s = Rset.empty) by congruence; subst.
      rewrite mem_empty in *; congruence.
  constructor; auto.
  > rewrite (load_store_old m p (rmw_instr_semantics instr v0)); auto.
    apply wf_rmw_instr_sem; auto.
  > destruct r; subst; auto.
    generalize (ESP0 a); intros.
    inv H0; inv ESP; try congruence.
    > constructor 1 with (Rset.remove t s); auto.
      rewrite Rset.mem_rmo; auto.
      congruence.
  econstructor eauto.
  inv ESP.
  erewrite load_alloc_other; try eassumption.
  eapply not_free_ranges_disjoint; try eassumption. autorw'.
  intros K. destruct (Rset.subset_singleton _ _ K); subst. elim (Rset.empty_not_mem RP2).
  elim TID. symmetry. eapply Rset.mem_singleton. eassumption.
  econstructor eauto.
  inv ESP.
  erewrite load_free_other; try eassumption.
  eapply not_free_ranges_disjoint; try eassumption. autorw'.
  intros K. destruct (Rset.subset_singleton _ _ K); subst. elim (Rset.empty_not_mem RP2).
  elim TID. symmetry. eapply Rset.mem_singleton. eassumption.
Qed.

  Lemma pfruh t d r a t' :
    d a = empty_perm \/ d a = HiddenBy t' ->
    range_has_store_perm t (upd_perm d a (HiddenBy t')) r ->
    range_has_store_perm t d r.
Proof.
  intros Ha [HR ESF].
  split. exact HR.
  intros p' Hp'; generalize (ESF p' Hp').
  unfold has_store_perm.
  unfold upd_perm. ptr; trivial. intros ->. destruct Ha as [-> | ->]; trivial. simpl. auto.
Qed.

Lemma localstore_leftmover_mem_step: forall t m2 e m3,
  mem_step t m2 e m3 ->
  forall t' m1 a v,
    t <> t' ->
    mem_step t' m1 (MEwrite false Local a v) m2 ->
    exists m',
      mem_step t m1 e m' /\ mem_step t' m' (MEwrite false Local a v) m3.
Proof.
  intros t m2 e m3 ESTEP t' m1 a v TID TSTEP.
  inv TSTEP.
  inv ESTEP.
  exists {| mem_rtl := m; perms := d'0 |}; split; constructor; auto.
  inv ESD0; trivial.
  > unfold has_store_perm in *.
    case (eq_dec a p). intros ->. autorw'.
    intros NE. rewrite perm_gso; trivial.
  > inv ESD1; unfold upd_perm; destruct Ptr.eq_dec; subst; auto; congruence.
  > generalize (ESP a); intros T; inv T; congruence.
  assert (a<>p) by congruence.
  assert (store_ptr Mint32 m p v0 <> None).
    eapply store_store_ex with (5:=ESS) (6:=ESS0); eauto.
  case_eq (store_ptr Mint32 m p v0); try congruence.
  clear H0; intros m2 Hm2.
  eelim store_comm with (6:=ESS) (7:=ESS0); eauto.
  intros m3 (Hm3 & Hm4).
  exists (MEM m2 d'0); split; constructor; auto.
  exploit emem_is_eq; eauto.
  congruence.
  destruct released; subst; auto.
  generalize (ESP a); intros T; inv T; try congruence.
  apply mem_eq_refl.
  assert (a<>p).
    inv ESP; congruence.
  exists (MEM m d'); split; constructor; auto.
  assert (load_ptr Mint32 m' p = load_ptr Mint32 m p).
    eapply load_store_old with (p:=a) (v:=v); eauto.
  congruence.
  assert (a<>p). intros ->.
    inv ESD0.
    destruct released.
    generalize (ESP p); intros T; inv T; try congruence.
    congruence.
  assert (store_ptr Mint32 m p v0 <> None).
    eapply store_store_ex with (5:=ESS) (6:=ESS0); eauto.
  case_eq (store_ptr Mint32 m p v0); try congruence.
  clear H0; intros m2 Hm2.
  eelim store_comm with (6:=ESS) (7:=ESS0); eauto.
  intros m3 (Hm3 & Hm4).
  exists (MEM m2 d'0); split; constructor; auto.
  inv ESD0. vauto.
  exploit emem_is_eq; eauto.
  congruence.
  destruct released; subst; auto.
  generalize (ESP a); intros T; inv T; try congruence.
  apply mem_eq_refl.
  assert (a<>p) by (intro; subst; exploit ESD0; eauto; congruence).
  exists (MEM m d'); split; constructor; auto.
  assert (load_ptr Mint32 m' p = load_ptr Mint32 m p).
    eapply load_store_old with (p:=a) (v:=v); eauto.
  congruence.
  assert (a<>p).
    intro; subst.
    unfold empty_perm in *.
    destruct r; try congruence.
    generalize (ESP p); intros T; inv T; congruence.
  assert (store_ptr Mint32 m p (rmw_instr_semantics instr v0) <> None).
    eapply store_store_ex with (5:=ESS) (6:=STO); eauto.
    apply wf_rmw_instr_sem; auto.
  case_eq (store_ptr Mint32 m p (rmw_instr_semantics instr v0)); try congruence.
  clear H0; intros m2 Hm2.
  eelim store_comm with (6:=ESS) (7:=STO); eauto.
  intros m3 (Hm3 & Hm4).
  exists (MEM m2 d'0); split; constructor; auto.
  > assert (load_ptr Mint32 m' p = load_ptr Mint32 m p).
      eapply load_store_old with (p:=a) (v:=v); eauto.
    congruence.
  > exploit emem_is_eq; eauto.
    congruence.
  > destruct r; subst; auto.
    generalize (ESP a); intro T; inv T; congruence.
  > apply wf_rmw_instr_sem; auto.
  > apply mem_eq_refl.
  destruct store_alloc with (4:=ESS) (5:=ESL) (x:= m) (6:= mem_eq_refl m) as ((q & Hq) & A); auto.
    exact (proj1 ESF).
  destruct (A _ Hq) as (n & Hn & EQ); clear A.
  exists (MEM q d'); split; constructor eauto.
  exploit emem_is_eq; eauto.
  congruence.
  edestruct store_free with (4:=ESS) (5:=ESA) (7:=ESL) as ((q & Hq) & A); auto.
    exact (proj1 ESWF). eapply not_free_ranges_disjoint; eauto. autorw'.
    eapply mem_eq_refl.
  destruct (A _ Hq) as (n' & Hn & EQ); clear A.
  exists (MEM q d'); split; econstructor eauto.
  eapply store_preserves_allocated_ranges; eassumption.
  exploit emem_is_eq; eauto.
  congruence.
Qed.

Inductive trace_mem_inv t P (m:mem) : list mem_event -> mem -> Prop :=
 | trace_mem_inv_nil: forall (TM: P m), trace_mem_inv t P m nil m
 | trace_mem_inv_cons: forall l m' e m''
   (TM1: trace_mem_inv t P m' l m'')
   (TM2: mem_step t m e m')
   (TM3: P m),
   trace_mem_inv t P m (e::l) m''.

Lemma trace_mem_inv_eq1_1 : forall t P s1 tr s2,
  trace_mem_inv t P s1 tr s2 -> forall e s3,
  P s3 ->
  mem_step t s2 e s3 -> trace_mem_inv t P s1 (tr++ (e::nil)) s3.
Proof.
  induction 1; simpl; intros.
  assert (trace_mem_inv t P m (e :: nil) s3).
    econstructor; eauto.
    econstructor; auto.
  auto.
  exploit IHtrace_mem_inv; eauto; intros.
  econstructor; eauto.
Qed.

Lemma trace_mem_inv_eq1 : forall t b s1 tr s2,
  mem_trace t b s1 tr s2 -> trace_mem_inv t b s1 (rev tr) s2.
Proof.
  induction 1; simpl.
  econstructor; auto.
  exploit trace_mem_inv_eq1_1; eauto.
Qed.

Lemma trace_mem_inv_eq2_1 : forall t P s1 tr s2,
  mem_trace t P s1 tr s2 -> forall e s0,
  P s0 ->
  mem_step t s0 e s1 -> mem_trace t P s0 (tr++ (e::nil)) s2.
Proof.
  induction 1; simpl; intros.
  econstructor; eauto.
  econstructor; auto.
  exploit IHmem_trace; eauto; intros.
  econstructor; eauto.
Qed.

Lemma trace_mem_inv_safe_snd: forall t t' b s1 tr s2,
  trace_mem_inv t' (safe t b) s1 tr s2 -> safe t b s2.
Proof.
  induction 1; auto.
Qed.
Hint Resolve trace_mem_inv_safe_snd.

Lemma trace_mem_inv_safe_fst: forall t t' b s1 tr s2,
  trace_mem_inv t' (safe t b) s1 tr s2 -> safe t b s1.
Proof.
  induction 1; auto.
Qed.
Hint Resolve trace_mem_inv_safe_fst.

Lemma trace_mem_inv_eq2 : forall t b s1 tr s2,
  trace_mem_inv t b s1 tr s2 -> mem_trace t b s1 (rev tr) s2.
Proof.
  induction 1; simpl.
  econstructor; auto.
  eapply trace_mem_inv_eq2_1; eauto.
Qed.

Lemma localread_leftmover_trace_mem: forall t t' b m2 l m3,
  trace_mem_inv t' b m2 l m3 ->
  forall a v inbuf, t<>t' ->
    mem_step t m2 (MEread Local inbuf a v) m2 ->
    mem_step t m3 (MEread Local inbuf a v) m3.
Proof.
  induction 1; intros.
  auto.
  exploit (localread_leftmover_mem_step _ _ _ _ TM2); eauto.
Qed.

Lemma localwrite_leftmover_mem_trace: forall t b t' m2 l m3,
  trace_mem_inv t' (safe t b) m2 l m3 ->
  forall m1 a v , t<>t' ->
    safe t b m1 ->
    mem_step t m1 (MEwrite false Local a v) m2 ->
    exists m',
      trace_mem_inv t' (safe t b) m1 l m' /\ mem_step t m' (MEwrite false Local a v) m3.
Proof.
  induction 1; intros.
  econstructor; split; [econstructor; auto|auto].
  edestruct (localstore_leftmover_mem_step _ _ _ _ TM2) as (m0 & M1 & M2); eauto.
  clear H2.
  assert (safe t b m0).
    exploit trace_mem_inv_safe_fst; eauto; intros.
  clear H.
  edestruct IHtrace_mem_inv as (m4 & M3 & M4); eauto.
  econstructor; split; eauto.
  econstructor; eauto.
Qed.

Lemma perm_step_readable_perm: forall t d1 d2 p t' e,
      readable_perm d1 p t ->
      perm_step t' d1 e d2 ->
      t <> t' ->
      readable_perm d2 p t.
Proof.
  intros t d1 d2 p t' e H H0 H1.
  inv H0; auto.
  > unfold has_store_perm in ESD.
    inv H.
    case (eq_dec p p0). intros ->. autorw'.
      destruct (Rset.subset_singleton _ _ ESD); subst. elim (Rset.empty_not_mem RP2).
      elim H1. eapply Rset.mem_singleton. eassumption.
    intros NE. econstructor. rewrite perm_gso; eauto. easy.
      > destruct (Ptr.eq_dec p0 p); subst.
        > inv H; inv ESD.
          constructor 1 with (Rset.add t' s0).
          rewrite perm_gss; auto.
          rewrite Rset.add_mem_o; auto.
          congruence.
      > inv ESD.
        destruct (Ptr.eq_dec p0 p); subst.
        > inv H; try congruence.
        > inv H.
          > constructor 1 with s0; auto.
            rewrite perm_gso; auto.
   > generalize (ESP p); intros T; inv T; inv H; try congruence.
     > assert (s0=s) by congruence; subst.
       constructor 1 with (Rset.remove t' s); auto.
       rewrite Rset.mem_rmo; auto.
Qed.


Lemma unbuffer_n_readable_perm: forall t N m1 b1 b1' m1_flushed d1,
  unbuffer_n t (m1,b1) N (MEM m1_flushed d1, b1') ->
  forall p t' e m2,
      readable_perm d1 p t ->
      mem_step t' m1 e m2 ->
      t <> t' ->
      forall m2_flushed d2,
          unbuffer_n t (m2,b1) N (MEM m2_flushed d2, b1') ->
          readable_perm d2 p t.
Proof.
  induction N; intros.
  > inv H; inv H3; auto.
    inv H1; try assumption.
    > eapply perm_step_readable_perm; eauto.
      destruct released; subst; auto.
      assert (perm_step t' d1 PErelease d2) by (constructor; auto).
      eapply perm_step_readable_perm; eauto.
      destruct released; subst; auto.
      assert (perm_step t' d1 PErelease d2) by (constructor; auto).
      eapply perm_step_readable_perm; eauto.
      destruct r; subst; auto.
      assert (perm_step t' d1 PErelease d2) by (constructor; auto).
      eapply perm_step_readable_perm; eauto.

  > inv H3; inv H.
    destruct mb2 as (mm2,dd2).
    destruct mb0.
    assert (dd2=b).
      eapply unbuffer_n_same_buf; eauto.
    subst.
    destruct m as (m,d).
    assert (d1=d).
      inv H8.
      destruct bi; inv HU3; auto.
    subst.
    destruct mm2 as (m3,d3).
    assert (d2=d3).
      inv H7.
      destruct bi; inv HU3; auto.
    subst.
    eapply IHN with (3:=H1); eauto.
Qed.

Require Import LocalLoad.

Lemma frms' t n :
  ∀ b m1 m1f,
    unbuffer_n' t (m1,b) n (m1f, empty_buffer) →
    ∀ inbuf a v,
      mem_step t m1f (MEread Local inbuf a v) m1f
      ∀ m2,
        le t m1 m2
        ∀ m2f,
          unbuffer_n' t (m2,b) n (m2f, empty_buffer) →
          mem_step t m2f (MEread Local inbuf a v) m2f.
Proof.
  induction n.
  intros b m1 m1f H inbuf a v H0 m2 H1 m2f H2. inversion H; inv H2.
  inv H0. destruct m2f. econstructor; eauto.
  destruct H1 as [P L M]. apply L; eauto using readable_frozen.
  destruct H1 as [P L M]. eapply le_frozen_readable. eapply P; eauto.
  eapply readable_frozen; eauto. eassumption.
  intros b m1 m1f H; inv H. destruct mb2 as (mi1 & bi1).
  intros inbuf a v H m2 H0 m2f H2. inv H2. destruct mb2 as (mi2 & bi2).
  assert (bi1 = bi2) as ->. inv H1. inv H5. app_inv. easy.
  eapply IHn. eapply H3. 3: eapply H7.
  assumption.
  inv H1. inv H5. app_inv.
  eauto using le_buf.
Qed.

Lemma flush_read_mem_step: forall t b m1 m1_flushed,
  flush t b m1 m1_flushed ->
  forall inbuf a v t' e m2,
    mem_step t m1_flushed (MEread Local inbuf a v) m1_flushed ->
    mem_step t' m1 e m2 ->
    t <> t' ->
    forall m2_flushed,
      flush t b m2 m2_flushed ->
      mem_step t m2_flushed (MEread Local inbuf a v) m2_flushed.
Proof.
  intros.
  apply flush_unbuffer_n' in H.
  apply flush_unbuffer_n' in H3.
  eapply (frms' _ _ _ _ _ H); eauto.
  eapply le_mem_step; eauto.
Qed.

Require Import Relation_Operators.
Require Import Operators_Properties.

Lemma flush_read_unbuffer: forall t b m1 m1_flushed,
  flush t b m1 m1_flushed ->
  forall inbuf a v b' m2,
    mem_step t m1_flushed (MEread Local inbuf a v) m1_flushed ->
    unbuffer t (m1,b) (m2,b') ->
    forall m2_flushed,
      flush t b' m2 m2_flushed ->
      mem_step t m2_flushed (MEread Local inbuf a v) m2_flushed.
Proof.
  intros.
  apply flush_unbuffer_n' in H.
  apply flush_unbuffer_n' in H2.
  inv H.
  > inv H1.
    unfold empty_buffer in *; simpl in *.
    eelim app_cons_not_nil; eauto.
  > assert (mb2=(m2,b')).
      inv H1; inv H4.
      exploit app_inj_tail; eauto.
      destruct 1; subst.
      f_equal.
      destruct bi0; inv HU3; inv HU0; try congruence.
    subst.
    assert (n = length ( b')).
      inv H4; simpl.
      generalize (app_length b' (bi::nil)).
      simpl; rewrite <- H3.
      omega.
    rewrite <- H in *.
    assert ((m2_flushed,empty_buffer)=(m1_flushed,empty_buffer)).
      eapply unbuffer_n'_func; eauto.
    congruence.
Qed.

Lemma mem_trace_safe_snd: forall t t' b s1 tr s2,
  mem_trace t' (safe t b) s1 tr s2 -> safe t b s2.
Proof.
  induction 1; auto.
Qed.
Hint Resolve mem_trace_safe_snd.

Lemma mem_remove : forall t t' s,
  Rset.mem t' (Rset.remove t s) = if peq t' t then false else Rset.mem t' s.
Proof.
  unfold Rset.mem, Rset.remove; intros.
  destruct peq.
  > subst; rewrite PTree.grs; auto.
  > rewrite PTree.gro; auto.
Qed.

Lemma mem_trace_readable_perm : forall a t' t P m1 e m2,
  mem_trace t P m1 e m2 ->
  readable_perm m1 a t' -> t<>t' ->
  readable_perm m2 a t'.
Proof.
  induction 1; auto.
  intros; exploit IHmem_trace; auto; clear IHmem_trace H0 H; intros.
  inv H; inv TM2; simpl in *; auto.
  > inv ESD.
    > econstructor; eauto.
    > econstructor; eauto.
    > unfold has_store_perm in *.
      econstructor.
      unfold upd_perm; destruct Ptr.eq_dec.
      > subst; autorw'.
        rewrite Rset.subset_spec in ESD0.
        exploit ESD0; eauto; intros.
        apply Rset.mem_singleton in H.
        elim H1; auto.
      > eauto.
        auto.
    > inv ESD0.
      destruct (Ptr.eq_dec a p); subst.
      > assert (s0=s) by congruence; subst.
        econstructor.
        rewrite perm_gss; eauto.
        apply Rset.mem_add; auto.
      > econstructor.
        rewrite perm_gso; eauto.
        auto.
    > generalize (ESP a); intros.
      rewrite RP1 in *; inv H.
      econstructor; eauto.
      rewrite mem_remove; rewrite peq_false; auto.
    > econstructor; eauto.
  > destruct released; subst.
    > generalize (ESP a); intros.
      rewrite RP1 in *; inv H.
      econstructor; eauto.
      rewrite mem_remove; rewrite peq_false; auto.
    > econstructor; eauto.
  > econstructor; eauto.
  > destruct released; subst.
    > generalize (ESP a); intros.
      rewrite RP1 in *; inv H.
      econstructor; eauto.
      rewrite mem_remove; rewrite peq_false; auto.
    > econstructor; eauto.
  > econstructor; eauto.
  > destruct r; subst.
    > generalize (ESP a); intros.
      rewrite RP1 in *; inv H.
      econstructor; eauto.
      rewrite mem_remove; rewrite peq_false; auto.
    > econstructor; eauto.
  > econstructor; eauto.
  > econstructor; eauto.
Qed.


Lemma addr_in_buf_app' {p b} :
  addr_in_buf p b
  ∀ b', addr_in_buf p (b ++ b').
Proof.
  induction b as [|[a v| |] b];
    try (simpl; intuition; congruence).
  intros X b'; generalize dependent X.
  rewrite <- app_comm_cons. unfold addr_in_buf. fold addr_in_buf.
  eq_case. intros -> _. auto.
  simpl; intuition.
Qed.

Lemma ext_trace_read_mem_step: forall a v st af M1 tr M2,
  ext_trace st af M1 tr M2 ->
  af = Interleaved ->
  let (m'0, b'0) := M1 in
    let (m'1, b) := M2 in
      b=nil ->
      (∀ x k, ¬ In (FBufItem x k) b'0) →
      (if addr_in_buf a b'0
        then
          buf_load a b'0 = Some v
          ∧ wf_val vwf_ptr areadable_perm m'0 a st
        else mem_step st m'0 (MEread Local false a v) m'0) ->
 mem_step st m'1 (MEread Local false a v) m'1.
Proof.
  induction 1; intros; subst; simpl in *; auto.
  > case_eq (addr_in_buf a b2); intros Ha; rewrite Ha in *; intuition.
    > apply H6.
      eapply mem_trace_readable_perm; eauto.
    > apply H2.
      eapply localread_leftmover_trace_mem ; eauto.
      exploit trace_mem_inv_eq1; eauto.
 > inv H.
   case_eq (addr_in_buf a b2).
   > intros X; apply IHext_trace; auto.
     intros x k K. apply (H3 x k). rewrite in_app. now left.
     pose proof (proj1 (buf_load_iff a b2) X).
     case_eq (buf_load a b2). 2: clarify.
     intros v' H'.
     rewrite (addr_in_buf_app' X) in H4.
     rewrite (buf_load_app1 H') in H4.
     intuition.
     autorw'.
     inv HU3; simpl in *; auto.
   > generalize (addr_in_buf_app a b2 (bi::nil)).
     bif2.
     > intros [H|H] K. congruence.
       destruct bi as [a' v'| |]; clarify.
       unfold addr_in_buf in H. destruct @eq_dec; clarify.
       rewrite buf_load_app2 in H4; auto.
       unfold buf_load in H4. destruct H4 as (H2 & H2').
       destruct @eq_dec; clarify.
       apply IHext_trace; auto.
       intros x k ?. apply (H3 x k). rewrite in_app. now left.
       inv HU3. simpl. autorw'. econstructor; eauto.
       eapply load_store_new; eauto.
       intuition.
     > intros (X & Y) _. apply IHext_trace; auto; clear IHext_trace.
       now intros x k ?; apply (H3 x k); rewrite in_app; left.
       inv H4.
       autorw'.
       inv HU3; econstructor; eauto.
       > erewrite (load_store_old); eauto.
         unfold addr_in_buf in Y.
         destruct @eq_dec; simpl in *; congruence.
       > erewrite (load_alloc_other); eauto.
         destruct (ranges_disjoint_dec(range_of_chunk a Mint32)(p,i)).
         auto.
         apply False_ind.
         destruct (load_chunk_allocated_someD ESL) as ((r & mk & HR & HR') & AL).
         destruct (alloc_someD ESL0) as (? & ? & ? & U).
         eapply U; eauto.
         apply ranges_overlap_comm.
         eapply overlap_inside_overlap; eauto.
       > eelim H3. rewrite in_app. right. left. reflexivity.
Qed.

Lemma refines_localload: forall addr args dst f stmt,
  refines
  (Sseq
    (Sload Local addr args dst)
    (Satomic f stmt))
  (Satomic f
    (Sseq
      (Sload Local addr args dst)
      stmt)).
Proof.
  unfold refines; intros.
  inv H.
  inv H0.
  > inv H3; inv H5.
    econstructor; eauto; clear H1.
    assert (Hread2:mem_step st m'1 (MEread Local false a v) m'1).
      clear - H16 H19 H8 H17.
      now exploit ext_trace_read_mem_step; eauto.
    econstructor; eauto.
    simpl; auto.
    replace (@nil (positive*ext_event)) with (nil++@nil (positive*ext_event)) by auto.
    econstructor; eauto.
    econstructor; eauto.
    simpl; auto.
  > inv H4; eelim H8; eauto.
Qed.


Lemma mem_trace_mon: forall t P1 m1 l m2,
   mem_trace t P1 m1 l m2 ->
   forall P2,
     (forall m, P1 m -> P2 m) ->
     mem_trace t P2 m1 l m2.
Proof.
  induction 1; econstructor; eauto.
Qed.

Lemma ext_trace_push_item: forall t af mb1 tr mb2,
  ext_trace t af mb1 tr mb2 ->
  forall m1 m2 bi b1 b2,
    mb1 = (m1,push_item bi b1) ->
    mb2 = (m2,b2) ->
    (b2 = empty_buffer /\ exists m1', exists m2', exists e,
      buf_step t m1' bi e m2' /\
      exists tr1, exists tr2,
        tr = tr1 ++ tr2 /\
        ext_trace t af (m1,b1) tr1 (m1',empty_buffer) /\
        ext_trace t af (m2',empty_buffer) tr2 (m2,empty_buffer))
    \/
    (exists b2', b2 = push_item bi b2' /\
      ext_trace t af (m1,b1) tr (m2,b2')).
Proof.
  induction 1; intros.
  > inv H; inv H0.
    right; econstructor; split; eauto.
  > inv H1; inv H2.
    exploit IHext_trace; eauto; clear IHext_trace.
    intros [(T1 & m1' & m2' & e' & T2 & tr1 & tr2 & T3 & T4 & T5)|(b2' & T1 & T2)].
    > left; split; auto.
      econstructor; econstructor; econstructor; split; eauto.
      destruct e.
      > inv H; unfold cons'; simpl.
        eauto.
      > exists ((t0,m::e):::tr1); exists tr2; repeat split; auto.
        subst; simpl; auto.
        econstructor 2; eauto.
    > right; econstructor; split; eauto.
      unfold push_item in *.
  > inv H1; inv H2.
    inv H.
    unfold push_item in HU3, HU2; simpl in *.
    destruct b2; inv HU2.
    > clear IHext_trace; left.
      exploit ext_trace_from_empty_buffer. eassumption. intros ->.
      split; auto.
      exists m0; exists m2. econstructor.
      split; eauto.
      exists nil; exists l; repeat split; auto.
    > exploit (IHext_trace m2 m4 b b2 b4); eauto; clear IHext_trace.
      intros [(T1 & m1' & m2' & e' & T2 & tr1 & tr2 & T3 & T4 & T5)|(b2' & T1 & T2)].
       > left; split; auto.
        econstructor; econstructor; econstructor; split; eauto.
        econstructor; econstructor; split; eauto.
        split; auto.
        econstructor 3; eauto.
        econstructor; simpl; eauto.
      > right; econstructor; split; eauto.
        econstructor 3; eauto.
        econstructor; eauto.
Qed.

Lemma ext_trace_write_mem_step: forall t af mb1 tr mb2,
  ext_trace t af mb1 tr mb2 ->
  let (m1,b1) := mb1 in
  let (m2,b2) := mb2 in
  forall a v m0,
    b1 = empty_buffer ->
    mem_step t m0 (MEwrite false Local a v) m1 ->
    exists m',
      ext_trace t af (m0,b1) tr (m',b2) /\
      mem_step t m' (MEwrite false Local a v) m2.
Proof.
  induction 1; intros.
  > econstructor; split.
    econstructor 1.
    subst; econstructor; constructor 2.
    auto.
  > apply trace_mem_inv_eq1 in H.
    assert (safe t b2 m0).
      subst; econstructor; constructor 2.
    exploit localwrite_leftmover_mem_trace; eauto.
    intros (m' & M1 & M2).
    destruct (IHext_trace _ _ _ H1 M2) as (m'' & M3 & M4).
    exists m''; split; auto.
    econstructor; eauto.
    rewrite <- (rev_involutive e).
    apply trace_mem_inv_eq2; auto.
  > subst; inv H.
    unfold empty_buffer in *.
    eelim app_cons_not_nil; eauto.
Qed.

Lemma ext_trace_hidden_perm_inv: forall tid af mb tr mb',
  ext_trace tid af mb tr mb' ->
  let '(m,_) := mb in
  let '(m',_) := mb' in
    forall a, m.(perms) a = HiddenBy tid -> m'.(perms) a = HiddenBy tid.
Proof.
  induction 1; simpl in *; unfold empty_perm in * ;try congruence; intros.
  > apply IHext_trace; auto.
    revert H1.
    clear IHext_trace H0 SAFE.
    induction H; auto.
    intros; exploit IHmem_trace; auto.
    clear IHmem_trace TM3 H1 H.
    inv TM2; simpl in *; unfold empty_perm in *; auto.
    > inv ESD; unfold empty_perm in *; trivial.
      > unfold upd_perm in *; destruct Ptr.eq_dec; intuition try congruence.
      > unfold has_store_perm in *. autorw'.
      > inv ESD0. intros. rewrite perm_gso. trivial. congruence.
      > generalize (ESP a); intros T; inv T; unfold empty_perm in *; try congruence.
    > destruct released; subst; auto.
      generalize (ESP a); intros T; inv T; unfold empty_perm in *; try congruence.
    > destruct released; subst; auto.
      generalize (ESP a); intros T; inv T; unfold empty_perm in *; try congruence.
    > destruct r; subst; auto.
      generalize (ESP a); intros T; inv T; unfold empty_perm in *; try congruence.
  > apply IHext_trace; auto.
    clear H0 IHext_trace.
    inv H.
    inv HU3; simpl in *; auto.
Qed.

Lemma refines_localstore_aux ge sp tid m b rs addr args dst f stmt af tr m' b' s' :
  bigstep ge sp tid (m, b, rs)
          (Sseq (Sstore false Local addr args dst) (Satomic f stmt))
          af tr (m', b', s') →
   bigstep ge sp tid (m, b, rs)
           (Satomic f (Sseq (Sstore false Local addr args dst) stmt))
           af tr (m', b', s').
Proof.
  intros H. inv H.
  inv H2; inv H4.
  edestruct (ext_trace_push_item _ _ _ _ _ H7)
      as [(T1 & m1' & m2' & e' & T2 & tr1 & tr2 & T3 & T4 & T5)|(b2' & T1 & T2)];
        eauto; clear H7.
  > simpl in T2.
    set (bi:=(WBufItem a (Val.conv (rs' dst) (type_of_chunk Mint32)))).
    assert (TT2:mem_step tid m1' (MEwrite false Local a (rs' dst)) m2').
      inv T2; constructor; auto.
      inv ESD; auto.
      inv H20.
      exploit ext_trace_hidden_perm_inv; eauto.
    elim (ext_trace_write_mem_step _ _ _ _ _ T5 _ _ _ (refl_equal _) TT2); intros mm (M1 & M2).
    clear T5 TT2.
    econstructor. subst. eapply ext_trace_app. eassumption.
    eapply ext_trace_app. eassumption. eassumption.
    simpl; intuition.
    replace (@nil (positive*ext_event)) with (nil++@nil (positive*ext_event)) by auto.
    econstructor; eauto.
    econstructor; eauto.
  > inv T1.
  > inv H3; eelim H7; reflexivity.
Qed.

Lemma refines_localstore: forall addr args dst f stmt,
  refines
  (Sseq
    (Sstore false Local addr args dst)
    (Satomic f stmt))
  (Satomic f
    (Sseq
      (Sstore false Local addr args dst)
      stmt)).
Proof.
  unfold refines; intros.
  inv H.
  econstructor; eauto.
  eapply refines_localstore_aux. eassumption.
Qed.

Lemma local_before_abort_bigstep:
  forall tid ge sp st stmt af tr st',
  bigstep ge sp tid st stmt af tr st' ->
  local_before_abort stmt = true ->
  let '(m,b,rs) := st in
  let '(m',b',s') := st' in
    safe tid b m ->
    safe tid b' m' ->
    ext_trace tid af (m,b) tr (m',b').
Proof.
  induction 1; simpl; try congruence;
    try (constructor; auto); auto; intros.
  destruct r; simpl in *; try congruence; subst; auto.
  replace l with (l++nil).
  eapply ext_trace_app; eauto.
  exploit IHbigstep; eauto; intros.
  inv H5; auto.
  repeat rewrite app_nil_r; auto.
  destruct st as ((m',b'),r').
  rewrite andb_true_iff in *; intuition eauto.
  destruct st as ((m',b'),r').
  rewrite andb_true_iff in *; intuition eauto.
  destruct st'' as ((m'',b''),r''); eauto.
  destruct st as ((m',b'),r');
  destruct st' as ((m'',b''),r''); eauto.
  intros.
  apply IHbigstep; auto.
  simpl; rewrite H0; auto.
  destruct st as ((mm',bb'),r');
  destruct st' as ((m'',b''),r''); eauto.
  simpl in *.
  rewrite andb_true_iff in *; intuition eauto.
  destruct st as ((mm',bb'),r');
  destruct st' as ((m'',b''),r''); eauto.
  rewrite andb_true_iff in *; intuition eauto.
  destruct st as ((mm',bb'),r');
  destruct st' as ((m'',b''),r''); eauto.
  rewrite andb_true_iff in *; intuition eauto.
  destruct st as ((mm',bb'),r');
  destruct st' as ((m'',b''),r''); eauto.
  rewrite andb_true_iff in *; intuition eauto.
  destruct st as ((mm',bb'),r');
  destruct st' as ((m'',b''),r''); eauto.
Qed.

Lemma local_before_abort_last:
  forall ge sp tid st stmt af tr st',
  bigstep ge sp tid st stmt af tr st' ->
  local_before_abort stmt = true ->
  let (m',s') := st' in
  match s' with
    | SReturn _ => False
    | SAbort => False
    | _ => True
  end.
Proof.
  induction 1; simpl; intros; auto;
  try (destruct st; destruct r; auto);
  try (destruct st'; destruct r; auto).
  destruct rs''; auto.
  rewrite andb_true_iff in *; intuition.
  rewrite andb_true_iff in *; intuition.
  rewrite andb_true_iff in *; intuition.
  rewrite andb_true_iff in *; intuition.
  destruct st''; destruct r; auto.
  simpl in *.
  rewrite andb_true_iff in *; intuition.
  simpl in *.
  rewrite andb_true_iff in *; intuition.
  rewrite andb_true_iff in H2; destruct H2; auto.
  rewrite andb_true_iff in H2; destruct H2; auto.
  rewrite andb_true_iff in H1; destruct H1; auto.
  rewrite andb_true_iff in H1; destruct H1; auto.
  rewrite andb_true_iff in H0; destruct H0; auto.
  rewrite andb_true_iff in H0; destruct H0; auto.
  rewrite andb_true_iff in H0; destruct H0; auto.
  rewrite andb_true_iff in H0; destruct H0; auto.
Qed.


Lemma refines_stmt_abort: forall stmt af e r,
  local_before_abort stmt = true ->
  refines (Sseq stmt (Sabort af r e)) (Sabort af r e).
Proof.
  unfold refines; intros.
  inv H0.
  inv H1.
  > inv H6.
    exploit local_before_abort_bigstep; eauto; simpl; intros.
    rewrite app_ass; simpl.
    rewrite <- (app_nil_l (l1++tr')).
    econstructor; eauto.
    econstructor; eauto.
  > exploit local_before_abort_last; eauto; simpl; intros.
    destruct s'; intuition.
    eelim H9; eauto.
Qed.

Lemma refines_abort_stmt: forall stmt af r e,
  refines (Sseq (Sabort af r e) stmt) (Sabort af r e).
Proof.
  unfold refines; intros.
  inv H.
  inv H0.
  inv H3.
  econstructor; eauto.
Qed.

Lemma refines_loop_branch_abort_aux: forall tid ge sp st S af tr st',
  bigstep ge sp tid st S af tr st' -> forall e stmt af0 r,
  S = Sloop (Sbranch (Sabort af0 r e) stmt) ->
  let '(m,b,rs) := st in
  let '(m',b',s') := st' in
    safe tid b m ->
    safe tid b' m' ->
  bigstep ge sp tid st (Sbranch (Sseq (Sloop stmt) (Sabort af0 r e)) (Sloop stmt)) af tr st'.
Proof.
  induction 1; intros; try congruence.
  inv H.
  eapply exec_branch_right.
  econstructor.
  inv H2.
  destruct st as ((mm,bb),s).
  exploit IHbigstep2; eauto; clear IHbigstep2 IHbigstep1; intros; clear H0.
  inv H.
  inv H8.
  destruct st' as ((mm',bb'),s').
  intros; exploit H2; eauto; clear H2; intros H2.
  inv H2.
  inv H10.
  eapply exec_branch_left.
  rewrite <- app_ass.
  econstructor; eauto.
  econstructor; eauto.
  eapply exec_branch_right.
  econstructor; eauto.
  eapply exec_branch_right.
  econstructor; eauto.
  destruct st as ((mm,bb),ss).
  destruct st' as ((mm',bb'),s').
  inv H1.
  intros.
  inv H.
  eapply exec_branch_left.
  replace l with (nil++l) by auto.
  econstructor; eauto.
  eapply exec_loop_end.
  econstructor; eauto.
  econstructor; eauto.
  econstructor; eauto.
Qed.

Lemma refines_loop_branch_abort: forall af r e stmt,
  refines
    (Sloop (Sbranch (Sabort af r e) stmt))
    (Sbranch (Sseq (Sloop stmt) (Sabort af r e)) (Sloop stmt)).
Proof.
  unfold refines; intros.
  inv H; econstructor; eauto.
  exploit refines_loop_branch_abort_aux; eauto.
Qed.


Lemma refines_branch_dup: forall stmt1 stmt2,
  refines
    (Sbranch stmt1 (Sbranch stmt1 stmt2))
    (Sbranch stmt1 stmt2).
Proof.
  unfold refines; intros.
  inv H; econstructor; eauto.
  inv H0.
  repeat (econstructor; eauto).
  inv H7.
  repeat (econstructor; eauto).
  vauto.
Qed.

Lemma left_mover_bigstep:
  forall tid ge sp st stmt af tr st',
  bigstep ge sp tid st stmt af tr st' ->
  forall (R1:no_atomic_in_statement stmt=true),
  left_mover stmt = true -> forall m'' b'' tr',
  let '(m',b',s') := st' in
  let '(m,b,s) := st in
    ext_trace tid af (m',b') tr' (m'',b'') ->
    exists m0,
      ext_trace tid af (m,b) (tr++tr') (m0,b'') /\
      bigstep ge sp tid (m0,b'',s) stmt Atomic nil (m'',b'',s') /\
      ( b=b').
Proof.
  induction 1; simpl; try congruence;
    try constructor;
      try (intros; econstructor; split; [eassumption|split;try econstructor; eauto];fail).
  > repeat rewrite andb_true_iff in *; intuition.
    destruct st as ((m' & b') & rs'); intros.
    edestruct H6 as (m1 & M1 & M2 & M3); eauto; clear H6; subst.
    econstructor; split; eauto.
    split; constructor; eauto.
  > repeat rewrite andb_true_iff in *; intuition.
    destruct st as ((m' & b') & rs'); intros.
    edestruct H6 as (m1 & M1 & M2 & M3); eauto; clear H2; subst.
    econstructor; repeat split; eauto.
    eapply exec_if_false; eauto.
  > destruct st'' as ((m'' & b'') & rs''); intros; simpl in *.
    edestruct IHbigstep2 as (m1 & M1 & M2 & M3); eauto; clear IHbigstep2.
    edestruct IHbigstep1 as (m1' & M1' & M2' & M3'); eauto; clear IHbigstep1.
    rewrite app_ass; econstructor; split; eauto.
    split; try congruence.
    replace (@nil (positive*ext_event)) with (nil++@nil (positive*ext_event)) by auto.
    eapply exec_while_true; eauto.
  > destruct st as ((m' & b') & rs'); intros; simpl in *.
    edestruct IHbigstep as (m1 & M1 & M2 & M3); eauto; clear IHbigstep; subst.
    econstructor; split; eauto.
    split ;auto.
    eapply exec_while_true_abrupt; eauto.
    red; intros.
    inv H4; eelim H1; eauto.
  > intros.
    econstructor; split; eauto.
    split; auto.
    eapply exec_while_false; eauto.
  > destruct st as ((m & b) & rs); destruct st' as ((m' & b') & rs'); intros; simpl in *.
    edestruct IHbigstep as (m1 & M1 & M2 & M3); eauto; clear IHbigstep.
    repeat rewrite andb_true_iff; intuition.
    repeat rewrite andb_true_iff; intuition.
  > econstructor; split; eauto.
    split; try econstructor; eauto.
  > repeat rewrite andb_true_iff in *; intuition.
    destruct st as ((m & b) & rs); destruct st' as ((m0' & b0') & rs0'); intros; simpl in *.
    assert (S:safe tid b'' m'') by eauto.
    edestruct H3 as (m1 & M1 & M2 & M3); eauto; clear H3 H7; subst.
    edestruct H8 as (m1' & M1' & M2' & M3'); eauto; clear H8 M1; subst.
    rewrite app_ass.
    econstructor; split; eauto.
    replace (@nil (positive*ext_event)) with (nil++@nil (positive*ext_event)) by auto.
    split; auto.
    econstructor; eauto.
  > repeat rewrite andb_true_iff in *; intuition.
    destruct st as ((m & b) & rs); destruct st' as ((m' & b') & rs'); intros.
    edestruct H6 as (m1 & M1 & M2 & M3); eauto; clear H6 H2.
    econstructor; split; eauto.
    split; auto.
    eapply exec_seq_abrupt; eauto.
    red; intros.
    inv H2; eelim H0; eauto.
  > repeat rewrite andb_true_iff in *; intuition.
    destruct st as ((m & b) & rs); destruct st' as ((m' & b') & rs'); intros.
    edestruct H5 as (m2 & M1 & M2 & M3); eauto; clear H5; subst.
    econstructor; split; eauto.
    split; auto.
    econstructor; eauto.
  > repeat rewrite andb_true_iff in *; intuition.
    destruct st as ((m & b) & rs); destruct st' as ((m' & b') & rs'); intros.
    edestruct H5 as (m2 & M1 & M2 & M3); eauto; clear H5; subst.
    econstructor; split; eauto.
    split; auto.
    eapply exec_branch_right; eauto.
  > destruct st as ((m0 & b9) & rs0); destruct st' as ((m' & b') & rs'); intros.
    edestruct IHbigstep2 as (m2 & M1 & M2 & M3); eauto; clear IHbigstep2.
    edestruct IHbigstep1 as (m2' & M1' & M2' & M3'); eauto; clear IHbigstep1; subst.
    rewrite app_ass; econstructor; split; eauto.
    split; auto.
    replace (@nil (positive*ext_event)) with (nil++@nil (positive*ext_event)) by auto.
    eapply exec_loop_next; eauto.
  > destruct st as ((m0 & b9) & rs0); destruct st' as ((m' & b') & rs'); intros.
    edestruct IHbigstep as (m2 & M1 & M2 & M3); eauto; clear IHbigstep; subst.
    econstructor; split; eauto.
    split; auto.
    eapply exec_loop_next_abrupt; eauto.
    red; intros.
    inv H3; eelim H0; eauto.
Qed.

Lemma left_mover_abort_last:
  forall ge sp tid st stmt af tr st',
  bigstep ge sp tid st stmt af tr st' ->
  left_mover stmt = true ->
  let (m',s') := st' in
  match s' with
    | SReturn _ => False
    | SAbort => False
    | _ => True
  end.
Proof.
  induction 1; simpl; intros; auto;
  try (destruct st; destruct r; auto);
  try (destruct st'; destruct r; auto);
  simpl in *;
  repeat rewrite andb_true_iff in *; intuition.
  congruence.
Qed.

Lemma refines_left_mover : forall stmt1 f stmt2,
  left_mover stmt1 = true ->
  no_atomic_in_statement stmt1 = true ->
  no_atomic_in_statement stmt2 = true ->
  refines
    (Sseq stmt1 (Satomic f stmt2))
    (Satomic f (Sseq stmt1 stmt2)).
Proof.
  unfold refines; intros.
  inv H2.
  inv H3.
  inv H8.
  edestruct (left_mover_bigstep _ _ _ _ _ _ _ _ H6) as (m0 & M1 & M2 & M3); eauto.
  subst.
  econstructor; eauto.
  econstructor; eauto.
  simpl; intuition.
  apply no_atomic_in_statement_dec; auto.
  replace (@nil (positive*ext_event)) with (nil++@nil (positive*ext_event)) by auto.
  econstructor; eauto.
  eauto.
  exploit left_mover_abort_last; eauto; simpl.
  destruct s'; intros; intuition.
  elim H11 with (m',b') r; auto.
Qed.





  
Lemma left_mover_strong_abort_last:
  forall ge sp tid st stmt af tr st',
  bigstep ge sp tid st stmt af tr st' ->
  left_mover_strong stmt = true ->
  let '(m', _,s') := st' in
  match s' with
    | SReturn _ => False
    | _ => True
  end.
Proof.
  induction 1; simpl; intros; auto;
  try (destruct st' as [(? & ?) [| ? | ?]]; auto);
  try (destruct st as [(? & ?) [| ? | ?]]; auto);
  simpl in *; repeat andb; intuition.
  congruence.
  destruct body; simpl in *; auto;
  rewrite andb_true_iff in IHbigstep; auto.
  destruct stmt1; simpl in *; auto;
  try rewrite andb_true_iff in H2; intuition.
  destruct stmt2; simpl in *; auto.
  inv H0.
  destruct stmt1; simpl in *; auto;
  try rewrite andb_true_iff in H1; intuition.
  inv H.
Qed.

Lemma no_atomic_in_left_move_conv s :
  no_atomic_in_statement (left_move_conv s) = no_atomic_in_statement s.
Proof.
  induction s; auto;
  simpl; try congruence.
  destruct s1; simpl in *; try congruence.
  destruct s2; simpl in *; try congruence.
  destruct af; auto.
  destruct release; auto.
Qed.

Lemma refines_strong_left_mover ge sp tid st S af tr st' :
  bigstep ge sp tid st S af tr st' →
  left_mover_strong S = true
  no_atomic_in_statement S = true
  match st' with
    | (m', b', SIntra rs') =>
      ∀ f S' tr',
      ∀ m'' b'' s'',
     no_atomic_in_statement S' = true
     safe tid b'' m'' →
     bigstep ge sp tid (m', b', rs') (Satomic f S') af tr' (m'', b'', s'') →
     bigstep ge sp tid st (Satomic f (Sseq (left_move_conv S) S')) af (tr ++ tr') (m'', b'', s'')
    | (_, SReturn _) => False
    | (m', b', SAbort) =>
      ∀ f S',
        no_atomic_in_statement S' = true
        safe tid b' m' →
        bigstep ge sp tid st (Satomic f (Sseq (left_move_conv S) S')) af tr (m', b', SAbort)
  end.
Proof.
  Hint Resolve no_atomic_in_left_move_conv.
  induction 1.
  intros H H0 f S' tr' m'' b'' [|?|r''] H1 SAFE H2; inv H2.
  econstructor. simpl. eassumption.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  rewrite <- (app_nil_r nil). vauto.
  econstructor. simpl. eassumption.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  rewrite <- (app_nil_r nil). vauto.
  econstructor. simpl. eassumption.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  rewrite <- (app_nil_r nil). vauto.
  now inversion 1.
  intros _ _. intros f S' tr' m'' b'' s'' H H0 H1. inv H1.
  econstructor; eauto.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  rewrite <- (app_nil_r nil). vauto.
  now inversion 1.
  intros _ _. intros f S' tr' m'' b'' s'' H1 H2 H3. inv H3.
  econstructor; eauto.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  rewrite <- (app_nil_r nil). vauto.
  now inversion 1.
  now inversion 1.
  now inversion 1.
  simpl. destruct ap. 2: now inversion 1. intros _ _.
  intros f S' tr' m''0 b'' s'' H5 SAFE H6. inv H6.
  econstructor; eauto. now simpl; intuition.
  rewrite <- (app_nil_r nil). econstructor; eauto.
  econstructor. 4: reflexivity. 4: eassumption. 4: assumption.
  econstructor. vauto. simpl.
  exploit ext_trace_read_mem_step. eapply H14. auto. simpl.
  intros Q. eapply Q; eauto.
  easy.
  simpl. destruct r. inversion 1. destruct ap. 2: now inversion 1. intros _ _.
  intros f S' tr' m''0 b''0 s'' H5' H6 H7.
  eapply refines_localstore_aux.
  econstructor; eauto.
  vauto.
  simpl. destruct r. now inversion 1. destruct ap. 2: now inversion 1. intros _ _.
  intros f S' tr' m'' b'' s'' H3 H4 H5. inv H5.
  now inversion 1.
  destruct st as ((mi & bi) & [|?|rsi]); auto.
  simpl. intro. andb as L1 L2. intro. andb as A1 A2.
  intros f S' H1 H2.
  pose proof (IHbigstep L1 A1 f S' H1 H2) as K; inv K. clear IHbigstep.
  econstructor; eauto.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  inv H15. 2: now vauto. destruct l1; clarify; destruct l2; clarify. clear H5. vauto.
  now simpl; intros; repeat andb; intuition.
  simpl. intro. andb as L1 L2. intro. andb as A1 A2.
  intros f S' tr' m'' b'' s'' H1 H2 H3.
  exploit IHbigstep; try assumption. eapply H1. eassumption. intros Hs. clear IHbigstep.
  inv Hs. econstructor; eauto.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  inv H16. destruct l1; clarify; destruct l2; clarify. clear H6.
  econstructor; eauto.
  econstructor; auto.
  eapply exec_seq_abrupt; eauto. vauto.
  destruct st as ((mi & bi) & [|?|rsi]); auto.
  simpl. intro. andb as L1 L2. intro. andb as A1 A2.
  intros f S' H1 H2.
  pose proof (IHbigstep L2 A2 f S' H1 H2) as K; inv K. clear IHbigstep.
  econstructor; eauto.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  inv H15. destruct l1; clarify; destruct l2; clarify. clear H5.
  econstructor; eauto. vauto. vauto.
  now simpl; intros; repeat andb; intuition.
  simpl. intro. andb as L1 L2. intro. andb as A1 A2.
  intros f S' tr' m'' b'' s'' H1 H2 H3.
  exploit IHbigstep; try assumption. eapply H1. eassumption. auto. intros Hs. clear IHbigstep.
  inv Hs. econstructor; eauto.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  inv H16. destruct l1; clarify; destruct l2; clarify. clear H6.
  econstructor; eauto.
  eapply exec_if_false; eauto.
  eapply exec_seq_abrupt; eauto. vauto.
  destruct st'' as ((m'' & b'') & [|?|rs'']); auto.
  simpl.
  intros H3 H4 f S' H5 H6.
  pose proof (IHbigstep2 H3 H4 f S' H5 H6) as Hs2. clear IHbigstep2.
  exploit (IHbigstep1). 5: eapply Hs2. assumption. assumption.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  rewrite no_atomic_in_left_move_conv. now autorw'.
  assumption.
  intros Hs; clear Hs2 IHbigstep1.
  inv Hs.
  inv H19. destruct l0; clarify; destruct l3; clarify. clear H9.
  inv H13. destruct l0; clarify; destruct l3; clarify. clear H9.
  econstructor. eassumption.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  rewrite <- (app_nil_l nil); econstructor; eauto.
  rewrite <- (app_nil_l nil); econstructor; eauto.
  econstructor. eassumption.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  econstructor. 2: congruence.
  rewrite <- (app_nil_l nil); econstructor; eauto.
  econstructor. eassumption.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  vauto.
  simpl. intros H3 H4 f S' tr' m''0 b''0 s'' H5 SAFE H6.
  exploit IHbigstep2; try assumption. eapply H5. eassumption. intros Hs2. clear IHbigstep2.
  exploit IHbigstep1; try assumption. 2: eassumption.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  rewrite no_atomic_in_left_move_conv. now autorw'.
  intros Hs1. clear IHbigstep1.
  clear Hs2. clear H6. clear H0 H1.
  inv Hs1. clear H15.
  econstructor. rewrite <- app_assoc. eassumption.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  inv H16.
  destruct l0; clarify; destruct l3; clarify. clear H6.
  inv H10.
  destruct l0; clarify; destruct l3; clarify. clear H6.
  destruct s''; vauto.
  vauto.
  vauto.
  destruct st as ((mi & bi) & [|?|rsi]); auto.
  simpl. intros H2 H3 f S' H4 H5.
  exploit (IHbigstep H2 H3 f (Sseq (Swhile cond args (left_move_conv body)) S')).
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  rewrite no_atomic_in_left_move_conv. now autorw'.
  assumption.
  intros Hs; clear IHbigstep. inv Hs.
  inv H18. destruct l1; clarify; destruct l2; clarify; clear H8.
  inv H12. destruct l1; clarify; destruct l2; clarify; clear H8.
  econstructor. eassumption.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  rewrite <- (app_nil_l nil). econstructor; eauto.
  rewrite <- (app_nil_l nil). vauto.
  econstructor. eassumption.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  econstructor. 2: congruence.
  rewrite <- (app_nil_l nil). vauto.
  econstructor. eassumption.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  econstructor. 2: congruence.
  vauto.
  eelim H1; reflexivity.
  simpl.
  intros H0 H1 f S' tr' m'' b'' s'' H2 H3 H4.
  inv H4. econstructor; eauto.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  rewrite <- (app_nil_l nil). vauto.
  destruct st' as ((m' & b') & [|?|rs']); auto.
  intros H0 H1 f S' H2 H3.
  assert (R1:left_move_conv (Sseq body (Swhile (negate_condition cond) args body)) =
    Sseq (left_move_conv body) (Swhile (negate_condition cond) args (left_move_conv body))).
    now destruct body; simpl; congruence.
  rewrite R1 in *; clear R1.
  simpl in *.
  assert (left_mover_strong body && left_mover_strong body = true) as L by intuition.
  assert (no_atomic_in_statement body && no_atomic_in_statement body = true) as A by intuition.
 refine (modusponens _ _ (IHbigstep _) _).
 destruct body; auto.
 clear IHbigstep; intros IHbigstep.
  exploit (IHbigstep A f S'); auto.
  intros Hs. clear IHbigstep. inv Hs.
  inv H14. destruct l1; clarify; destruct l2; clarify; clear H6.
  inv H8. destruct l1; clarify; destruct l2; clarify; clear H6.
  econstructor. eassumption.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  rewrite <- (app_nil_l nil). econstructor; eauto.
  rewrite <- (app_nil_l nil). vauto.
  eelim H16; reflexivity.
  econstructor. eassumption.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  rewrite <- (app_nil_l nil). vauto.
  simpl; intros; apply IHbigstep; simpl; intuition.
  now destruct body; rewrite andb_true_iff; auto.
  assert (R1:left_move_conv (Sseq body (Swhile (negate_condition cond) args body)) =
    Sseq (left_move_conv body) (Swhile (negate_condition cond) args (left_move_conv body))).
    now destruct body; simpl; congruence.
  rewrite R1 in *; clear R1.
  simpl. intros H0 H1 f S' tr' m'' b'' s'' H2 H3 H4.
  refine (modusponens _ _ (IHbigstep _) _).
  simpl.
  destruct body; rewrite andb_true_iff; intuition.
  clear IHbigstep; intros IHbigstep.
  exploit IHbigstep. simpl; intuition. 3: eassumption. assumption. assumption.
  intros Hs. clear IHbigstep. inv Hs. econstructor; eauto.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  inv H15. 2: now vauto. destruct l1; clarify; destruct l2; clarify. clear H7.
  rewrite <- (app_nil_l nil). econstructor; eauto. econstructor. vauto.
  case_eq (left_mover_strong stmt1 && left_mover_strong stmt2); intros Hb.
  replace (left_move_conv (Sseq stmt1 stmt2)) with
    (Sseq (left_move_conv stmt1) (left_move_conv stmt2)) in *.
  intros _. andb as L1 L2. simpl; intro. andb as A1 A2.
  destruct st' as ((mi & bi) & [|?|rsi]); auto.
  intros f S' H2 H3.
  exploit IHbigstep2; try assumption. eapply H2. intros Hs2. clear IHbigstep2.
  exploit (IHbigstep1 L1 A1 f). 3: eassumption.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  rewrite no_atomic_in_left_move_conv. now autorw'.
  assumption.
  intros Hs1. clear IHbigstep1. clear Hs2.
  inv Hs1.
  inv H14. destruct l0; clarify; destruct l3; clarify; clear H6.
  inv H10. destruct l0; clarify; destruct l3; clarify; clear H6.
  econstructor; eauto.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  rewrite <- (app_nil_l nil). econstructor; eauto.
  rewrite <- (app_nil_l nil). vauto.
  econstructor; eauto.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  econstructor; eauto.
  rewrite <- (app_nil_l nil). now vauto.
  econstructor; eauto.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  vauto.
  intros f S' tr' m'' b'' s'' H2 H3 H4.
  exploit IHbigstep2; try assumption. eapply H2. eassumption. intros Hs2. clear IHbigstep2.
  exploit IHbigstep1; try assumption. 2: eassumption.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  rewrite no_atomic_in_left_move_conv. now autorw'.
  intros Hs1. clear IHbigstep1.
  clear Hs2. clear H4 H H0.
  inv Hs1.
  econstructor. rewrite <- app_assoc. eassumption.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  inv H12.
  destruct l0; clarify; destruct l3; clarify. clear H4.
  inv H8.
  destruct l0; clarify; destruct l3; clarify. clear H4.
  destruct s''; vauto.
  vauto.
  vauto.
  destruct stmt1; simpl; try congruence; destruct stmt2; simpl in *; try congruence.
  destruct stmt1; destruct stmt2; try (simpl in *; congruence).
  simpl.
  destruct af0; try congruence.
  destruct st' as ((m'' & b'') & [|?|rs'']); auto.
  clear IHbigstep1 IHbigstep2 Hb; intros _ _.
  inv H; inv H0; intros.
  rewrite app_nil_r; econstructor; eauto.
  destruct release; simpl; intuition;
  eauto using no_atomic_in_statement_dec.
  econstructor; eauto; try congruence.
  destruct release.
  > rewrite <- (app_nil_l nil). econstructor; eauto.
    econstructor; eauto.
    econstructor; econstructor 2.
  > subst; econstructor; eauto.
  inv H0.
  inv H0.
  case_eq (left_mover_strong stmt1 && left_mover_strong stmt2); intros Hb.
  replace (left_move_conv (Sseq stmt1 stmt2)) with
    (Sseq (left_move_conv stmt1) (left_move_conv stmt2)) in *.
  destruct st' as ((m' & b') & [|?|rs']); auto.
  simpl. intros _. andb as L1 L2. intro. andb as A1 A2. intros f S' H1 H2.
  exploit (IHbigstep L1 A1 f (Sseq (left_move_conv stmt2) S')).
  simpl. rewrite no_atomic_in_left_move_conv. autorw'. assumption.
  intros K; inv K. clear IHbigstep.
  inv H13. destruct l1; clarify; destruct l2; clarify; clear H5.
  inv H9. destruct l1; clarify; destruct l2; clarify; clear H5.
  econstructor; eauto.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  rewrite <- (app_nil_l nil). econstructor; eauto.
  rewrite <- (app_nil_l nil). econstructor; eauto.
  econstructor; eauto.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  econstructor; eauto.
  rewrite <- (app_nil_l nil). econstructor; eauto.
  econstructor; eauto.
  simpl; intuition; eauto using no_atomic_in_statement_dec.
  vauto.
  now simpl; intros; repeat andb; intuition.
  eelim H0; reflexivity.
  destruct stmt1; simpl; try congruence; destruct stmt2; simpl in *; try congruence.
  destruct stmt1; destruct stmt2; try (simpl in *; congruence).
  inv H; eelim H0; eauto.
  now inversion 1.
  simpl; congruence.
  intros _ _. intros f S' tr' m'' b'' s'' H0 H1 H2. inv H2.
  econstructor; eauto. simpl; intuition.
  rewrite <- (app_nil_l nil). vauto.
  now inversion 1.
  now inversion 1.
  now inversion 1.
  now inversion 1.
  now inversion 1.
Qed.


Lemma refines_left_mover_strong : forall stmt1 f stmt2,
  left_mover_strong stmt1 = true ->
  no_atomic_in_statement stmt1 = true ->
  no_atomic_in_statement stmt2 = true ->
  refines
    (Sseq stmt1 (Satomic f stmt2))
    (Satomic f (Sseq (left_move_conv stmt1) stmt2)).
Proof.
  intros stmt1 f stmt2 H H0 H1.
  intros ge sp tid af tr st st' H2.
  inv H2. inv H3; exploit refines_strong_left_mover.
  eapply H6. auto. auto. simpl.
  intros H2. econstructor; eauto.
  eapply H7. auto. auto. simpl. destruct s'.
  2: inversion 1. 2: eelim H11; reflexivity.
  clear H11.
  intros K.
  econstructor; eauto.
Qed.

Lemma right_mover_bigstep:
  forall tid ge sp st stmt af tr st',
  bigstep ge sp tid st stmt af tr st' ->
  no_atomic_in_statement stmt = true ->
  right_mover stmt = true ->
  let '(m',b',s') := st' in
  let '(m,b,s) := st in
    m = m' /\ b = b' /\ tr = nil /\
      bigstep ge sp tid (m,b,s) stmt Atomic tr (m,b,s').
Proof.
  induction 1; simpl; try congruence;
    try (repeat split; econstructor; eauto; fail).
  > repeat rewrite andb_true_iff in *; destruct st as ((m1,b1),s1); repeat constructor; intuition.
  > repeat rewrite andb_true_iff in *; destruct st as ((m1,b1),s1).
    intuition auto.
    intros; apply exec_if_false; intuition auto.
  > destruct st'' as ((m1,b1),s1); simpl in *; intros.
    intuition try congruence.
    subst; auto.
    econstructor; eauto.
    subst; auto.
  > destruct st as ((m1,b1),s1); simpl in *; intros.
    intuition try congruence.
    econstructor; eauto.
    red; intros.
    inv H7; eelim H1; eauto.
  > intuition.
    apply exec_while_false; auto.
  > destruct st as ((m1,b1),s1); destruct st' as ((m2,b2),s2); simpl in *; intros.
    repeat rewrite andb_true_iff in *.
    intuition.
    subst; constructor; auto.
  > destruct st as ((m1,b1),s1); destruct st' as ((m2,b2),s2); simpl in *; intros.
    repeat rewrite andb_true_iff in *.
    intuition try congruence.
    subst; auto.
    subst; econstructor; intuition eauto.
  > destruct st as ((m1,b1),s1); destruct st' as ((m2,b2),s2); simpl in *; intros.
    repeat rewrite andb_true_iff in *.
    intuition try congruence.
    subst; econstructor; intuition eauto.
  > destruct st as ((m1,b1),rs1); destruct st' as ((m2,b2),rs2); simpl in *; intros.
    repeat rewrite andb_true_iff in *.
    intuition try congruence.
    subst; econstructor; intuition eauto.
  > destruct st as ((m1,b1),rs1); destruct st' as ((m2,b2),rs2); simpl in *; intros.
    repeat rewrite andb_true_iff in *.
    intuition try congruence.
    subst; eapply exec_branch_right; intuition eauto.
  > destruct st as ((m1,b1),rs1); destruct st' as ((m2,b2),rs2); simpl in *; intros.
    intuition try congruence.
    subst; auto.
    subst; econstructor; intuition eauto.
  > destruct st as ((m1,b1),rs1); destruct st' as ((m2,b2),rs2); simpl in *; intros.
    intuition try congruence.
    subst; econstructor; intuition eauto.
Qed.

Lemma refines_right_mover : forall stmt1 f stmt2,
  right_mover stmt2 = true ->
  no_atomic_in_statement stmt1 ->
  no_atomic_in_statement stmt2 ->
  refines
    (Sseq (Satomic f stmt1) stmt2)
    (Satomic f (Sseq stmt1 stmt2)).
Proof.
  unfold refines; intros.
  inv H2.
  inv H3.
  inv H6.
  exploit (right_mover_bigstep _ _ _ _ _ _ _ _ H8); eauto.
  clear H8; intros (T1 & T2 & T3 & T4); subst.
  rewrite app_ass; simpl.
  econstructor; eauto.
  econstructor; eauto.
  simpl; split; apply no_atomic_in_statement_dec; auto.
  replace (@nil (positive*ext_event)) with (nil++@nil (positive*ext_event)) by auto.
  econstructor; eauto.

  inv H7.
  econstructor; eauto.
  econstructor; eauto.
  simpl; split; apply no_atomic_in_statement_dec; auto.
  econstructor; eauto.
Qed.


Lemma refines_if_atomic : forall cond args f stmt1 stmt2,
  no_atomic_in_statement stmt1 ->
  no_atomic_in_statement stmt2 ->
  refines
    (Sifthenelse cond args (Satomic f stmt1) (Satomic f stmt2))
    (Satomic f (Sifthenelse cond args stmt1 stmt2)).
Proof.
  unfold refines; intros.
  inv H1; econstructor; eauto.
  inv H2; inv H14; econstructor; simpl; intuition eauto.
  apply no_atomic_in_statement_dec; auto.
  eapply exec_if_true; eauto.
  apply no_atomic_in_statement_dec; auto.
  eapply exec_if_false; eauto.
Qed.

Lemma refines_fence_load: forall f af addr args dst,
  refines
    (Sseq (Sfence false) (Sload af addr args dst))
    (Satomic f (Sload af addr args dst)).
Proof.
  unfold refines; intros.
  inv H.
  inv H0.
  inv H3; inv H5.
  assert (S:safe st b' m') by eauto.
  assert (b' = empty_buffer) by eapply (ext_trace_from_empty_buffer _ _ _ _ _ _ H13); auto.
  subst.
  assert (b'' = empty_buffer) by eapply (ext_trace_from_empty_buffer _ _ _ _ _ _ H1); auto.
  subst.
  econstructor; eauto.
    econstructor; eauto.
    simpl; auto.
    simpl in *. vauto.
  inv H4; eelim H8; eauto.
Qed.