Module RTLinjectlow


Require Import
  Utf8 Classical
  Coqlib Ast Maps Mem Op
  Globalenvs Events Values.

Require Import
  Utils Emem Permissions TSOMemoryMachine
  INJECT RTLinject.

Require Import
  TSOmachine Simulations.

Section TSOSEM.

  Definition te_of_me (me: mem_event) : Events.thread_event :=
    match me with
      | MEwrite _ _ p v => Events.TEmem (Events.MEwrite p Mint32 v)
      | MEread _ _ p v => Events.TEmem (Events.MEread p Mint32 v)
      | MErmw _ p v i => Events.TEmem (Events.MErmw p Mint32 v i)
      | MEalloc p i k => Events.TEmem (Events.MEalloc p i k)
      | MEfree p k => Events.TEmem (Events.MEfree p k)
      | MEperm _ => Events.TEtau
    end.

  Definition te_of_te (ev: thread_event) : option Events.thread_event :=
    match ev with
      | TEext e => Some (Events.TEext e)
      | TEtso (INJECT.TSOmem e) => Some (te_of_me e)
      | TEend ReturnVoid
      | TEend FailEvent => Some (Events.TEext Events.Efail)
      | TEstart fp v => Some (Events.TEstart fp (v::nil))
      | TEexit => Some Events.TEexit
      | TEtso TSOfence => Some (Events.TEmem Events.MEfence)
      | TEtso (INJECT.TSOunbuf _)
      | TEbegin BeginLow
      | TEend (ReturnEvent _)
      | TEtau => Some Events.TEtau
      | TEtso (INJECT.TSObeginatomic)
      | TEtso (INJECT.TSOendatomic _)
      | TEtso (INJECT.TSOstart _)
      | TEato _
      | TEbegin BeginHigh => None
    end.

  Definition not_a_high_state (st: intra_state) : bool :=
    match st with
      | RIInjectState _ _ _ _ _ _ (INJECT.NormalState _ is k) =>
        match is with
          | Satomic _ _
          | Sloop _ | Sbranch _ _ => false
          | _ => match in_atomic k with
                   | Some _ => false
                   | None => true
                 end
        end
      | _ => true
    end.

  Inductive rtl_step' (ge:genv) : intra_stateEvents.thread_eventintra_stateProp :=
  | Rtl_step s e s' te
    (STEP:rtli_step ge s e s')
    (LOW: not_a_high_state s)
    (TE: Some te = te_of_te e) :
    rtl_step' ge s te s'.

  Ltac inv_step :=
    match goal with
      | H : step _ _ _ _ _ |- _ => inversion H; try (subst; clear H)
    end.

  Ltac sktau :=
    match goal with
      | [H: te_samekind ?t Events.TEtau |- _] =>
        rewrite (te_tau_samekind t H) in *; clear H
      | [H: te_samekind ?t ?q |- _] =>
        let p := fresh in
        destruct t as [p|p| | |? ?|? ?|? ? ?|]; try destruct p; inversion H; subst; clear H
    end.

  Lemma rtli_receptive : forall ge : genv, receptive(@mklts thread_labels intra_state (rtl_step' ge)).
Proof.
    intros ge.
    intros l l' s s' STEP' Hll.
    simpl in *.
    inv STEP'.
    inv STEP; try inv_step; inv TE;
    match goal with [H: atomic_statement_mem_event _ _ _ _ ?l |- _] => destruct l;
                                                                      try now inversion H
                 | _ => idtac end;
    sktau;
    try (now inversion LOW);
    try (now eexists; vauto);
    try (now eexists; vauto; econstructor; vauto).
    destruct res0; clarify. eexists; vauto. simpl in *; intuition congruence.
    eexists; vauto. apply Rtl_step with (e := TEbegin BeginLow); vauto.
    intuition subst.
    eexists; vauto. apply Rtl_step with (e := TEtso (INJECT.TSOmem (MEread ap inbuf a v0))); vauto.
    intuition subst.
    inv ASME;
    eexists; eapply Rtl_step with (e := TEtso (INJECT.TSOmem (MErmw r p v1 _))).
      (econstructor;[|congruence]).
    eapply exec_atomic. rewrite <- H1. vauto. easy. intuition. easy. easy.
  Qed.

  Ltac hpc :=
    match goal with
      | H: _ = _, K: _ = _ |- _ => rewrite H in K; inversion K; subst; clear K
      | H: _ = _, K: _ = _ |- _ => rewrite <- H in K; inversion K; subst; clear K
    end.

  Lemma map_vint_inj : forall {u v},
                         map Vint u = map Vint v
                         u = v.
Proof.
    induction u as [|a u]; intros [|b v]; trivial; inversion 1. f_equal. intuition.
  Qed.

  Lemma rtli_determinate : forall ge : genv,
                             determinate (@mklts thread_labels intra_state (rtl_step' ge)).
Proof.
    Hint Resolve atomic_statement_determinate @atomic_statement_determinate_eq @map_val_of_eval_eq
    @map_vint_inj.

    intros ge u v v' l l' stepv stepv'.
    simpl in *.
    inv stepv. inv STEP; simpl in *; clarify;
    inv stepv'; inv STEP; simpl in *;
    try destruct sp; clarify; repeat hpc;
    try (by (intuition (repeat f_equal; eauto); simpl in *; clarify));
    (inv_step; inv_step; simpl in *; clarify; discr; repeat hpc; intuition (repeat (eauto; f_equal)); vauto); eauto;
    inv ASME; inv ASME0; simpl; hpc; intuition; now inv H.
  Qed.

  Definition rtl_ge_init (p: program) (ge:genv) (m: Mem.mem) : Prop :=
    Genv.globalenv_initmem p ge Ast.low_mem_restr m.

  Definition RtlInjectSem : SEM.
Proof.
  refine (mkSEM _ _ _ rtl_ge_init (@prog_main _ _) (@Genv.find_symbol _)
         rtl_step' rtl_inject_init
         _ rtli_receptive rtli_determinate).
  intros ge s. set (P := exists l', exists s', rtl_step' ge s l' s').
  destruct (classic P) as [H|H]; intuition.
  left. intros s' l' K. elim H. exists l'; exists s'. assumption.
  Defined.

End TSOSEM.

Section TRACES.

  Require Traces.

  Variable p : program.
  Variable args : list val.
  Variable t : Traces.trace event.
  Definition rtli_lts ge := mklts event_labels (TSO.step RtlInjectSem ge).
  Definition rtli_traces : Prop :=
    exists ge : genv,
      exists s : TSO.state RtlInjectSem,
        TSO.init RtlInjectSem p args ge s /\
        Traces.traces (rtli_lts ge) s t.

End TRACES.

Section LOWSIM.

  Variable ge : genv.

  Definition can_unbuffer (tso: tsomem) : Prop :=
    ∀ tid bi buf,
      tso.(TSOMemoryMachine.buffers) tid = buf ++ bi :: nil
      ∃m', ∃e',
        TSOMemoryMachine.buf_step tid tso.(shared_mem) bi e' m'.

  Definition progress (s: state) : Prop :=
    ∀ tid st,
      (snd s) ! tid = Some st
      ∃e, ∃s',
        astep ge s (tid, e::nil) s'
      ∧ (∀ bi, eTEtso (TSOunbuf bi))
      ∧ not_a_high_state st.

  Definition wf_load (s: state) : Prop :=
    ∀ tid, match (snd s) ! tid with
             | Some (RIInjectState _ _ sp _ _ _ (NormalState irs
                    (Sload _ addr args _) _)) =>
    ∀ p m v, eval_addressing ge sp addr (map irs args) = Some (Vptr p) →
           flush tid ((fst s).(TSOMemoryMachine.buffers) tid) (fst s) m
           load_ptr Mint32 m.(MemoryMachine.mem_rtl) p = Some v
           wf_val v
             | _ => True
           end.

  Definition reachable (i: state) : stateProp :=
    fun s => ∃tr, trace ge i tr s.

  Remark reachable_refl : reflexive _ reachable.
Proof.
intros x. exists nil. constructor. Qed.
  Remark reachable_trans: transitive _ reachable.
Proof.
intros x y z (tr1 & H1) (tr2 & H2).
         eexists. eapply trace_app; eauto.
  Qed.

  Definition can_write_and_free (s: state) : Prop :=
      ∀ tid, match (snd s) ! tid with
               | Some (RIInjectState _ _ sp _ _ _ (NormalState irs
                      (Sstore _ _ addr args src) k)) =>
    ∀ p, eval_addressing ge sp addr (map irs args) = Some (Vptr p) →
    (fst s).(TSOMemoryMachine.buffers) tid = empty_buffer
    load_ptr Mint32 (fst s).(MemoryMachine.mem_rtl) pNone
               | Some (RIState _ c (Some sp) pc _) =>
    ∀ res, c ! pc = Some (Ireturn res) →
    (fst s).(TSOMemoryMachine.buffers) tid = empty_buffer
    ∃ m', free_ptr sp MObjStack (fst s).(MemoryMachine.mem_rtl) = Some m'
        ∧ forall tid' p v b,
          (fst s).(TSOMemoryMachine.buffers) tid' = b ++ WBufItem p v :: nilstore_ptr Mint32 m' p vNone
               | _ => True
             end.

  Lemma may_store_may_load : ∀ m p v m',
                               store_ptr Mint32 m p v = Some m' →
                               load_ptr Mint32 m pNone.
Proof.
    intros m p v m' H K.
    pose proof (store_chunk_allocated_someD H).
    pose proof (load_chunk_allocated_noneD K).
    intuition.
  Qed.

  Lemma can_unbuffer_can_write_and_free i :
    (∀ s, reachable i scan_unbuffer (fst s)) →
    ∀ s, reachable i sprogress scan_write_and_free s.
Proof.
    intros SAFE (m & st) REACH PROGRESS tid. simpl.
    case_eq (st ! tid); trivial.
    intros ts Hst.
    case_eq ts; trivial.
    intros stk c [sp|] pc rs Hts; trivial.
    intros res Hpc Bemp.
    generalize (PROGRESS tid). intros P.
    destruct (P _ Hst) as (e & ts' & STEP & TSO & LOW).
    inv STEP; autorw'.
    2: eelim TSO; reflexivity.
    2: inv AS1; inv ST; autorw'.
    2: inv AS1; inv ST; autorw'.
    2: inv AS1; inv ST.
    2: inv AS1.
    inv AS1. inv ST; autorw'. eelim IS_not_mem; reflexivity.
    assert (reachable i (TSOMEM m (upd m.(TSOMemoryMachine.buffers) tid (FBufItem sp MObjStack ::nil)), st ! tid <- (RIRetState stk (rs res)))) as REACH'.
    apply reachable_trans with (m, st). assumption.
    eexists ((tid, _::nil)::nil). econstructor. econstructor.
    eapply astep_free. eassumption. reflexivity.
    eapply intra_step_mem. vauto. destruct m. vauto. easy. easy. easy.
    generalize (SAFE _ REACH'). intros X. edestruct (X tid) as (M & BS). simpl. rewrite upd_s. rewrite app_nil_l. reflexivity. clear X.
    simpl in *.
    exists M.(MemoryMachine.mem_rtl). split.
    destruct BS. inv H. simpl. assumption.
    intros tid' p v b H K.
    assert (reachable i (TSOMEM M (upd (upd (TSOMemoryMachine.buffers m) tid (FBufItem sp MObjStack :: nil)) tid empty_buffer), st ! tid <- (RIRetState stk (rs res)))) as REACH''.
    eapply reachable_trans. apply REACH'.
    destruct BS as (e'' & BS).
    eexists ((tid, _::nil)::nil). econstructor. econstructor.
    eapply astep_unbuf. eapply tso_step_unbuf. reflexivity. rewrite upd_s. rewrite app_nil_l. reflexivity. eassumption.
    assert (tidtid'). intros ->. autorw'. unfold empty_buffer in *. app_inv.
    generalize (SAFE _ REACH''). intros X. edestruct (X tid') as (M' & BS'). simpl.
    rewrite upd_o;trivial. rewrite upd_o;trivial. autorw'.
    simpl in *.
    destruct BS' as (ee & BS').
    inv BS'. simpl in *. autorw'.
    intros stk c sp next rs edst is Hts.
    case_eq is; trivial.
    intros irs stmt cont His.
    case_eq stmt; trivial.
    intros release ap addr args dst Hstmt p EVAL Bemp K.
    generalize (PROGRESS tid). intros P.
    destruct (P _ Hst) as (e & ts' & STEP & TSO & LOW).
    inv STEP; autorw'.
    2: eelim TSO; reflexivity.
    2: inv AS1; inv ST; inv INJECT.
    2: inv AS1; inv ST; inv INJECT.
    2: inv AS1; inv ST; inv INJECT.
    2: inv AS1; inv INJECT.
    inv AS1. inv ST; inv INJECT; eelim IS_not_mem; reflexivity.
    inv ST. inv INJECT. autorw'.
    assert (∃s', reachable i s' ∧
     (fst s').(MemoryMachine.mem_rtl) = m.(MemoryMachine.mem_rtl) ∧
     (fst s').(TSOMemoryMachine.buffers) tid =
                 WBufItem p (irs dst) :: nil)
    as ONE.
    eexists. split.
    apply reachable_trans with (m, st). assumption.
    eexists ((tid, _::nil)::nil). econstructor. econstructor.
    eapply astep_free. eassumption. reflexivity.
    eapply intra_step_mem. vauto. eassumption. easy. easy. easy. split;
    simpl; inv ES.
    destruct release. inv TM3. reflexivity. subst. reflexivity.
    simpl. rewrite upd_s. simpl in *. autorw'.
    destruct ONE as ((s' & st') & REACH' & MEM & BUF).
    generalize (SAFE _ REACH'). intros X. edestruct (X tid) as (M & BS).
    autorw'. rewrite app_nil_l. reflexivity.
    destruct BS as (e & BS).
    destruct m. inv BS. simpl in *. autorw'.
    destruct s' as ((s' & s'd) & ?). simpl in *. clarify. inv ES.
    exploit may_store_may_load; eauto.
    Qed.

  Inductive safe_buf t : bufferMemoryMachine.memProp :=
  | SBnil m : safe_buf t nil m
  | SBsnoc m buf bi m' e
      (UNB: TSOMemoryMachine.buf_step t m bi e m')
      (SB: safe_buf t buf m')
    : safe_buf t (buf ++ bi :: nil) m.

  Lemma can_unbuffer_safe' {i tid} :
    (∀ s, reachable i scan_unbuffer (fst s)) →
    ∀ buf,
    ∀m t, reachable i (m,t) →
        m.(TSOMemoryMachine.buffers) tid = buf
        safe_buf tid buf m.(shared_mem).
Proof.
    intros SAFE.
    refine (rev_ind _ _ _). vauto.
    intros bi buf IH m t REACH EQB.
    generalize (SAFE _ REACH tid). intros K.
    destruct m as (m & B).
    destruct (K _ _ EQB) as (m' & H).
    generalize (IH (TSOMEM m' (upd B tid buf)) t). simpl in *.
    destruct H as (e' & H).
    intros F. clear IH.
    econstructor; eauto. apply F.
    apply reachable_trans with (TSOMEM m B, t); auto.
    2: apply upd_s.
    eexists. eapply trace_cons. apply trace_nil.
    eapply astep_unbuf. vauto.
  Qed.
  Corollary can_unbuffer_safe i :
    (∀ s, reachable i scan_unbuffer (fst s)) →
    ∀ s t, reachable i (s,t) →
         ∀ tid, safe_buf tid (s.(TSOMemoryMachine.buffers) tid) s.(shared_mem).
Proof.
intros H s t H0 tid. eapply can_unbuffer_safe'; eauto. Qed.

  Definition l_state : Type := (tso_state * PTree.t intra_state)%type.
  Definition l_step : l_statefulleventl_stateProp := TSO.step RtlInjectSem ge.

  Inductive match_bi : buf_itembuffer_itemProp :=
  | MBIW p v
    : match_bi (WBufItem p v) (BufferedWrite p Mint32 v)
  | MBIA p i k
    : match_bi (ABufItem p i k) (BufferedAlloc p i k)
  | MBIF p k
    : match_bi (FBufItem p k) (BufferedFree p k)
  .

  Definition match_buf : (thread_idbuffer) → buffersProp :=
    fun x y => ∀ t, lift_forall_list match_bi (rev (x t)) (y t).

  Definition match_mem : MemoryMachine.memmemProp :=
    fun x y => MemoryMachine.mem_rtl x = y.

  Remark match_bi_abi {a b m n t buf} :
    match_bi a b
    match_mem m n
    safe_buf t (buf ++ a :: nil) m
    forall {n'}, apply_buffer_item b n = Some n' →
    ∃ m', unbuffer t (m, buf ++ a :: nil) (m', buf)
    ∧ match_mem m' n'
    ∧ safe_buf t buf m'
  .
Proof.
    inversion 1; subst; simpl; intros MEM SAFE n' U.
    destruct m as (m & P); inv MEM.
    inv SAFE; app_inv. inv UNB. simpl in U. autorw'.
    eexists. split. vauto.
    econstructor; eauto.
    econstructor; eauto.
    destruct m; inv MEM.
    inv SAFE; app_inv. inv UNB. simpl in U. autorw'.
    eexists. split. vauto. split; vauto.
    destruct m; inv MEM.
    inv SAFE; app_inv. inv UNB. simpl in U. autorw'.
    eexists. split. vauto. split; vauto.
  Qed.

  Definition safe_tsomem : tsomemProp :=
    fun M => ∀ t, safe_buf t (M.(TSOMemoryMachine.buffers) t) M.(shared_mem).

  Definition safe_state : stateProp :=
    fun Mts => safe_tsomem (fst Mts) ∧ progress Mtswf_load Mtscan_write_and_free Mts.

  Remark flush_ab {a b t} :
    match_buf a b
    forall {m n}, match_mem m n
    safe_tsomem (TSOMEM m a) →
    forall {n'}, apply_buffer (b t) n = Some n' →
    ∃ m',
      flush t (a t) m m'
    ∧ match_mem m' n'
  .
Proof.
    intros BUF m n MEM SAFE.
    generalize (SAFE t). simpl. clear SAFE.
    rewrite <- (rev_involutive (a t)).
    generalize dependent m. generalize dependent n.
    generalize (BUF t). clear BUF.
    generalize (rev (a t)). generalize (b t).
    induction 1. simpl. intros ? ? ? _ ? K; inv K. eexists; intuition eauto. vauto.
    simpl. intros n m MEM SAFE n' K.
    case_eq (apply_buffer_item y n);[intros M'|]; intros Q; autorw'. simpl in K.
    destruct (match_bi_abi HEAD MEM SAFE Q) as (m' & A & B & C).
    destruct (IHlift_forall_list _ _ B C _ K) as (m'' & A' & B'). clear IHlift_forall_list.
    eexists. split. 2: apply B'.
    vauto.
  Qed.

  Inductive match_state : statel_stateProp :=
  | MS m m' buf buf' ts
       (MEM: match_mem m m')
       (BUF: match_buf buf buf')
    : match_state (TSOMEM m buf, ts) (mktsostate buf' m', ts)
  .

  Definition match_ev : thread_eventfulleventProp :=
    fun te e =>
      match te with
        | TEext f => e = Evisible f
        | TEend ReturnVoid
        | TEend FailEvent => e = Evisible Efail
        | TEbegin BeginHigh => False
        | _ => e = Etau
      end.

  Definition progress' (s: state) : Prop :=
    ∀ tid,
      match (snd s) ! tid with
        | Some (RIInjectState stk c sp pc rs dst
               (NormalState irs (Sload ap addr args res) k)) =>
      ∀ p, eval_addressing ge sp addr (map irs args) = Some (Vptr p) →
        wf_ptr p
      ∧ ∀ m' perms, flush tid ((fst s).(TSOMemoryMachine.buffers) tid) (fst s).(shared_mem) (MemoryMachine.MEM m' perms) →
       (match ap with Local => readable_perm perms p tid
                   | Global => ∀ t, perms p = HiddenBy ttid = t end)
     ∧ (∃v, wf_val v
            if addr_in_buf p ((fst s).(TSOMemoryMachine.buffers) tid)
            then buf_load p ((fst s).(TSOMemoryMachine.buffers) tid) = Some v
            else MemoryMachine.mem_step tid (fst s) (MEread ap false p v) (fst s))
     ∧ (∀ x k, ¬ In (FBufItem x k) ((fst s).(TSOMemoryMachine.buffers) tid))
        | Some (RIInjectState _ _ _ _ _ _
               (NormalState irs (Satomicmem r cas args dst) k)) =>
       ∃ instr, ∃ p, ∃ v, atomic_statement_mem_event r cas (map irs args) v (MErmw r p v instr)
       ∧ wf_rmw instr
       ∧ wf_ptr p
       ∧ load_ptr Mint32 (fst s).(MemoryMachine.mem_rtl) p = Some vwf_val v
       ∧ ∃m', store_ptr Mint32 (fst s).(MemoryMachine.mem_rtl) p (rmw_instr_semantics instr v) = Some m'
       ∧ ∃d', (if r then release tid (fst s).(MemoryMachine.perms) d' else (fst s).(MemoryMachine.perms)=d') ∧ d' p = empty_perm
        | Some (RIInjectState stk c sp pc rs dst
               (NormalState irs (Srequestperm rp addr args) k)) =>
      ∀ p, eval_addressing ge sp addr (map irs args) = Some (Vptr p) →
      ∃ perm',
        perm_step tid (fst s).(MemoryMachine.perms) (PErequest rp p) perm'
        | Some (RIInjectState stk c sp pc rs dst
               (NormalState irs Srelease k)) =>
      ∃ perm',
        perm_step tid (fst s).(MemoryMachine.perms) PErelease perm'
        | Some (RIInjectState stk c sp pc rs dst
               (NormalState irs (Sstore released ap addr args src) k)) =>
      (∀ p, eval_addressing ge sp addr (map irs args) = Some (Vptr p) →
            check_perm_store tid (fst s).(MemoryMachine.perms) ap pwf_ptr p)
      ∧
      if released thenperm',
        perm_step tid (fst s).(MemoryMachine.perms) PErelease perm'
      else True
        | Some (RIInjectState stk c sp pc rs dst
               (NormalState irs Sfreeperm k)) =>
      ∃ perm',
        perm_step tid (fst s).(MemoryMachine.perms) PEfreeperm perm'
        | _ => True
      end.

  Remark progress_progress' (s: state) :
    progress sprogress' s.
Proof.
    intros P tid.
    destruct s as (((m & perm) & B) & st). simpl.
    case_eq (st ! tid). 2: easy.
    intros ts H.
    generalize (P _ _ H). clear P.
    intros (e & ts' & STEP & TSO & LOW).
    inv STEP; try (inv AS1; try inv ST; try inv INJECT; autorw');
    try (eelim IS_not_mem; reflexivity).
    intros ? ?; clarify. inv ES.
    case_eq (addr_in_buf p (B tid)); intros K; autorw'.
      intuition.
      pose proof (flush_preserves_perm H2); simpl in *; subst.
      auto.
      exists v. intuition.
      inv TM2; split; auto; intros m' perms H;
      pose proof (flush_preserves_perm H); simpl in *; subst;
      intuition.
      exists v. intuition. vauto.
    exists v. intuition. vauto.
    split. intros ? ?; clarify. inv ES. split; assumption.
    destruct released; trivial.
    inv ES. inv TM3. eexists; eassumption.
    intros ? ?; clarify. inv ES. inv TM1.
    eexists; eauto.
    inversion ASME; (inv ES; clarify; try now (destruct bi; clarify));
      (eexists; eexists; eexists; split;[autorw'; eassumption|]).
    inv TM2. intuition. eexists; intuition eauto.
    inv ES. inv TM1.
    eexists; eauto.
    inv ES. inv TM1.
    eexists; eauto.
    eelim TSO; reflexivity.
  Qed.

  Lemma safe_not_stuck s tso st tid ts :
    safe_state s
    match_state s (tso, st) →
    st ! tid = Some ts
    ¬ ∀ ts' ev, ¬ rtl_step' ge ts ev ts'.
Proof.
    destruct s as (s & st').
    intros (SAFE_MEM & PROGRESS & _) MS' Gtid K; inv MS'.
    destruct (PROGRESS _ _ Gtid) as (s' & e & H & TSO & LOW).
    inv H. autorw'. inv AS1.
    inv ST; try (eelim IS_not_mem; reflexivity); clarify.
    eelim K; vauto.
    eelim K; vauto.
    eelim K; vauto.
    eelim K; vauto.
    eelim K; vauto.
    eelim K; vauto.
    eelim K; vauto.
    eelim K; vauto.
    eelim K. econstructor; eauto. eapply RTLI_return_external with (res := res); eauto. reflexivity.
    eelim K; vauto.
    eelim K; vauto.
    eelim K; econstructor; eauto. eapply RTLI_inject_start_low; eauto. reflexivity.
    eelim K; econstructor; eauto. eapply RTLI_inject_start_low; eauto. reflexivity.
    inv INJECT; try (eelim IS_not_mem; reflexivity); try now (simpl in LOW; clarify);
    eelim K;
    (econstructor; eauto; [eapply RTLI_inject_step; eauto ; vauto | reflexivity]).
    inv INJECT. eelim K. econstructor; eauto. vauto. reflexivity.
    eelim K; vauto. eelim K; vauto.

    inv ST.
    eelim K; econstructor; eauto. eapply RTLI_fun_internal_alloc with (sp := sp); eauto. reflexivity.
    eelim K; vauto.
    inv INJECT; try (now simpl in LOW; clarify; autorw');
    try (eelim K;
    (econstructor; eauto; [eapply RTLI_inject_step; eauto ; vauto | reflexivity])).
    eelim TSO; reflexivity.
    inv AS1. inv ST. 2: inv INJECT.
    autorw'. eelim K. vauto.
    inv AS1. inv ST. 2: inv INJECT.
    autorw'. eelim K; vauto.
    inv AS1. inv ST. 2: inv INJECT.
    autorw'. eelim K; vauto.
    autorw'. inv AS1. inv INJECT.
    simpl in LOW; clarify.
  Qed.

  Definition bw_step_spec : Prop :=
    ∀ s t ev t',
      evEoutofmemory
      safe_state s
      match_state s t
      l_step t ev t' →
      ∃tid, ∃e, ∃s',
        astep ge s (tid, e::nil) s'
      ∧ match_ev e ev
      ∧ match_state s' t'
  .

  Lemma bw_step : bw_step_spec.
Proof.
    intros s t ev t' NOTOOM (SAFE & PROGRESS & WFL & WRFR) MS' STEP.
    inv STEP.
    inv tidSTEP.
    inv STEP; try (simpl in TE; inv TE; clarify; fail).
    inv TE.
    inv MS'; inv tsoSTEP;
    unfold RtlInjectSem in *; simpl in *.
    exists tid. exists (TEtso (INJECT.TSOmem (MEalloc sp f.(fn_stacksize) MObjStack))).
    eexists. split.
    eapply astep_free; eauto; try congruence. eapply intra_step_mem. vauto.
    econstructor; eauto.
    split. easy. split. vauto.
    unfold tupdate. intros t'. destruct peq as [-> | NE]. rewrite upd_s. unfold push_item.
    simpl. apply lfl_snoc. vauto.
    rewrite upd_o; intuition; apply BUF.

    inv TE.
    inv MS'; inv tsoSTEP;
    unfold RtlInjectSem in *; simpl in *.
    exists tid. exists (TEtso (INJECT.TSOmem (MEfree sp MObjStack))).
    eexists. split.
    eapply astep_free; eauto; try congruence. eapply intra_step_mem. vauto.
    econstructor; eauto.
    split. easy. split. vauto.
    unfold tupdate. intros t'. destruct peq as [-> | NE]. rewrite upd_s. unfold push_item.
    simpl. apply lfl_snoc. vauto.
    rewrite upd_o; intuition; apply BUF.

    inv INJECT; try (elim EV; clarify); simpl in *; try clarify.
    inv MS'. inv tsoSTEP.
    destruct (flush_ab BUF MEM SAFE AB) as (M & FLUSH & MM).
    exists tid. exists (TEtso (INJECT.TSOmem (MEread ap (addr_in_buf a (buf tid)) a v))).
    destruct m as (m & d). destruct M as (M & D). inv MM. inv MEM.
    pose proof (flush_preserves_perm FLUSH) as X; simpl in X.
    pose proof (WFL tid) as WFL'. simpl in *. autorw'.
    pose proof (WFL' _ _ _ (eq_refl _) FLUSH LD) as WFV.
    clear WFL WFL'.
    eexists. split.
    eapply astep_free; eauto; try congruence. eapply intra_step_mem. vauto.
    generalize (progress_progress' _ PROGRESS tid). simpl. autorw'.
    intros H. generalize (H _ (eq_refl _)). clear H.
    intros (H & K). generalize (K _ _ FLUSH). clear K. simpl in *.
    intros (K & (v' & L & L') & FR).
    eapply TSOMemoryMachine.tso_step_load; vauto.
    pose proof (read_as_if_flush tid ap false (buf tid) _ _ a v FLUSH) as Y.
    case_eq (addr_in_buf a (buf tid)); intros; autorw'.
    assert (Some v' = Some v). apply Y. destruct ap; vauto. clarify.
    assert (v' = v). exploit Y. destruct ap; econstructor; auto.
    inversion 1; inv L'; autorw'. clarify.

    split. easy. vauto.

    inv MS'. inv tsoSTEP. clear EV.
    exists tid. exists (TEtso (INJECT.TSOmem (MEwrite released ap a (rs0 src)))).
    generalize (progress_progress' _ PROGRESS tid). simpl. autorw'.
    destruct released.
    destruct m as (m & perm).
    intros (PS' & perm' & Hperm').
    destruct (PS' _ (eq_refl _)) as (PS & WFP).
    eexists (TSOMEM (MemoryMachine.MEM m perm') (upd buf tid (WBufItem a (rs0 src) :: buf tid)), _).
    split.
    eapply astep_free; eauto. eapply intra_step_mem. vauto.
    eapply TSOMemoryMachine.tso_step_write; vauto.
    easy. easy. easy. split. easy.
    econstructor; eauto.
    intros t. unfold tupdate. destruct peq as [->|NE]. rewrite upd_s. simpl.
    apply lfl_snoc. split. auto. vauto. rewrite upd_o; auto.
    intros (PS' & _).
    destruct (PS' _ (eq_refl _)) as (PS & WFP).
    eexists (TSOMEM m (upd buf tid (WBufItem a (rs0 src) :: buf tid)), _).
    split.
    eapply astep_free; eauto. eapply intra_step_mem. vauto.
    eapply TSOMemoryMachine.tso_step_write; vauto.
    easy. easy. easy. split. easy.
    econstructor; eauto.
    intros t. unfold tupdate. destruct peq as [->|NE]. rewrite upd_s. simpl.
    apply lfl_snoc. split. auto. vauto. rewrite upd_o; auto.

    inv ASME. inv MS'. inv tsoSTEP; clarify. simpl in *.
    assert (buf tid = nil).
    generalize (BUF tid). rewrite Bemp. inversion 1.
    destruct (buf tid). easy. simpl in *. app_inv.
    generalize (progress_progress' _ PROGRESS tid). simpl. autorw'.
    intros (instr & q & w & AS & WF & WFP & LD' & WFV & M & ST' & d' & K & K').
    inv MEM. inversion AS; subst. rewrite <- H2 in H0. clarify. autorw'.
    destruct m.
    exists tid. eexists (TEtso (INJECT.TSOmem _)).
    eexists. split. eapply astep_free; eauto. eapply intra_step_mem; eauto. vauto. simpl in *.
    eapply TSOMemoryMachine.tso_step_rmw; vauto. easy. easy. easy. split. easy. vauto.

    inv MS'. inv tsoSTEP. simpl in *.
    assert (buf tid = nil).
    generalize (BUF tid). rewrite Bemp. inversion 1.
    destruct (buf tid). easy. simpl in *. app_inv.
    exists tid. exists (TEtso TSOfence).
    eexists. split. eapply astep_free; eauto.
    eapply intra_step_mem; eauto. vauto. vauto. easy. easy. easy.
    split. easy.
    vauto.

    inv MS'. inv tsoSTEP. simpl in *.
    assert (buf tid = nil).
    generalize (BUF tid). rewrite Bemp. inversion 1.
    destruct (buf tid). easy. simpl in *. app_inv.
    exists tid. exists (TEtso TSOfence).
    eexists. split. eapply astep_free; eauto.
    eapply intra_step_mem; eauto. vauto. vauto. easy. easy. easy.
    split. easy.
    vauto.

    inv tidSTEP; inv MS'. inv STEP; try inv INJECT; try inv ASME; simpl in TE; clarify; try (eelim EV; clarify);
    (exists tid; eexists; eexists;
      (try now split;[econstructor;eauto;try (econstructor; eauto); vauto; easy|split;vauto])
    ).

    inv tsoSTEP; inv MS'. generalize (SAFE t). simpl in *.
    generalize (BUF t). rewrite EQbufs. intros K; inv K.
    assert (I := rev_last_eq (eq_sym _ _ _ H0)). rewrite I. intros K.
    destruct (match_bi_abi HEAD MEM K AB) as (n & A & B & C). inv A. app_inv.
    exists t. eexists (TEtso (TSOunbuf _)).
    eexists (TSOMEM n _, st). split. vauto.
    split. vauto.
    econstructor; eauto.
    intros t'. unfold tupdate. destruct peq as [->|NE]. rewrite upd_s.
    rewrite rev_involutive. auto. rewrite upd_o; auto.

    inv MS'.
    inv tidSTEP. inv STEP; try inv INJECT;
                 try (simpl in TE; solve by inversion);
    try now (exists tid; exists TEtau; eexists; split; [eapply astep_free; eauto; try easy; eapply intra_step_not_mem; eauto; vauto | vauto]).
    now (exists tid; exists (TEbegin BeginLow); eexists; split; [eapply astep_free; eauto; try easy; vauto | vauto]).
    destruct m. unfold RtlInjectSem in *.
    generalize (progress_progress' _ PROGRESS tid). simpl in *.
    rewrite Gtid. intros Q; destruct (Q _ H) as (p' & Hp').
    exists tid; eexists (TEtso (INJECT.TSOmem _)); eexists; split; [eapply astep_free; eauto; try easy; eapply intra_step_mem; eauto; vauto | vauto].

    inv ASME; clarify.

    (exists tid; eexists (TEend (ReturnEvent _)); eexists; split; [eapply astep_free; eauto; try easy; vauto | vauto]). econstructor; eauto.
    vauto. easy.

    exists tid. exists (TEtso (INJECT.TSOmem (MEperm PErelease))).
    destruct m.
    eexists (TSOMEM _ _, _). split.
    eapply astep_free; eauto.
    eapply intra_step_mem. vauto.
    eapply tso_step_perm.
    econstructor. econstructor. apply release_func. reflexivity.
    easy. easy. easy. intuition. vauto. vauto.

    exists tid. exists (TEtso (INJECT.TSOmem (MEperm PEfreeperm))).
    generalize (progress_progress' _ PROGRESS tid). simpl in *.
    autorw'. intros (perm' & Hperm). destruct m.
    eexists (TSOMEM (MemoryMachine.MEM _ _) _, _). split.
    eapply astep_free; eauto.
    eapply intra_step_mem. vauto.
    eapply tso_step_perm. vauto.
    easy. easy. easy. intuition. vauto.

    (exists tid; eexists (TEend (ReturnEvent _)); eexists; split; [eapply astep_free; eauto; try easy; vauto | vauto]). econstructor; eauto.
    vauto. easy.

    inv tidSTEP; inv MS'. inv STEP; try inv INJECT; try inv ASME; simpl in TE; clarify; try (eelim EV; clarify).
    inv tsoSTEP. inv MEM.
    exists tid. eexists. eexists. split.
    eapply astep_spawn; eauto; vauto. split. easy.
    econstructor; eauto. vauto.
    intros t'. unfold tupdate. destruct peq as [->|NE]. rewrite upd_s.
    vauto. rewrite upd_o. vauto. congruence.

    inv tidSTEP; inv MS'. inv STEP; try inv INJECT; try inv ASME; simpl in TE; clarify; try (eelim EV; clarify).
    exists tid. eexists. eexists. split.
    eapply astep_spawn_fail; eauto; vauto. vauto.

    inv tidSTEP; inv MS'. inv STEP; try inv INJECT; try inv ASME; simpl in TE; clarify; try (eelim EV; clarify).
    inv tsoSTEP. inv MEM.
    exists tid. eexists. eexists. split.
    eapply astep_exit; eauto; vauto. vauto.

    apply False_ind.
    inv tidSTEP. inv tsoSTEP. inv STEP; clarify. inv INJECT; try inv ASME; try now clarify.
    simpl in TE. inv TE. clear EV. inv MS'. simpl in *. inv MEM.
    assert (buf tid = nil) as B.
    generalize (BUF tid). autorw'. inversion 1. destruct (buf tid); trivial; simpl in *. app_inv.
    assert (flush tid (buf tid) m m) as FLUSH. autorw'. vauto.
    generalize (progress_progress' _ PROGRESS tid). simpl. autorw'.
    intros H. generalize (H _ (eq_refl _)). clear H.
    intros (? & K). destruct m. generalize (K _ _ FLUSH). clear K.
    intros (? & (v & L & M) & N). simpl in *.
    inv M; autorw'.

    apply False_ind.
    inv tidSTEP. inv STEP; try inv INJECT; try inv ASME; clarify. inv TE. clear EV. inv MS'. inv tsoSTEP. simpl in *.
    assert (buf tid = nil).
    generalize (BUF tid). rewrite Bemp. inversion 1.
    destruct (buf tid). easy. simpl in *. app_inv.
    generalize (WRFR tid). simpl. autorw'. intros K.
    inv MEM.
    exact (K _ (eq_refl _) (eq_refl _) LD).

    apply False_ind.
    inv tidSTEP. inv STEP; try inv INJECT; try inv ASME; clarify. inv TE. inv MS'. inv tsoSTEP. simpl in *.
    assert (buf tid = nil).
    generalize (BUF tid). rewrite Bemp. inversion 1.
    destruct (buf tid). easy. simpl in *. app_inv.
    generalize (WRFR tid). simpl. autorw'. intros K.
    inv MEM.
    destruct (K _ (eq_refl _) (eq_refl _)) as (? & ? & K').
    autorw'. destruct FAIL as (tid' & p & ch & v & b & HB & HS).
    generalize (BUF tid'). rewrite HB. inversion 1. subst. inv HEAD.
    symmetry in H3.
    apply rev_last_eq in H3.
    now elim (K' tid' p v (rev xl)).

    apply False_ind.
    inv tidSTEP. inv STEP; try inv INJECT; try inv ASME; clarify. inv TE. clear EV.
    inv tsoSTEP. inv MS'. simpl in *. inv MEM.
    assert (flush tid (buf tid) m m) as FLUSH.
    replace (buf tid) with (@nil buf_item). vauto.
    generalize (BUF tid). autorw'. inversion 1. destruct (buf tid); trivial; simpl in *. app_inv.
    generalize (progress_progress' _ PROGRESS tid). simpl. autorw'.
    intros (instr & q & w & AS & WF & WFP & LD' & WFV & M & ST' & d' & K & K').
    inv AS. rewrite <- H in H1. clarify. autorw'.

    apply False_ind.
    eapply safe_not_stuck; eauto. split; intuition.

    elim NOTOOM; reflexivity.

    inv tidSTEP. inv STEP; try inv INJECT; try inv ASME; clarify.
    inv tidSTEP. inv STEP; try inv INJECT; try inv ASME; clarify.
    inv tidSTEP. inv STEP; try inv INJECT; try inv ASME; clarify.
    inv tidSTEP. inv STEP; try inv INJECT; try inv ASME; clarify.
    inv tidSTEP. inv STEP; try inv INJECT; try inv ASME; clarify.
    inv tidSTEP. inv STEP; try inv INJECT; try inv ASME; clarify.
  Qed.

  Lemma bw_taustar :
      ∀ j j',
        taustar (rtli_lts ge) j j' →
        ∀ i,
          match_state i j
          (∀ s, reachable i scan_unbuffer (fst s) ∧ progress swf_load s) →
        ∃ tr, ∃ i',
           low_trace ge i tr i' ∧ filter_fullevent tr = nilmatch_state i' j'.
Proof.
    unfold rtli_lts. simpl.
    induction 1.
    intros i H _. exists nil. exists i. simpl. intuition. split. vauto. intuition.
    simpl in *.
    intros i MS SAFE.
    assert (EtauEoutofmemory) as zz by discriminate.
    assert (safe_state i) as yy.
    destruct (SAFE i (reachable_refl _)).
    split. intros tid. destruct i; simpl. eapply (can_unbuffer_safe). eapply SAFE. eapply reachable_refl. intuition.
    apply (can_unbuffer_can_write_and_free i). eapply SAFE. apply reachable_refl. assumption.
    destruct (bw_step _ _ _ _ zz yy MS H) as (tid & e & i' & STEP & ME & MS').
    assert (∀ s, reachable i' scan_unbuffer (fst s) ∧ progress swf_load s) as SAFE'.
      intros u v. apply SAFE. apply reachable_trans with i'; trivial. eexists. vauto.
    destruct (IHtaustar _ MS' SAFE') as (tr & i'' & (TR & LOW) & TAU & MS'').
    exists (tr ++ (tid, e::nil)::nil). exists i''. split. split. apply trace_app with i'. vauto. trivial.
    intros t'. rewrite in_app_iff. intros [K|K]. exact (LOW t' K). inv K; clarify.
    split. rewrite filter_fullevent_app, TAU. simpl. destruct e; clarify.
    assumption.
  Qed.

  Lemma bw_fintrace :
    ∀ j trace j',
      Traces.fintrace (rtli_lts ge) j trace j' →
      ∀ i,
        match_state i j
        (∀ s, reachable i scan_unbuffer (fst s) ∧ progress swf_load s) →
        ∃ tr, ∃ i',
           low_trace ge i tr i' ∧ filter_fullevent tr = rev tracematch_state i' j'.
Proof.
    unfold rtli_lts. simpl.
    induction 1. clarify.
    now eauto using bw_taustar.
    simpl in *. clarify.
    intros i MS SAFE.
    destruct TS as (si & TAU & STEP). simpl in *.
    destruct (bw_taustar _ _ TAU _ MS SAFE) as (ti & ii & (X & LOWi) & TAUi & MSi).
    assert (Evisible evEoutofmemory) as zz by discriminate.
    assert (reachable i ii) as tt. now exists ti.
    assert (safe_state ii) as yy.
    split. intros tid. destruct ii; simpl. eapply can_unbuffer_safe. eapply SAFE. eassumption.
    repeat split; try now eapply SAFE. eapply can_unbuffer_can_write_and_free. 2: eassumption. eapply SAFE.
    now eapply SAFE.
    destruct (bw_step _ _ _ _ zz yy MSi STEP) as (tid & e & i'' & STEP'' & ME & MS'').
    assert (reachable i i''). eapply reachable_trans with ii. trivial. exists ((tid, e::nil)::nil). vauto.
    destruct (IHfintrace _ MS'') as (L' & i' & (X' & LOWi') & ME' & MS').
    intros q Q. apply SAFE. eapply reachable_trans with i''; trivial.
    exists (L' ++ ((tid, e::nil) :: nil) ++ ti).
    exists i'. intuition. split. eapply trace_app; eauto. eapply trace_app; eauto. vauto.
    intros t'. rewrite in_app_iff. rewrite in_app_iff. simpl. intros [K|[[K|K]|K]]; clarify.
    exact (LOWi' t' K). exact (LOWi t' K).
    repeat rewrite filter_fullevent_app.
    rewrite ME', TAUi. destruct e; try destruct be; try destruct e; clarify. 2: congruence.
    simpl.
    inv ME.
    reflexivity.
    inv ME. elim EV.
    reflexivity.
  Qed.

End LOWSIM.

Definition init (p: program) (ge: genv) (s: state) : Prop :=
  (∀ p, (fst s).(MemoryMachine.perms) p = empty_perm)
∧ (∀ tid, (fst s).(TSOMemoryMachine.buffers) tid = nil)
∧ (TSO.init RtlInjectSem p nil ge (mktsostate (fun _ => nil) (fst s).(MemoryMachine.mem_rtl), snd s)).

Definition safe_program (p: program) : Prop :=
  ∀ ge s,
    init p ge s
    ∀ s', reachable ge s s' → can_unbuffer (fst s') ∧ progress ge s' ∧ wf_load ge s'.

Inductive low_traces (p: program) : Traces.trace eventProp :=
| LTr ge i f tr trf t
      (INIT: init p ge i)
      (TRACE: low_trace ge i tr f)
      (FILTER: trf = rev (filter_fullevent tr))
      (NOFAIL: ¬In Efail trf)
      (TEQ: Traces.appt trf Traces.Send = t)
  : low_traces p t
| LTrF ge i f f' tr trf t t' x fe
      (INIT: init p ge i)
      (TRACE: low_trace ge i tr f)
      (FILTER: trf = rev (filter_fullevent tr))
      (NOFAIL: ¬In Efail trf)
      (FAILSTEP: astep ge f (x, (fe::nil)) f')
      (FAIL: fe = TEext Efailfe = TEend FailEventfe = TEend ReturnVoid)
      (TEQ: Traces.appt trf t' = t)
  : low_traces p t
.

Lemma init_ex p ge s :
  TSO.init RtlInjectSem p nil ge s
  ∃ s', init p ge s' ∧ match_state s' s.
Proof.
  destruct s as (m & st).
  intros (mainst & maintid & im & mptr & GE & FS & I & LTS).
  exists (TSOMEM (MemoryMachine.MEM im (fun _ => empty_perm)) (fun _ => nil), st).
  split. split. easy. split. easy. simpl. exists mainst. exists maintid. exists im.
  exists mptr. intuition. f_equal. simpl. clarify.
  vauto.
Qed.

Inductive tfin : Traces.trace event -> Prop :=
  | tfin_end: tfin Traces.Send
  | tfin_cons x t:
      tfin ttfin (Traces.Scons x t)
.

Lemma fintrace_no_fail {ge j trace j'} :
  Traces.fintrace (rtli_lts ge) j trace j' →
  ¬ In Efail trace.
Proof.
  induction 1; subst. intuition.
  intros [K|K]; intuition.
Qed.

Lemma bw_sim p :
  safe_program p
  ∀ trace, rtli_traces p nil trace
           tfin trace
           low_traces p trace.
Proof.
  intros SAFE trace (ge & j & J & TR) FIN.
  inv TR.
  destruct (init_ex _ _ _ J) as (i & I & MS).
  pose proof (SAFE _ _ I) as S.
  destruct (bw_fintrace ge _ _ _ PREF i MS S) as (tr & i' & TR & EV & _).
  econstructor; eauto. rewrite EV. rewrite rev_involutive. eapply fintrace_no_fail; eassumption.
  now autorw'; rewrite rev_involutive.

  destruct (init_ex _ _ _ J) as (i & I & MS).
  pose proof (SAFE _ _ I) as S.
  destruct (bw_fintrace ge _ _ _ PREF i MS S) as (tr & i' & TR & EV & MSi).
    assert (Evisible EfailEoutofmemory) as zz by discriminate.
    inv TR.
    assert (reachable ge i i') as tt. now exists tr.
    assert (safe_state ge i') as yy.
    split. intros tid. destruct i'; simpl. eapply can_unbuffer_safe. eapply S. eassumption.
    repeat split; try now eapply S. eapply can_unbuffer_can_write_and_free. 2: eassumption. eapply S.
    now eapply S.
    destruct (bw_step ge _ _ _ _ zz yy MSi FAIL) as (tid & e & i'' & STEP'' & ME & MS'').
    assert (reachable ge i i''). eapply reachable_trans with i'. trivial. exists ((tid, e::nil)::nil). vauto.
  eapply LTrF; eauto. split.
  eapply trace_app. eassumption. vauto. intuition. simpl.
  rewrite EV. rewrite rev_involutive. eapply fintrace_no_fail; eassumption.
  destruct e; try destruct be; try destruct e; try destruct ev; clarify; intuition.
  now simpl; autorw'; rewrite rev_involutive.

  apply False_ind. clear -FIN. induction l; inv FIN. intuition.
  apply False_ind. clear -FIN. induction l; inv FIN. intuition.

  apply False_ind. clear J. generalize dependent j. induction FIN; inversion 1. subst. eauto.
Qed.