Module RefinesRules


Require Import 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.
Require Import RefinesDefs AllRefinesRulesAux.
Require Import RefinesUtils.
Import Bigstep.

Lemma refines_refl : forall stmt, refines stmt stmt.
Proof.
  unfold refines; intros.
  auto.
Qed.


Lemma refines_trans : forall stmt1 stmt2 stmt3,
  refines stmt1 stmt2 -> refines stmt2 stmt3 -> refines stmt1 stmt3.
Proof.
  unfold refines; intros.
  eauto.
Qed.

Hint Resolve ext_trace_nil.

Hint Resolve ext_trace_app.

Inductive trace_mem_inv t P (m:mem) : list mem_event -> mem -> Prop :=
 | trace_mem_inv_nil: 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_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.
  exploit trace_mem_inv_eq2_1; eauto.
Qed.

Lemma perm_gss:
  forall (d : perm_map) (perm : permission) (p : pointer),
  upd_perm d p perm p = perm.
Proof.
  unfold upd_perm; intros.
  destruct Ptr.eq_dec; intuition.
Qed.

Lemma perm_gso:
  forall (d : perm_map) (p0 : pointer) (perm : permission) (p : pointer),
    p<>p0 ->
    upd_perm d p0 perm p = d p.
Proof.
  unfold upd_perm; intros.
  destruct Ptr.eq_dec; intuition.
Qed.


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

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

Lemma refines_seq : forall stmt1 stmt2 stmt1' stmt2',
  refines stmt1 stmt1' -> refines stmt2 stmt2' ->
  refines (Sseq stmt1 stmt2) (Sseq stmt1' stmt2').
Proof.
  unfold refines; intros.
  inv H1.
  inv H2.
  apply bigstep_simpl in H5; eauto.
  exploit H; eauto; intros.
  rewrite app_ass.
  inv H1.
  eapply bigstep_left_ext in H7; eauto.
  exploit H7; eauto.
  clear H7; intros H7.
  exploit H0; eauto; intros.
  inv H1.
  rewrite app_ass.
  rewrite <- (app_ass tr'0).
  rewrite <- H13.
  rewrite app_ass.
  rewrite <- app_ass.
  econstructor; eauto.
  econstructor; eauto.

  apply bigstep_simpl in H6; eauto.
  exploit H; eauto; intros.
  inv H1.
  rewrite app_ass.
  econstructor; eauto.
  eapply exec_seq_abrupt; eauto.
  red; intros.
  inv H1; eelim H10; eauto.
Qed.

Lemma while_repeat_congruence : forall body1 body2 cond args,
  refines body1 body2 ->
  refines (Swhile cond args body1) (Swhile cond args body2) .
Proof.
  intros.
  assert (forall ge sp tid st S af tr st',
    bigstep ge sp st tid S af tr st' -> forall cond args,
    S = Swhile cond args body1 ->
    let '((m,b),s) := tid in
    safe st b m ->
    let '((m',b'),s') := st' in
    safe st b' m' ->
    RefinesDefs.bigstep ge sp st tid (Swhile cond args body2) af tr st').
    induction 1; intros; try congruence.
    > inv H2; subst.
      destruct st'' as ((m'',b''),s''); intros.
      apply bigstep_simpl in H0_; eauto.
      generalize (H _ _ _ _ _ _ _ H0_); intros T1.
      exploit IHbigstep2; eauto; intros T2; clear IHbigstep2 IHbigstep1.
      clear H0_ H0_0.
      inv T1; inv T2.
      eapply bigstep_left_ext in H11; eauto.
      exploit H11; eauto; clear H11; intros H11.
      inv H11.
      rewrite app_ass.
      rewrite <- (app_ass tr').
      rewrite <- H12.
      rewrite app_ass.
      rewrite <- app_ass.
      econstructor; eauto.
      econstructor; eauto.
    > destruct st0 as ((m0,b0),s0); intros.
      inv H3; clear IHbigstep.
      apply bigstep_simpl in H1; eauto.
      generalize (H _ _ _ _ _ _ _ H1); intros T1; clear H1.
      inv T1; econstructor; eauto.
      eapply exec_while_true_abrupt; eauto.
      red; intros.
      inv H1; eelim H2; eauto.
    > inv H1.
      replace (@nil (positive*ext_event)) with (nil++@nil (positive*ext_event)) by auto.
      econstructor; eauto.
      eapply exec_while_false; eauto.
  unfold refines; intros.
  inv H1.
  exploit H0; eauto; clear H0.
  simpl; intros T; exploit T; eauto.
  intros T'; inv T'.
  rewrite app_ass.
  econstructor; eauto.
Qed.

Lemma refines_repeat_congruence : forall body1 body2 cond args,
  refines body1 body2 ->
  refines (Srepeat body1 cond args) (Srepeat body2 cond args) .
Proof.
  intros; unfold refines; intros.
  inv H0.
  inv H1.
  > inv H9.
    apply bigstep_simpl in H3; eauto.
    generalize (H _ _ _ _ _ _ _ H3); clear H3; intros T1.
    inv T1.
    eapply bigstep_left_ext in H5; eauto.
    exploit H5; eauto; clear H5; intros H5.
    generalize (while_repeat_congruence _ _ _ _ H _ _ _ _ _ _ _ H5); clear H5; intros T2.
    inv T2.
    repeat rewrite app_ass.
    rewrite <- (app_ass tr'0).
    rewrite <- H7.
    rewrite app_ass.
    rewrite <- app_ass.
    econstructor; eauto.
    econstructor.
    econstructor; eauto.
  > apply bigstep_simpl in H4; eauto.
    generalize (H _ _ _ _ _ _ _ H4); clear H4; intros T1.
    inv T1.
    rewrite app_ass.
    econstructor; eauto.
    econstructor; eauto.
    eapply exec_seq_abrupt; eauto.
    red; intros.
    inv H0; eelim H8; eauto.
Qed.

Lemma refines_remove_leak_left: forall l r1 r2 stmt,
  refines (Sseq (Leak l r1 r2) stmt) stmt.
Proof.
  unfold refines; intros.
  inv H.
  inv H0.
  inv H3.
  simpl; econstructor; eauto.
  inv H4.
  eelim H8; eauto.
Qed.

Lemma refines_remove_leak_right: forall l r1 r2 stmt,
  refines (Sseq stmt (Leak l r1 r2)) stmt.
Proof.
  unfold refines; intros.
  inv H.
  inv H0.
  inv H5.
  rewrite app_nil_r; simpl.
  econstructor; eauto.
  econstructor; eauto.
Qed.


Lemma refines_branch_same_begin: forall stmt1 stmt2 stmt3,
  refines
     (Sbranch (Sseq stmt1 stmt2) (Sseq stmt1 stmt3))
     (Sseq stmt1 (Sbranch stmt2 stmt3)).
Proof.
  unfold refines; intros.
  inv H.
  inv H0.
  > inv H7.
    > repeat (econstructor; eauto).
    > repeat (econstructor; eauto).
  > inv H7.
    > econstructor; eauto.
      econstructor; eauto.
      eapply exec_branch_right; eauto.
    > repeat (econstructor; eauto).
Qed.

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

Lemma Rsetmem_empty_false: forall x,
  Rset.mem x Rset.empty = false.
Proof.
  intros; generalize (@Rset.empty_not_mem x).
  destruct (Rset.mem x Rset.empty); simpl; auto; congruence.
Qed.
Hint Resolve Rsetmem_empty_false.

Lemma Rset_mem_add_false1 : forall tid t s,
  tid<> t ->
  Rset.mem tid s = false -> Rset.mem tid (Rset.add t s) = false.
Proof.
  unfold Rset.mem, Rset.add; intros.
  rewrite PTree.gsspec; destruct peq; intuition.
Qed.
Hint Resolve Rset_mem_add_false1.

Lemma Rset_mem_add_false2 : forall t tid s,
  Rset.mem tid (Rset.add t s) = false ->
  Rset.mem tid s = false.
Proof.
  unfold Rset.mem, Rset.add; intros.
  rewrite PTree.gsspec in *; destruct peq; auto; congruence.
Qed.
Hint Resolve Rset_mem_add_false2.

Lemma Rset_mem_remove : forall t tid s,
  Rset.mem tid s = false ->
  Rset.mem tid (Rset.remove t s) = false.
Proof.
  unfold Rset.mem, Rset.remove; intros.
  rewrite PTree.grspec; destruct peq; auto.
Qed.
Hint Resolve Rset_mem_remove.

Lemma Rset_mem_remove2 : forall t tid s,
  Rset.mem tid (Rset.remove t s) = false ->
  t<>tid ->
  Rset.mem tid s = false.
Proof.
  unfold Rset.mem, Rset.remove; intros.
  rewrite PTree.grspec in *.
  rewrite peq_false in H; auto.
Qed.
Hint Resolve Rset_mem_remove2.

Lemma refines_loop_aux : forall stmt stmt',
  refines stmt stmt' ->
  forall ge sp tid st stmt1 af tr st',
    bigstep ge sp tid st stmt1 af tr st' ->
    let '(m,b,rs) := st in safe tid b m ->
    let '(m',b',rs') := st' in safe tid b' m' ->
    stmt1 = Sloop stmt ->
    forall stmt2, stmt2 = Sloop stmt' ->
      RefinesDefs.bigstep ge sp tid st stmt2 af tr st'.
Proof.
  unfold refines; induction 2; intros; try congruence; subst;
  try destruct st as ((mm,bb),rrs);
  try destruct st' as ((mm',bb'),rrs');
  try destruct st'' as ((mm'',bb''),rrs''); intros; try congruence; subst.
  inv H2.
  replace (@nil (positive*ext_event)) with (nil++@nil (positive*ext_event)) by auto.
  repeat (econstructor; eauto).
  inv H3.
  apply bigstep_simpl in H0_; eauto.
  exploit H; eauto; intros.
  exploit IHbigstep2; eauto; intros IH2.
  clear IHbigstep2 IHbigstep1 H0_0 H0_.
  inv H3; inv IH2.
  eapply bigstep_left_ext in H9; eauto.
  simpl in *; exploit H9; eauto.
  clear H9; intros H9.
  inv H9.
  rewrite app_ass.
  rewrite <- (app_ass tr').
  rewrite <- H11.
  rewrite app_ass.
  rewrite <- app_ass.
  econstructor; eauto.
  eapply exec_loop_next; eauto.

  inv H4.
  apply bigstep_simpl in H0; eauto.
  exploit H; eauto; clear H0; intros.
  inv H0.
  econstructor; eauto.
  econstructor; eauto.
  red; intros.
  inv H0; eelim H1; eauto.
Qed.

Lemma refines_loop : forall stmt stmt',
  refines stmt stmt' ->
  refines (Sloop stmt) (Sloop stmt').
Proof.
  unfold refines; intros.
  inv H0.
  exploit refines_loop_aux; eauto; simpl.
  intros T; exploit T; eauto.
  intros H0.
  inv H0.
  rewrite app_ass.
  econstructor; eauto.
Qed.

Lemma refines_if : forall cond args stmt1 stmt1' stmt2 stmt2',
  refines stmt1 stmt1' ->
  refines stmt2 stmt2' ->
  refines (Sifthenelse cond args stmt1 stmt2) (Sifthenelse cond args stmt1' stmt2').
Proof.
  unfold refines; intros.
  inv H1.
  inv H2.
  apply bigstep_simpl in H14; eauto.
  exploit H; eauto; intros.
  inv H1.
  rewrite app_ass.
  repeat (econstructor; eauto).
  apply bigstep_simpl in H14; eauto.
  exploit H0; eauto; intros.
  inv H1.
  rewrite app_ass.
  econstructor; eauto.
  eapply exec_if_false; eauto.
Qed.

Lemma refines_if1 : forall cond args stmt1 stmt1' stmt2,
  refines stmt1 stmt1' ->
  refines (Sifthenelse cond args stmt1 stmt2) (Sifthenelse cond args stmt1' stmt2).
Proof.
  intros; apply refines_if; auto.
  apply refines_refl.
Qed.

Lemma refines_if2 : forall cond args stmt1 stmt2 stmt2',
  refines stmt2 stmt2' ->
  refines (Sifthenelse cond args stmt1 stmt2) (Sifthenelse cond args stmt1 stmt2').
Proof.
  intros; apply refines_if; auto.
  apply refines_refl.
Qed.

Lemma no_atomic_in_statement_dec: forall stmt,
  no_atomic_in_statement stmt = true ->
  INJECT.no_atomic_in_statement stmt.
Proof.
  induction stmt; simpl; auto.
  rewrite andb_true_iff; intuition.
  rewrite andb_true_iff; intuition.
  rewrite andb_true_iff; intuition.
Qed.

Require Import Relation_Operators.
Require Import Operators_Properties.

Lemma ext_trace_prefix: forall t af mb1 tr mb2,
  ext_trace t af mb1 tr mb2 ->
  let (m1,b1) := mb1 in
  let (m2,b2) := mb2 in
      exists l', b1 = b2 ++ l'.
Proof.
  induction 1; simpl; intros.
  > exists nil; rewrite app_nil_r; auto.
  > eauto.
  > subst; inv H; simpl in *.
    elim IHext_trace; auto.
    intros l' L1; subst.
    rewrite app_ass; eauto.
Qed.

Lemma star_unbuffer_safe_aux : forall t mb mb0,
  star (unbuffer t) mb mb0 ->
  safe t (snd mb) (fst mb) ->
  safe t (snd mb0) (fst mb0).
Proof.
  induction 1; auto.
Qed.

Lemma star_unbuffer_safe : forall t m b m0 b0,
  star (unbuffer t) (m, b) (m0, b0) ->
  safe t b m ->
  safe t b0 m0.
Proof.
  intros.
  exploit star_unbuffer_safe_aux; eauto.
Qed.
Hint Resolve star_unbuffer_safe.

Lemma star_unbuffer_ext_trace_aux: forall t mb mb',
  star (unbuffer t) mb mb' ->
  let (m',b') := mb in safe t b' m' ->
    ext_trace t Interleaved mb nil mb'.
Proof.
  induction 1.
  > destruct x; destruct y; econstructor 3; eauto.
  > destruct x; constructor.
    apply H.
  > destruct x; destruct y; destruct z.
    replace (@nil (positive*ext_event)) with (nil++@nil (positive*ext_event)) by auto.
    eauto.
Qed.

Lemma star_unbuffer_ext_trace: forall t m b m' b',
  star (unbuffer t) (m,b) (m',b') ->
  safe t b m ->
  ext_trace t Interleaved (m,b) nil (m',b').
Proof.
  intros.
  exploit star_unbuffer_ext_trace_aux; eauto.
Qed.

Lemma refines_atomic : forall b stmt stmt',
  refines stmt stmt' ->
  no_atomic_in_statement stmt' = true ->
  refines (Satomic b stmt) (Satomic b stmt').
Proof.
  unfold refines; intros.
  inv H1.
  inv H2.
  apply bigstep_simpl in H15; eauto.
  exploit H; eauto; clear H H15; intros.
  inv H.
  eelim app_eq_nil; eauto.
  intros; subst; simpl in *.
  inv H13.
  econstructor; eauto.
  econstructor; eauto.
  eapply no_atomic_in_statement_dec; eauto.
Qed.

Fixpoint uses (stmt:statement) : Rset.t :=
  match stmt with
    | Sfence _
    | Sabort _ _ _
    | Sfreeperm
    | Sskip
    | Srelease
    | Leak _ _ _ => Rset.empty
    | Sreturn arg => Rset.add_list arg Rset.empty
    | Sassume _ args
    | Sload _ _ args _
    | Satomicmem _ _ args _
    | Sop _ args _
    | Srequestperm _ _ args
    | Sstore _ _ _ args _ => Rset.add_list args Rset.empty
    | Sseq stmt1 stmt2
    | Sbranch stmt1 stmt2 => Rset.union (uses stmt1) (uses stmt2)
    | Sifthenelse _ args stmt1 stmt2 =>
      Rset.add_list args (Rset.union (uses stmt1) (uses stmt2))
    | Swhile _ args body
    | Srepeat body _ args => Rset.add_list args (uses body)
    | Sloop s => uses s
    | Satomic _ body => uses body
  end
.


Lemma mem_add1: forall x,
  Rset.mem x (Rset.add x Rset.empty) = true.
Proof.
  unfold Rset.mem, Rset.add, Rset.empty; intros.
  rewrite PTree.gss; auto.
Qed.

Lemma mem_union_left: forall x s1 s2,
  Rset.mem x s1 -> Rset.mem x (Rset.union s1 s2).
Proof.
  unfold Rset.mem, Rset.add, Rset.union; intros.
  rewrite PTree.gcombine; auto.
  destruct (s1!x); auto.
  destruct (s2!x); auto.
Qed.

Lemma mem_union_right: forall x s1 s2,
  Rset.mem x s2 -> Rset.mem x (Rset.union s1 s2).
Proof.
  unfold Rset.mem, Rset.add, Rset.union; intros.
  rewrite PTree.gcombine; auto.
  destruct (s1!x); auto.
  destruct (s2!x); auto.
Qed.

Lemma mem_union_case: forall x s1 s2,
  Rset.mem x (Rset.union s1 s2) ->
  Rset.mem x s1 \/ Rset.mem x s2.
Proof.
  unfold Rset.mem, Rset.add, Rset.union; intros.
  rewrite PTree.gcombine in H; auto.
  destruct (s1!x); auto.
  destruct (s2!x); auto.
Qed.

Lemma case_bool: forall b, ~b = true -> b = false.
Proof.
  destruct b; congruence.
Qed.

Lemma no_def_no_change: forall tid ge sp st stmt af l st',
  bigstep ge sp tid st stmt af l st' ->
  let (m,rs) := st in
  match st' with
    | (m',SIntra rs') =>
      forall x,
        Rset.mem x (defs stmt) = false -> rs x = rs' x
    | _ => True
  end.
Proof.
  induction 1; simpl; intros; subst; auto;
  try (
    unfold upd_regset; destruct peq; auto; subst;
      rewrite mem_add1 in *; congruence).
  destruct st; destruct r; auto; intros.
  apply IHbigstep.
  apply case_bool; intros; intro.
  rewrite mem_union_left in H1; auto; congruence.
  destruct st; destruct r; auto; intros.
  apply IHbigstep.
  apply case_bool; intros; intro.
  rewrite mem_union_right in H1; auto; congruence.
  destruct st''; destruct r; auto; intros.
  apply eq_trans with (rs' x); auto.
  destruct st; destruct st'.
  destruct r0; auto; intros.
  apply IHbigstep; simpl.
  apply case_bool; intros; intro.
  apply mem_union_case in H1.
  destruct H1; congruence.
  destruct st; destruct st'; destruct r0; auto; intros.
  apply eq_trans with (rs' x); auto.
  apply IHbigstep1; simpl.
  apply case_bool; intros; intro.
  rewrite mem_union_left in H2; auto; congruence.
  apply IHbigstep2; simpl.
  apply case_bool; intros; intro.
  rewrite mem_union_right in H2; auto; congruence.
  destruct st; destruct st'; destruct r0; auto; intros.
  apply IHbigstep; simpl.
  apply case_bool; intros; intro.
  rewrite mem_union_left in H1; auto; congruence.
  destruct st; destruct st'; destruct r0; auto; intros.
  apply IHbigstep; simpl.
  apply case_bool; intros; intro.
  rewrite mem_union_left in H0; auto; congruence.
  destruct st; destruct st'; destruct r0; auto; intros.
  apply IHbigstep; simpl.
  apply case_bool; intros; intro.
  rewrite mem_union_right in H0; auto; congruence.
  destruct st; destruct st'; destruct r0; auto; intros.
  apply eq_trans with (rs x); auto.
Qed.


Lemma eq_args: forall (rs rs':INJECT.regset) args,
  (forall x, In x args -> rs x = rs' x) ->
  map rs args = map rs' args.
Proof.
  induction args; simpl; intros; auto.
  f_equal; eauto.
Qed.

Lemma orb_true_left: forall b,
  b || true = true.
Proof.
  destruct b; auto.
Qed.
Hint Resolve orb_true_left.

Lemma abrupt_correct: forall tid ge sp st stmt af tr st',
  bigstep ge sp tid st stmt af tr st' ->
  (forall m' rs', st' <> (m',SIntra rs')) ->
  abrupt stmt = true.
Proof.
  induction 1; simpl; auto; intros T;
    try (eelim T; eauto; fail);
  simpl; unfold abrupt in *; simpl;
    try (rewrite IHbigstep; eauto).
  intuition.
  simpl in H0; auto.
  apply orb_prop in H0; intuition.
  rewrite IHbigstep2; eauto.
Qed.

Lemma refines_swap_assert : forall stmt cond args,
  negb (abrupt stmt) ->
  forallb (fun r => negb (Rset.mem r (defs stmt))) args ->
  refines (Sseq stmt (Sassume cond args)) (Sseq (Sassume cond args) stmt).
Proof.
  unfold refines; intros.
  inv H1.
  inv H2.
  > inv H7.
    rewrite (eq_args rs' rs) in H12.
    rewrite app_nil_r.
    replace l1 with (nil++l1) by auto.
    econstructor; eauto.
    econstructor; eauto.
    econstructor; eauto.
    intros; exploit no_def_no_change; eauto.
    simpl; intros.
    rewrite H2; auto.
    unfold is_true in *.
    rewrite forallb_forall in H0.
    apply case_bool; intro.
    exploit H0; eauto.
    rewrite H4; simpl; congruence.
  > exploit abrupt_correct; eauto.
    intros T; rewrite T in H; inv H.
Qed.

Require Import Relation_Operators.
Require Import Operators_Properties.

Lemma ext_trace_empty: forall t af mb tr mb',
  ext_trace t af mb tr mb' ->
  (snd mb) = nil ->
  tr = nil ->
  mb = mb'.
Proof.
  induction 1; simpl; auto.
  > destruct e; unfold cons'; simpl; try congruence.
    intros; rewrite <- IHext_trace; simpl; auto.
    inv H; auto.
  > inv H; intros.
    eelim app_cons_not_nil; eauto.
Qed.

Lemma no_store_ext_trace: forall tid ge sp st stmt af l st',
  bigstep ge sp tid st stmt af l st' ->
  let '(m,b,rs) := st in
  safe tid b m ->
  match st' with
    | (m',b',SIntra rs') =>
      safe tid b' m' ->
      store stmt = false -> ext_trace tid af (m,b) l (m',b')
    | _ => True
  end.
Proof.
  induction 1; simpl; intros; subst; auto; unfold store in *;
    try (constructor 1); try constructor; try congruence; intros.
  subst; auto.
  destruct rs''; simpl; try congruence; intros; auto.
  exploit IHbigstep; eauto; intros T; inv T.
  replace l with (l++nil); eauto with datatypes.
  destruct st; destruct p; destruct r; simpl; try congruence; intros; auto.
  apply IHbigstep; auto.
  apply case_bool; intros T; rewrite T in *; inv H3.
  destruct st; destruct p; destruct r; simpl; try congruence; intros; auto.
  apply IHbigstep; auto.
  apply case_bool; intros T; rewrite T in H3.
  destruct (store_fun ifso); inv H3.
  destruct st''; destruct p; destruct r; simpl; try congruence; intros; auto.
  eapply ext_trace_app with (m',b'); auto.
  destruct st; destruct p; destruct r; auto; intros.
  destruct st; destruct p; destruct st'; destruct p; destruct r0; auto; intros.
  apply IHbigstep; simpl in *; auto.
  rewrite H2; auto.
  destruct st; destruct p; destruct st'; destruct p; destruct r0; auto; intros.
  rewrite orb_false_iff in H4; destruct H4.
  eapply ext_trace_app with (m',b'); auto.
  destruct st; destruct p; destruct st'; destruct p; destruct r0; auto; intros.
  rewrite orb_false_iff in H3; destruct H3.
  auto.
  destruct st; destruct p; destruct st'; destruct p; destruct r0; auto; intros.
  rewrite orb_false_iff in H2; intuition.
  destruct st; destruct p; destruct st'; destruct p; destruct r0; auto; intros.
  rewrite orb_false_iff in H2; intuition.
  destruct st; destruct p; destruct st'; destruct p; destruct r0; auto; intros.
  simpl in *.
  eapply ext_trace_app; eauto.
Qed.

Lemma refines_atomic' : forall b stmt stmt',
  refines_in_atomic stmt stmt' ->
  no_atomic_in_statement stmt' = true ->
  refines (Satomic b stmt) (Satomic b stmt').
Proof.
  unfold refines, refines_in_atomic; intros.
  inv H1.
  econstructor; eauto.
  inv H2.
  econstructor; eauto.
  eapply no_atomic_in_statement_dec; eauto.
Qed.

Lemma refines_in_atomic_refl : forall stmt, refines_in_atomic stmt stmt.
Proof.
  unfold refines_in_atomic; intros.
  auto.
Qed.

Lemma refines_in_atomic_trans : forall stmt1 stmt2 stmt3,
  refines_in_atomic stmt1 stmt2 -> refines_in_atomic stmt2 stmt3 -> refines_in_atomic stmt1 stmt3.
Proof.
  unfold refines_in_atomic; intros.
  eauto.
Qed.

Lemma refines_in_atomic_seq : forall stmt1 stmt2 stmt1' stmt2',
  refines_in_atomic stmt1 stmt1' -> refines_in_atomic stmt2 stmt2' ->
  refines_in_atomic (Sseq stmt1 stmt2) (Sseq stmt1' stmt2').
Proof.
  unfold refines_in_atomic; intros.
  inv H1.
  exploit app_eq_nil; eauto.
  destruct 1; subst.
  econstructor; eauto.
  econstructor; eauto.
Qed.

Lemma refines_in_atomic_seq_left : forall stmt1 stmt2 stmt1',
  refines_in_atomic stmt1 stmt1' ->
  refines_in_atomic (Sseq stmt1 stmt2) (Sseq stmt1' stmt2).
Proof.
  intros; apply refines_in_atomic_seq; auto using refines_in_atomic_refl.
Qed.

Lemma refines_in_atomic_seq_right : forall stmt1 stmt2 stmt2',
  refines_in_atomic stmt2 stmt2' ->
  refines_in_atomic (Sseq stmt1 stmt2) (Sseq stmt1 stmt2').
Proof.
  intros; apply refines_in_atomic_seq; auto using refines_in_atomic_refl.
Qed.

Lemma ext: forall (rs rs0:INJECT.regset),
  (forall x : positive, rs x = rs0 x) -> rs=rs0.
Proof.
  intros.
  apply extensionality; auto.
Qed.

Lemma mem_empty: forall x,
  Rset.mem x Rset.empty = false.
Proof.
  unfold Rset.mem, Rset.empty; intros.
  rewrite PTree.gempty; auto.
Qed.

Lemma not_mem_add1 : forall x y s,
  Rset.mem x s = false ->
  x<>y ->
  Rset.mem x (Rset.add y s) = false.
Proof.
  unfold Rset.mem, Rset.add; intros.
  rewrite PTree.gsspec; destruct peq; intuition.
Qed.

Lemma not_mem_add2 : forall x y s,
  Rset.mem x (Rset.add y s) = false ->
  Rset.mem x s = false.
Proof.
  unfold Rset.mem, Rset.add; intros.
  rewrite PTree.gsspec in H; destruct peq; intuition.
  congruence.
Qed.

Lemma not_mem_add3 : forall x y s,
  Rset.mem x (Rset.add y s) = false -> x<>y.
Proof.
  unfold Rset.mem, Rset.add; intros.
  rewrite PTree.gsspec in H; destruct peq; intuition.
Qed.

Lemma not_mem_remove1 : forall x y s,
  Rset.mem x s = false ->
  Rset.mem x (Rset.remove y s) = false.
Proof.
  unfold Rset.mem, Rset.remove; intros.
  rewrite PTree.grspec; destruct peq; auto.
Qed.

Lemma not_mem_remove2 : forall x s,
  Rset.mem x (Rset.remove x s) = false.
Proof.
  unfold Rset.mem, Rset.remove; intros.
  rewrite PTree.grspec; destruct peq; intuition.
Qed.

Lemma not_mem_remove3 : forall x y s,
  Rset.mem x (Rset.remove y s) = false ->
  x=y \/ Rset.mem x s = false.
Proof.
  unfold Rset.mem, Rset.remove; intros.
  rewrite PTree.grspec in H; destruct PTree.elt_eq; auto.
Qed.

Lemma not_mem_remove_list1 : forall x y s,
  Rset.mem x s = false ->
  Rset.mem x (Rset.remove_list y s) = false.
Proof.
  induction y; simpl; intuition.
Qed.

Lemma not_mem_remove_list2 : forall x y s,
  In x y ->
  Rset.mem x (Rset.remove_list y s) = false.
Proof.
  induction y; simpl; intuition.
  subst; apply not_mem_remove2.
Qed.

Lemma not_mem_remove_list3 : forall x y s,
  Rset.mem x (Rset.remove_list y s) = false ->
  (In x y) \/ Rset.mem x s = false.
Proof.
  induction y; simpl; intuition.
  apply not_mem_remove3 in H.
  destruct H; auto.
  edestruct IHy; eauto.
Qed.

Lemma not_mem_inter1 : forall x s1 s2,
  Rset.mem x s1 = false ->
  Rset.mem x (Rset.inter s1 s2) = false.
Proof.
 unfold Rset.mem, Rset.inter; intros.
 rewrite PTree.gcombine; auto.
 destruct (s1!x); auto.
 destruct (s2!x); auto.
Qed.

Lemma not_mem_inter2 : forall x s1 s2,
  Rset.mem x s2 = false ->
  Rset.mem x (Rset.inter s1 s2) = false.
Proof.
 unfold Rset.mem, Rset.inter; intros.
 rewrite PTree.gcombine; auto.
 destruct (s1!x); auto.
 destruct (s2!x); auto.
Qed.

Lemma not_mem_inter3 : forall x s1 s2,
  Rset.mem x (Rset.inter s1 s2) = false ->
  Rset.mem x s1 = false \/
  Rset.mem x s2 = false.
Proof.
 unfold Rset.mem, Rset.inter; intros.
 rewrite PTree.gcombine in H; auto.
 destruct (s1!x); auto.
 destruct (s2!x); auto.
Qed.

Hint Resolve
  not_mem_add2
  not_mem_add3
  not_mem_inter2
  not_mem_inter1
  not_mem_remove2
  not_mem_remove1
  not_mem_remove_list2
  not_mem_remove_list1
  not_mem_add1
   mem_empty.


Lemma bigstep_and_dead: forall ge sp tid st stmt af l st',
  bigstep ge sp tid st stmt af l st' ->
  let (m,rs) := st in
  let (m',s') := st' in
    forall rs0 s,
      (forall x, Rset.mem x (dead_in stmt s) = false ->
        rs x = rs0 x) ->
      match s' with
        | SIntra rs' =>
          exists rs0',
            (forall x, Rset.mem x s = false -> rs' x = rs0' x)
            /\ bigstep ge sp tid (m,rs0) stmt af l (m',SIntra rs0')
        | _ => bigstep ge sp tid (m,rs0) stmt af l st'
      end.
Proof.
  induction 1; simpl; intros.
  > exists rs0; split; auto.
    econstructor; eauto.
  > exists rs0; split; auto.
    econstructor; eauto.
  > exists rs0; split; auto.
    econstructor; eauto.
  > destruct rs''; intros.
    econstructor; eauto.
    econstructor; eauto.
    edestruct IHbigstep as (rs0' & R1 & R2); eauto.
    exists rs0'; split; auto.
    econstructor; eauto.
  > exists (rs0 ## res <- v); split.
    intros; subst; repeat unfold upd_regset; destruct peq; auto.
    econstructor; eauto.
    rewrite <- (eq_args rs rs0); auto.
  > eexists. split. eassumption. vauto.
  > econstructor; split; eauto.
    econstructor; eauto.
  > exists rs0; split; eauto.
    econstructor; eauto.
    rewrite <- (eq_args rs rs0); auto.
  > exists (rs0 ## res <- v); split.
    intros; subst; repeat unfold upd_regset; destruct peq; auto.
    econstructor; eauto.
    rewrite <- (eq_args rs rs0); auto.
  > exists rs0; split; auto.
    econstructor; eauto.
    rewrite <- H6 ;auto.
    rewrite <- (eq_args rs rs0); eauto.
    subst.
    rewrite <- H6 ;auto.
  > exists rs0; split; auto.
    econstructor; eauto.
    rewrite <- H3; auto.
    rewrite <- (eq_args rs rs0); eauto.
    subst.
    rewrite <- H3 ;auto.
  > exists (rs0 ## res <- v); split.
    intros; subst; repeat unfold upd_regset; destruct peq; auto.
    econstructor; eauto.
    rewrite <- (eq_args rs rs0); auto.
  > destruct st; destruct r; intros.
    rewrite (eq_args rs rs0) in H; auto.
    econstructor; eauto.
    rewrite (eq_args rs rs0) in H; auto.
    econstructor; eauto.
    edestruct (IHbigstep rs0) as (rs0' & R1 & R2); eauto.
    rewrite (eq_args rs rs0) in H; auto.
    exists rs0'; split; auto.
    econstructor; eauto.
  > destruct st; destruct r; intros.
    rewrite (eq_args rs rs0) in H; auto.
    eapply exec_if_false; eauto.
    rewrite (eq_args rs rs0) in H; auto.
    eapply exec_if_false; eauto.
    edestruct (IHbigstep rs0) as (rs0' & R1 & R2); eauto.
    rewrite (eq_args rs rs0) in H; auto.
    exists rs0'; split; auto.
    eapply exec_if_false; eauto.
  > destruct st''; destruct r; intros.
    rewrite (eq_args rs rs0) in H; auto.
    simpl in *.
    edestruct (IHbigstep1 rs0 Rset.empty) as (rs0' & R1 & R2); auto.
    econstructor; eauto.
    rewrite (eq_args rs rs0) in H; auto.
    simpl in *.
    edestruct (IHbigstep1 rs0 Rset.empty) as (rs0' & R1 & R2); auto.
    econstructor; eauto.
    rewrite (eq_args rs rs0) in H; auto.
    edestruct (IHbigstep1 rs0 Rset.empty) as (rs0' & R1 & R2); eauto.
    edestruct (IHbigstep2 rs0' Rset.empty) as (rs0'' & R3 & R4); eauto.
    exists rs0''; split; auto.
    econstructor; eauto.
  > destruct st; destruct r; intros.
    rewrite (eq_args rs rs0) in H; auto.
    eapply exec_while_true_abrupt; auto.
    apply IHbigstep with Rset.empty; auto.
    rewrite (eq_args rs rs0) in H; auto.
    apply exec_while_true_abrupt; auto.
    apply IHbigstep with Rset.empty; auto.
    edestruct (IHbigstep rs0 Rset.empty) as (rs0' & R1 & R2); eauto.
    rewrite (eq_args rs rs0) in H; auto.
    exists rs0'; split; auto.
    apply exec_while_true_abrupt; auto.
    red; intros.
    inv H3; eelim H1; eauto.
  > rewrite (eq_args rs rs0) in H; auto.
    exists rs0; split; auto.
    eapply exec_while_false; eauto.
  > destruct st; destruct st'; destruct r0; intros.
    econstructor; eapply IHbigstep with (s:=Rset.empty); auto.
    econstructor; eapply IHbigstep with (s:=Rset.empty); auto.
    edestruct (IHbigstep rs0 Rset.empty) as (rs0' & R1 & R2); eauto.
    exists rs0'; split; auto.
    econstructor; eauto.
  > destruct st; destruct st'; destruct r0; intros.
    edestruct (IHbigstep1 rs0 (dead_in stmt2 s)) as (rs0' & R1 & R2); eauto.
    econstructor; eauto.
    edestruct (IHbigstep1 rs0 (dead_in stmt2 s)) as (rs0' & R1 & R2); eauto.
    econstructor; eauto.
    edestruct (IHbigstep1 rs0 (dead_in stmt2 s)) as (rs0' & R1 & R2); eauto.
    edestruct (IHbigstep2 rs0' s) as (rs0'' & R1' & R2'); eauto.
    exists rs0''; split; auto.
    econstructor; eauto.
  > destruct st; destruct st'; destruct r0; intros.
    eapply exec_seq_abrupt; eauto.
    eapply exec_seq_abrupt; eauto.
    eelim H0; eauto.
  > rewrite (eq_args rs rs0).
    econstructor.
    intros; apply H; auto.
  > econstructor; eauto.
  > rewrite (eq_args rs rs0) in H.
    exists rs0; split; auto.
    econstructor; eauto.
    eauto.
  > destruct st; destruct st'; destruct r0; intros.
    econstructor; eauto.
    econstructor; eauto.
    edestruct (IHbigstep rs0 s) as (rs0' & R1 & R2); eauto.
    exists rs0'; split; auto.
    econstructor; eauto.
  > destruct st; destruct st'; destruct r0; intros.
    eapply exec_branch_right; eauto.
    eapply exec_branch_right; eauto.
    edestruct (IHbigstep rs0 s) as (rs0' & R1 & R2); eauto.
    exists rs0'; split; auto.
    eapply exec_branch_right; eauto.
  > exists rs0; split; auto.
    econstructor; eauto.
  > destruct st; destruct st'; destruct r0; intros.
    edestruct (IHbigstep1 rs0 Rset.empty) as (rs0' & R1 & R2); eauto.
    exploit (IHbigstep2 rs0' Rset.empty); eauto; intros R3.
    econstructor; eauto.
    edestruct (IHbigstep1 rs0 Rset.empty) as (rs0' & R1 & R2); eauto.
    exploit (IHbigstep2 rs0' Rset.empty); eauto; intros R3.
    econstructor; eauto.
    edestruct (IHbigstep1 rs0 Rset.empty) as (rs0' & R1 & R2); eauto.
    edestruct (IHbigstep2 rs0' Rset.empty) as (rs0'' & R1' & R2'); eauto.
    exists rs0''; split; auto.
    econstructor; eauto.
  > destruct st; destruct st'; destruct r0; intros.
    apply exec_loop_next_abrupt; auto.
    apply IHbigstep with Rset.empty; auto.
    apply exec_loop_next_abrupt; auto.
    apply IHbigstep with Rset.empty; auto.
    eelim H0; eauto.
Qed.

Lemma rbigstep_left_ext : forall tid ge sp st' stmt af tr m' s',
  RefinesDefs.bigstep ge sp tid (m',s') stmt af tr st' ->
  forall tr' m'',
  ext_trace tid af m'' tr' m' ->
  RefinesDefs.bigstep ge sp tid (m'',s') stmt af (tr'++tr) st'.
Proof.
  intros.
  inv H.
  exploit bigstep_left_ext; eauto; clear H3.
  simpl; intros T; exploit T; eauto; clear T; intros.
  inv H.
  rewrite <- app_ass.
  rewrite <- H3.
  rewrite app_ass.
  econstructor; eauto.
Qed.

Lemma refines_dead_code : forall stmt1 stmt2,
  abrupt stmt1 = false ->
  store stmt1 = false ->
  Rset.forallb (fun r => Rset.mem r (dead_in stmt2 Rset.empty)) (defs stmt1) = true ->
  refines (Sseq stmt1 stmt2) stmt2.
Proof.
  unfold refines; intros.
  inv H2.
  inv H3.
  > exploit (no_store_ext_trace _ _ _ _ _ _ _ _ H6); eauto; intros.
    generalize (no_def_no_change _ _ _ _ _ _ _ _ H6); simpl; intros.
    rewrite app_ass.
    eapply rbigstep_left_ext; eauto.
    assert
      (forall x, Rset.mem x (dead_in stmt2 Rset.empty) = false -> rs' x = rs x).
      intros.
      case_eq (Rset.mem x (defs stmt1)); intros.
      assert (Rset.mem x (dead_in stmt2 Rset.empty)).
      apply (Rset.forallb_forall H1); auto.
      congruence.
      symmetry; auto.
    generalize (bigstep_and_dead _ _ _ _ _ _ _ _ H8 _ _ H5); simpl.
    destruct s'; intros.
    econstructor; eauto.
    econstructor; eauto.
    destruct H7 as (rs0' & R1 & R2).
    assert (r=rs0').
      apply ext.
      intros; apply R1; auto.
    subst.
    econstructor; eauto.
  > exploit abrupt_correct; eauto.
    congruence.
Qed.

Lemma refines_dead_code_return : forall stmt1 args,
  abrupt stmt1 = false ->
  store stmt1 = false ->
  Rset.forallb (fun r => forallb (fun arg => negb (Peqb r arg)) args) (defs stmt1) = true ->
  refines (Sseq stmt1 (Sreturn args)) (Sreturn args).
Proof.
  unfold refines; intros.
  inv H2.
  inv H3.
  > exploit (no_store_ext_trace _ _ _ _ _ _ _ _ H6); eauto; intros.
    generalize (no_def_no_change _ _ _ _ _ _ _ _ H6); simpl; intros.
    rewrite app_ass.
    eapply rbigstep_left_ext; eauto.
    generalize H8; intros H11'.
    inv H8.
    assert
      (forall x, Rset.mem x (dead_in (Sreturn args) (defs stmt1)) = false -> rs' x = rs x).
      intros.
      case_eq (Rset.mem x (defs stmt1)); intros.
      > assert ( forall r, In r args -> negb (Peqb x r)).
          apply forallb_forall.
          apply (Rset.forallb_forall H1).
          auto.
        simpl in H5.
        apply not_mem_remove_list3 in H5.
        destruct H5.
        > exploit H8; eauto.
          rewrite Peqb_refl in *.
          simpl; congruence.
        > congruence.
      > symmetry; auto.
    generalize (bigstep_and_dead _ _ _ _ _ _ _ _ H11' _ _ H5); simpl.
    intros.
    inv H7.
    replace tr' with (nil++tr') by auto.
    econstructor; eauto.
    econstructor; eauto.
  > exploit abrupt_correct; eauto.
    congruence.
Qed.

Lemma refines_seq_assoc1 : forall stmt1 stmt2 stmt3,
  refines (Sseq stmt1 (Sseq stmt2 stmt3))
          (Sseq (Sseq stmt1 stmt2) stmt3).
Proof.
  unfold refines; intros.
  inv H.
  econstructor; eauto.
  inv H0.
  inv H5.
  rewrite <- app_ass.
  repeat (econstructor; eauto).
  eapply exec_seq_abrupt; eauto.
  econstructor; eauto.
  eapply exec_seq_abrupt; eauto.
  eapply exec_seq_abrupt; eauto.
Qed.

Lemma refines_seq_assoc2 : forall stmt1 stmt2 stmt3,
  refines (Sseq (Sseq stmt1 stmt2) stmt3)
          (Sseq stmt1 (Sseq stmt2 stmt3)).
Proof.
  unfold refines; intros.
  inv H.
  econstructor; eauto.
  inv H0.
  inv H3.
  rewrite app_ass.
  repeat (econstructor; eauto).
  eelim H10; eauto.
  inv H4.
  econstructor; eauto.
  eapply exec_seq_abrupt; eauto.
  eapply exec_seq_abrupt; eauto.
Qed.

Lemma refines_loop_one_aux :
  forall ge sp tid st s0 s1 af tr st',
    bigstep ge sp tid st (Sseq s0 (Sseq (Sloop s0) s1)) af tr st' ->
    bigstep ge sp tid st (Sseq (Sloop s0) s1) af tr st'.
Proof.
  intros.
  inversion_clear H; clarify.
  inversion_clear H1; clarify.
  rewrite <- app_ass.
  eapply exec_seq; eauto.
  eapply exec_loop_next; eauto.
  eapply exec_seq_abrupt; eauto.
  econstructor; eauto.
  econstructor; eauto.
  econstructor; eauto.
Qed.

Lemma refines_skip_aux :
  forall ge sp tid st s af tr st',
    bigstep ge sp tid st (Sseq s Sskip) af tr st' ->
    bigstep ge sp tid st s af tr st'.
Proof.
  intros.
  inversion H; clarify.
  inversion H; clarify.
  inversion H9; clarify.
  replace (l0 ++ nil) with l0 by auto with datatypes; auto.
Qed.

Lemma refines_loop_parenthesis_aux : forall ge sp tid st S af tr st',
  bigstep ge sp tid st S af tr st' ->
  forall s1 s2,
    S = Sloop (Sseq s1 s2) ->
    bigstep ge sp tid st (Sbranch (Sseq s1 (Sseq (Sloop (Sseq s2 s1)) s2)) Sskip) af tr st'.
Proof.
  induction 1; intros; clarify.
  > eapply exec_branch_right; eauto.
    econstructor; eauto.

  > exploit IHbigstep2; clarify; clear IHbigstep1 IHbigstep2; intro IndHip.
    clear H0.
    inv IndHip.
    > eapply exec_branch_left.
      inv H.
      > replace ((l1 ++ l2) ++ tr2) with (l1 ++ l2 ++ tr2) by auto with datatypes.
        eapply exec_seq; eauto.
        inv H7.
        > inv H6.
          repeat (rewrite <- app_ass).
          eapply exec_seq; eauto.
          eapply exec_loop_next; eauto.
          eapply exec_seq; eauto.
        > repeat (rewrite <- app_ass).
          eapply exec_seq_abrupt; eauto.
          eapply exec_loop_next; eauto.
          eapply exec_seq; eauto.
        > eapply exec_seq_abrupt; eauto.
          eapply exec_loop_next_abrupt; eauto.
          eapply exec_seq; eauto.
      > eelim H9; eauto.
    > eapply exec_branch_left.
      inv H7.
      inv H.
      > rewrite app_nil_r.
        econstructor; eauto.
        replace (l2) with (nil ++ l2) by auto.
        econstructor; eauto.
        constructor.
      > eelim H8; eauto.

  > eapply exec_branch_left; eauto.
    inv H.
    > econstructor; eauto.
      replace (l2) with (nil ++ l2) by auto.
      econstructor; eauto.
      constructor.
    > econstructor; eauto.
Qed.

Lemma refines_while_aux: forall ge sp tid st S af tr st',
  bigstep ge sp tid st S af tr st' ->
  forall cond args body,
    S = Swhile cond args body ->
  let '((m',b'),s') := st' in
    safe tid b' m' ->
   bigstep ge sp tid st
     (Sseq (Sloop (Sseq (Sassume cond args) body))
        (Sassume (negate_condition cond) args)) af tr st'.
Proof.
  induction 1; intros; try congruence.
  > inv H3.
    destruct st'' as ((m'',b''),s''); intros.
    exploit IHbigstep2; eauto; clear IHbigstep1 IHbigstep2; intros IH2.
    inv IH2.
    > rewrite <- app_ass.
      econstructor; eauto.
      eapply exec_loop_next; eauto.
      replace l1 with (nil++l1) by auto.
      econstructor; eauto.
      econstructor; eauto.
    > eapply exec_seq_abrupt; eauto.
      eapply exec_loop_next; eauto.
      replace l1 with (nil++l1) by auto.
      econstructor; eauto.
      econstructor; eauto.
  > inv H2.
    destruct st as ((m'',b''),s''); intros.
    econstructor; eauto.
    econstructor; eauto.
    replace l with (nil++l) by auto.
    econstructor; eauto.
    econstructor; eauto.
  > inv H0.
    replace (@nil (positive*ext_event)) with (nil++@nil (positive*ext_event)) by auto.
    econstructor; eauto.
    econstructor; eauto.
    econstructor; eauto.
    exploit eval_negate_condition; eauto.
Qed.

Lemma refines_while : forall body cond args,
  refines (Swhile cond args body)
          (Sseq
            (Sloop (Sseq (Sassume cond args) body))
            (Sassume (negate_condition cond) args)).
Proof.
  unfold refines; intros.
  inv H.
  econstructor; eauto.
  exploit refines_while_aux; eauto.
Qed.

Lemma refines_while_inv_aux: forall ge sp tid st S af tr st',
  bigstep ge sp tid st S af tr st' ->
  forall cond args body,
    S = Sloop (Sseq (Sassume cond args) body) ->
    match st' with
      | (m',SIntra s') =>
        bigstep ge sp tid (m',s') (Sassume (negate_condition cond) args) af nil st' ->
        bigstep ge sp tid st (Swhile cond args body) af tr st'
      | _ => bigstep ge sp tid st (Swhile cond args body) af tr st'
    end.
Proof.
  induction 1; intros; try congruence.
  > inv H; inv H0.
    eapply exec_while_false.
    exploit eval_negate_condition; eauto.
    replace (negate_condition (negate_condition cond)) with cond.
    simpl; auto.
    destruct cond; simpl; auto; destruct c; simpl; auto.
  > inv H2.
    exploit IHbigstep2; eauto; clear IHbigstep2 IHbigstep1.
    intros IH.
    destruct st' as (m',r').
    destruct r'; auto.
    > inv H.
      > inv H4.
        eapply exec_while_true; eauto.
      > eelim H9; eauto.
    > inv H.
      > inv H4.
        eapply exec_while_true; eauto.
      > eelim H9; eauto.
    > intros T.
      inv H.
      > inv H4.
        eapply exec_while_true; eauto.
      > eelim H9; eauto.
  > inv H1.
    clear IHbigstep.
    destruct st' as (m',r').
    destruct r'; auto.
    > inv H.
      > inv H3.
        eapply exec_while_true_abrupt; eauto.
      > inv H4; congruence.
    > inv H.
      > inv H3.
        eapply exec_while_true_abrupt; eauto.
      > inv H4; congruence.
    > intros T.
      inv H.
      > inv H3.
        eapply exec_while_true_abrupt; eauto.
      > eelim H8; eauto.
Qed.

Lemma refines_while_inv : forall body cond args,
  refines (Sseq
            (Sloop (Sseq (Sassume cond args) body))
            (Sassume (negate_condition cond) args))
          (Swhile cond args body).
Proof.
  unfold refines; intros.
  inv H.
  econstructor; eauto.
  inv H0.
  assert (l2=nil).
    inv H5; auto.
  subst; rewrite app_nil_r.
  destruct s'; try (inv H5; congruence).
  assert (m'0=m') by (inv H5; congruence); subst.
  assert (r=rs') by (inv H5; congruence); subst.
  assert (b'0=b') by (inv H5; congruence); subst.
  generalize dependent H5.
  exploit refines_while_inv_aux; eauto; simpl.
  exploit refines_while_inv_aux; eauto; simpl.
  destruct s'; auto.
  eelim H8; eauto.
Qed.

Lemma Peqb_false {x y} :
  negb (Peqb x y) -> x <> y.
Proof.
pose proof (Peqb_eq x y) as (u & v).
  intros H. unfold is_true in H. rewrite negb_true_iff in H.
  intros contra. subst.
  intuition. autorw'.
Qed.

Lemma not_undef : forall {X v} {a b:X},
    v <> Vundef ->
    (if Val.eq_dec v Vundef then a else b) = b.
Proof.
  intros X i a b'.
  destruct (Val.eq_dec i Vundef); clarify.
Qed.

Lemma ext_trace_from_empty_buffer': forall t mb af tr mb',
  ext_trace t af mb tr mb' ->
  snd mb = empty_buffer -> snd mb' = empty_buffer.
Proof.
  induction 1; simpl in *; auto.
  inv H; intros; subst.
    eelim app_cons_not_nil; eauto.
Qed.

Lemma ext_trace_from_empty_buffer: forall t m af tr m' b',
  ext_trace t af (m,empty_buffer) tr (m',b') -> b' = empty_buffer.
Proof.
  intros; exploit ext_trace_from_empty_buffer'; eauto.
Qed.

Hint Constructors ext_trace.

Lemma refines_cas_fail_stronger : forall r ptr new old dst,
  refines
  (Sseq
    (Satomicmem r Op.AScas (ptr::new::old::nil) dst)
    (Sassume (Op.Ccomp Cne) (dst::old::nil)))
  (Satomic true
    (Sseq
      (if r then
        (Sseq (Sload Global (Op.Aindexed Int.zero) (ptr::nil) dst) Srelease)
       else
          (Sload Global (Op.Aindexed Int.zero) (ptr::nil) dst))
      (Sassume (Op.Ccomp Cne) (dst::old::nil)))).
Proof.
  unfold refines; intros.
  inv H.
  inv H0.
  inv H5.
  inv H3.
  assert (b''=empty_buffer) by (eapply ext_trace_from_empty_buffer; eauto).
  subst.
  econstructor; eauto; clear H1.
  rewrite app_nil_r.
  inv H17.
  assert ((rmw_instr_semantics (rmw_CAS (rs old) (rs new)) v)=v).
    inv H10.
    unfold upd_regset in *.
    rewrite peq_true in *.
    destruct v; try (inv H1; fail).
    > destruct peq; try (inv H1; fail).
      rewrite Int.eq_true in H1; inv H1.
      destruct (rs old); try (inv H1; fail).
      > simpl.
        destruct Val.eq_dec; try congruence; simpl.
        destruct Val.eq_dec; try congruence; simpl.
        destruct Val.eq_dec; try congruence; simpl.
        inv e; rewrite Int.eq_true in H1; inv H1.
      > simpl.
        destruct Val.eq_dec; try congruence; simpl.
        destruct Val.eq_dec; try congruence; simpl.
        destruct Val.eq_dec; try congruence; simpl.
    > simpl.
      destruct Val.eq_dec; try congruence; simpl.
      destruct Val.eq_dec; try congruence; simpl.
      destruct Val.eq_dec; try congruence; simpl.
      destruct peq; try congruence.
      unfold Ptr.eq in *.
      destruct Ptr.eq_dec; intuition.
      inv H1.
      rewrite e in *.
      unfold Ptr.eq in *.
      destruct Ptr.eq_dec; intuition.
      inv H1.
  assert (flush st nil m'0 m'0).
    constructor 2.
  econstructor; eauto.
  destruct r; simpl; eauto.
  change (@nil (positive * ext_event)) with (nil ++ @nil (positive * ext_event)).
  econstructor; eauto.
  2: econstructor; eauto.
  assert (load_ptr Mint32 m'0 p = Some v).
    inv H16.
    revert H0; subst; intros.
    simpl; auto.
  destruct r.
  > inv H16; clear H16 H1.
    revert H0; subst; intros.
    change (@nil (positive * ext_event)) with (nil ++ nil ++ @nil (positive * ext_event)).
    assert (Hg:
      bigstep ge sp st (MEM m'1 d, empty_buffer, rs ## dst <- v)
        Srelease Atomic (nil ++ nil)
        (MEM m'1 d', empty_buffer, SIntra rs ## dst <- v)).
      econstructor; eauto.
      econstructor; eauto.
      econstructor; auto.
    replace m'1 with m0 in *.
    econstructor; eauto.
    apply exec_load with p v; auto.
    simpl.
    econstructor; eauto.
    unfold empty_perm in *; intros.
    generalize (ESP p); intros T; inv T; try congruence.
    simpl; rewrite <- H.
    destruct p; inv H2.
    rewrite Int.add_zero; reflexivity.
    apply emem_is_eq.
    eapply Emem.store_same; eauto.
    congruence.
    apply mem_eq_refl.
  > replace m' with m'0 in *.
    apply exec_load with p v; auto.
    simpl.
    inv H16.
    revert H0; subst; intros.
    econstructor; eauto.
    unfold empty_perm in *; intros; congruence.
    simpl; rewrite <- H.
    destruct p; inv H2.
    rewrite Int.add_zero; reflexivity.
    inv H16; f_equal.
    apply emem_is_eq.
    eapply Emem.store_same; eauto.
    congruence.
    apply mem_eq_refl.
    congruence.

  inv H4.
  eelim H8; eauto.
Qed.


Lemma refines_cas_success : forall r ptr new old dst,
  negb (Peqb dst old) ->
  negb (Peqb dst new) ->
  negb (Peqb ptr dst) ->
  refines
  (Sseq
    (Satomicmem r Op.AScas (ptr::new::old::nil) dst)
    (Sassume (Op.Ccomp Ceq) (dst::old::nil)))
  (Satomic true
    (Sseq
      (Sload Global (Op.Aindexed Int.zero) (ptr::nil) dst)
      (Sseq
        (Sassume (Op.Ccomp Ceq) (dst::old::nil))
        (Sstore r Global (Op.Aindexed Int.zero) (ptr::nil) new)))).
Proof.
  intros r ptr new old dst old_kept new_kept ptr_kept.
  apply Peqb_false in old_kept.
  apply Peqb_false in new_kept.
  apply Peqb_false in ptr_kept.
  unfold refines.
  intros ge sp tid af tr st st' H.
  inv H. inv H0.
  inv H3.
  inv H5.
  assert (b''=empty_buffer) by (eapply ext_trace_from_empty_buffer; eauto).
  subst.
  econstructor; eauto; clear H1.
  rewrite app_nil_r.
  set (v':=(Val.conv (rs new) Tint)).
  inv H17.
  assert (S3:flush st empty_buffer m'1 m'1).
    constructor 2.
  econstructor; simpl; eauto.
  change (@nil (positive * ext_event)) with (nil ++ @nil (positive * ext_event)).
  apply exec_seq with m'1 (rs##dst<-v) nil.
  inv H16.
  apply exec_load with p v; eauto. simpl.
  econstructor; eauto.
  unfold empty_perm in *; intros.
  destruct r; try congruence.
  generalize (ESP p); intros T; inv T; try congruence.
  simpl; rewrite <- H.
  destruct p; inv LD.
  rewrite Int.add_zero; reflexivity.
  change (@nil (positive * ext_event)) with (nil ++ @nil (positive * ext_event)).
  apply exec_seq with m'1 (rs##dst<-v) nil.
  econstructor; eauto.
  eapply exec_store_atomic with (a:=p); eauto.
  unfold upd_regset; rewrite peq_false; auto.
  simpl in *.
  unfold upd_regset; rewrite peq_false; auto.
  rewrite <- H.
  destruct p.
  rewrite Int.add_zero; reflexivity.
  simpl.
    inv H16.
    unfold upd_regset.
    rewrite peq_false; auto.
    destruct ESWF3.
    econstructor; eauto.
    replace (rs new) with (rmw_instr_semantics (rmw_CAS (rs old) (rs new)) v); auto.
    clear STO.
    unfold rmw_instr_semantics.
    destruct Val.eq_dec; try congruence; simpl.
    destruct Val.eq_dec; try congruence; simpl.
    subst; elim ESWF1.
    destruct Val.eq_dec; auto.
    generalize H8; simpl.
    unfold upd_regset; rewrite peq_true.
    rewrite peq_false; auto.
    destruct v; try congruence.
    destruct (rs old); try congruence.
    rewrite Int.eq_false; try congruence.
    unfold eval_compare_null.
    unfold eval_compare_mismatch.
    destruct Int.eq; congruence.
    destruct (rs old); try congruence.
    unfold eval_compare_null.
    unfold eval_compare_mismatch.
    destruct Int.eq; congruence.
    unfold Ptr.eq.
    destruct Ptr.eq_dec; simpl; intuition; try congruence.
    econstructor; eauto. apply Rset.empty_subset.
    destruct (rs new); auto.
    eauto.
    eauto.
  inv H4; eelim H8; eauto.
Qed.


Lemma refines_seq_left : forall stmt1 stmt2 stmt1',
  refines stmt1 stmt1' ->
  refines (Sseq stmt1 stmt2) (Sseq stmt1' stmt2).
Proof.
  intros; apply refines_seq; auto using refines_refl.
Qed.

Lemma refines_seq_right : forall stmt1 stmt2 stmt2',
  refines stmt2 stmt2' ->
  refines (Sseq stmt1 stmt2) (Sseq stmt1 stmt2').
Proof.
  intros; apply refines_seq; auto using refines_refl.
Qed.

Lemma refines_if_with_branch : forall cond args ifso ifnot,
  refines (Sifthenelse cond args ifso ifnot)
          (Sbranch
            (Sseq (Sassume cond args) ifso)
            (Sseq (Sassume (negate_condition cond) args) ifnot)).
Proof.
  unfold refines; intros.
  inversion H; clarify.
  inversion H0; clarify.
  econstructor; eauto.
  econstructor; eauto.
  replace tr0 with (nil ++ tr0) by auto with datatypes.
  econstructor; eauto.
  econstructor; eauto.

  replace tr0 with (nil ++ tr0) by auto with datatypes.
  econstructor; eauto.
  eapply exec_branch_right.
  econstructor; eauto.
  assert (eval_condition (negate_condition cond) (map rs args) = Some (negb false)).
  eapply eval_negate_condition; eauto.
  simpl in H2.
  econstructor; eauto.
Qed.

Lemma refines_seq_branch : forall stmt1 stmt2 stmt3,
  refines
    (Sseq stmt1 (Sbranch stmt2 stmt3))
    (Sbranch (Sseq stmt1 stmt2) (Sseq stmt1 stmt3)).
Proof.
  unfold refines; intros.
  inversion H; clarify.
  inversion H0; clarify.
  inversion H6; clarify.
  econstructor; eauto.
  eapply exec_branch_left; eauto.
  econstructor; eauto.
  econstructor; eauto.
  eapply exec_branch_right; eauto.
  econstructor; eauto.
  econstructor; eauto.
  econstructor; eauto.
  econstructor; eauto.
Qed.

Lemma refines_branch_seq : forall stmt1 stmt2 stmt3,
  refines
    (Sseq (Sbranch stmt1 stmt2) stmt3)
    (Sbranch (Sseq stmt1 stmt3) (Sseq stmt2 stmt3)).
Proof.
  unfold refines; intros.
  inversion H; clarify.
  inversion H0; clarify.
  inversion H4; clarify.
  econstructor; eauto.
  eapply exec_branch_left; eauto.
  econstructor; eauto.
  econstructor; eauto.
  eapply exec_branch_right; eauto.
  econstructor; eauto.
  econstructor; eauto.
  inversion H5; clarify.
  econstructor; eauto.
  econstructor; eauto.
  eapply exec_branch_right; eauto.
  econstructor; eauto.
Qed.

Lemma refines_branch : forall stmt1 stmt2 stmt1' stmt2',
  refines stmt1 stmt1' -> refines stmt2 stmt2' ->
  refines (Sbranch stmt1 stmt2) (Sbranch stmt1' stmt2').
Proof.
  unfold refines; intros.
  inversion H1; clarify.
  inversion H2; clarify.
  assert (RefinesDefs.bigstep ge sp st (m,b,rs) stmt1' af tr0 (m',b',s')).
  assert (ext_trace st af (m',b') nil (m',b')).
    econstructor; eauto.
    assert (safe st b' m') by eauto.
    auto.
  replace tr0 with (tr0 ++ nil) by auto with datatypes.
  exact (H _ _ _ _ _ _ _ (bigstep_def _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ SAFE H10 H4)).
  inversion H4; clarify.
  assert (bigstep ge sp st (m, b, rs) (Sbranch stmt1' stmt2') af tr (m'0, b'0, s')).
  eapply exec_branch_left; eauto.
  assert (ext_trace st af (m'0,b'0) (tr'0 ++ tr') (m'',b'')); eauto.
  replace ((tr ++ tr'0) ++ tr') with (tr ++ (tr'0 ++ tr')) by auto with datatypes.
  econstructor; eauto.

  assert (RefinesDefs.bigstep ge sp st (m,b,rs) stmt2' af tr0 (m',b',s')).
  assert (ext_trace st af (m',b') nil (m',b')).
    econstructor; eauto.
    assert (safe st b' m') by eauto.
    auto.
  replace tr0 with (tr0 ++ nil) by auto with datatypes.
  exact (H0 _ _ _ _ _ _ _ (bigstep_def _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ SAFE H10 H4)).
  inv H4.
  rewrite app_ass.
  econstructor; eauto.
  eapply exec_branch_right; eauto.
Qed.

Lemma seq_seq : forall ge sp tid st s1 s3 s4 af tr st',
  bigstep ge sp tid st (Sseq s1 (Sseq s3 s4)) af tr st' ->
  bigstep ge sp tid st (Sseq (Sseq s1 s3) s4) af tr st'.
Proof.
  intros.
  inversion_clear H; clarify.
  inversion_clear H1; clarify.
  rewrite <- app_ass.
  eapply exec_seq; eauto.
  eapply exec_seq; eauto.
  eapply exec_seq_abrupt; eauto.
  eapply exec_seq; eauto.
  eapply exec_seq_abrupt; eauto.
  econstructor; eauto.
Qed.

Lemma seq_seq_1 : forall ge sp tid st s1 s3 s4 af tr st',
  bigstep ge sp tid st (Sseq (Sseq s1 s3) s4) af tr st' ->
  bigstep ge sp tid st (Sseq s1 (Sseq s3 s4)) af tr st'.
Proof.
  intros.
  inversion_clear H; clarify.
  inversion_clear H0; clarify.
  rewrite app_ass.
  eapply exec_seq; eauto.
  eapply exec_seq; eauto.
  destruct (H3 (m',b') rs'); auto.
  inversion_clear H0; clarify.
  eapply exec_seq; eauto.
  eapply exec_seq_abrupt; eauto.
  eapply exec_seq_abrupt; eauto.
Qed.

Lemma unroll_once : forall ge sp tid st s af tr st',
  bigstep ge sp tid st (Sseq s (Sloop s)) af tr st' ->
  bigstep ge sp tid st (Sloop s) af tr st'.
Proof.
  intros.
  inversion_clear H; clarify.
  replace tr with (tr ++ nil) by auto with datatypes.
  eapply exec_loop_next; eauto.
  econstructor; eauto.
Qed.

Lemma unroll_once_1 : forall ge sp tid st s' s af tr st',
  bigstep ge sp tid st (Sseq (Sseq s (Sloop s)) s') af tr st' ->
  bigstep ge sp tid st (Sseq (Sloop s) s') af tr st'.
Proof.
  intros.
  inversion_clear H; clarify.
  econstructor; eauto.
  eapply unroll_once; eauto.
  econstructor; eauto.
  eapply unroll_once; eauto.
Qed.

Lemma neg_neg_cond : forall cond,
  negate_condition (negate_condition cond) = cond.
Proof.
  intros.
  destruct cond; simpl.
  destruct c; simpl; reflexivity.
  destruct c; simpl; reflexivity.
  destruct c; simpl; reflexivity.
  destruct c; simpl; reflexivity.
  destruct c; simpl; reflexivity.
  destruct c; simpl; reflexivity.
  destruct i; simpl; reflexivity.
  destruct i; simpl; reflexivity.
Qed.

Lemma refines_repeat : forall body cond args,
  refines (Srepeat body cond args)
          (Sseq
            (Sloop (Sseq body (Sassume (negate_condition cond) args)))
            (Sseq body (Sassume cond args))).
Proof.
  unfold refines; intros.
  inversion_clear H; clarify.
  inversion_clear H0; clarify.
  inversion_clear H; clarify.
  generalize (bigstep_def _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ H3 H2 H1); intro W; clear H2.
  generalize (refines_while _ _ _ _ _ _ _ _ _ _ W); intro L; clear W.
  inversion L; clarify.
  clear L.
  rewrite neg_neg_cond in H7.
  rewrite app_ass; rewrite <- H2; clear H2.
  rewrite <- app_ass.
  econstructor; eauto; clear H12.
  inversion_clear H7; clarify.
  inversion H; clarify.
  rewrite <- app_ass.
  rewrite app_nil_r.
  replace (l1 ++ l3) with (nil ++ (l1 ++ l3)) by auto with datatypes.
  eapply (exec_seq _ _ _ _ m rs); eauto.
  econstructor; eauto.
  econstructor; eauto.
  clear H.


  assert (bigstep ge sp st (m0, b0, rs0)
         (Sbranch
            (Sseq (Sassume (negate_condition cond) args)
               (Sseq
                  (Sloop (Sseq body (Sassume (negate_condition cond) args)))
                  body)) Sskip) af tr3 (m'2, b'2, SIntra rs'0)).
  eapply (refines_loop_parenthesis_aux _ _ _ _ _ _ _ _ H7 (Sassume (negate_condition cond) args) body); reflexivity.
  clear H7.
  inversion_clear H; clarify.
  inversion_clear H5; clarify.
  inversion_clear H7; clarify.
  repeat rewrite <- app_ass.
  rewrite app_ass.
  eapply (exec_seq _ _ _ _ m'4 rs'2); eauto.
  2 : econstructor; eauto.
  inversion H5; clarify.
  inversion H6; clarify.
  rewrite app_nil_r.
  repeat rewrite app_ass.
  replace (l1 ++ l5 ++ l7 ++ l0) with ((l1 ++ l5) ++ (l7 ++ l0)) by auto with datatypes.
  eapply exec_loop_next; eauto.
  econstructor; eauto.
  replace (l7 ++ l0) with ((l7 ++ l0) ++ nil) by auto with datatypes.
  eapply (exec_loop_next _ _ _ _ _ _ m'4); eauto.
  econstructor; eauto.
  congruence.

  inversion_clear H6; clarify.
  repeat rewrite app_ass.
  rewrite <- app_ass.
  eapply exec_loop_next; eauto.
  econstructor; eauto.
  replace (l7 ++ l0 ++ tr4 ++ tr5) with ((l7 ++ l0) ++ (tr4 ++ tr5)) by auto with datatypes.
  econstructor; eauto.
  econstructor; eauto.
  congruence.
  congruence.
  congruence.
  congruence.

  inversion H5; clarify.
  inversion H6; clarify.
  repeat rewrite app_ass; simpl.
  rewrite <- app_ass.
  eapply (exec_seq _ _ _ _ m'3); eauto.
  replace (l1 ++ l0) with ((l1 ++ l0) ++ nil) by auto with datatypes.
  eapply exec_loop_next; eauto.
  econstructor; eauto.
  econstructor; eauto.
  econstructor; eauto.
  congruence.
  congruence.
  assert (bigstep ge sp st (m'0, b'0, rs')
         (Sbranch
            (Sseq (Sassume (negate_condition cond) args)
               (Sseq
                  (Sloop (Sseq body (Sassume (negate_condition cond) args)))
                  body)) Sskip) af tr1 (m'1, b'1, s')).
  apply (refines_loop_parenthesis_aux _ _ _ _ _ _ _ _ H); eauto.
  inversion_clear H4; clarify.
  inversion H5; clarify.
  inversion H9; clarify.
  repeat rewrite <- app_ass.
  econstructor; eauto.
  econstructor; eauto.
  eapply (exec_seq _ _ _ _ m'0); eauto.
  econstructor; eauto.
  eapply (exec_seq_abrupt); eauto.
  rewrite <- app_ass.
  econstructor; eauto.
  econstructor; eauto.

  eapply exec_seq_abrupt; eauto.
  eapply exec_loop_next_abrupt; eauto.
  econstructor; eauto.

  inversion H5; clarify.
  rewrite app_nil_r.
  econstructor; eauto.
  econstructor; eauto.
  econstructor; eauto.

  econstructor; eauto.
  econstructor; eauto.
  econstructor; eauto.
  econstructor; eauto.
Qed.

Lemma refines_branch_left : forall stmt1 stmt2 stmt1',
  refines stmt1 stmt1' ->
  refines (Sbranch stmt1 stmt2) (Sbranch stmt1' stmt2).
Proof.
  intros; apply refines_branch; auto.
  apply refines_refl.
Qed.

Lemma refines_branch_right : forall stmt1 stmt2 stmt2',
  refines stmt2 stmt2' ->
  refines (Sbranch stmt1 stmt2) (Sbranch stmt1 stmt2').
Proof.
  intros; apply refines_branch; auto.
  apply refines_refl.
Qed.

Lemma refines_branch_assoc : forall stmt1 stmt2 stmt3,
  refines (Sbranch (Sbranch stmt1 stmt2) stmt3) (Sbranch stmt1 (Sbranch stmt2 stmt3)).
Proof.
  unfold refines; intros.
  inv H.
  inv H0.
  inv H7.
  econstructor; eauto.
  eapply exec_branch_left; eauto.
  econstructor; eauto.
  eapply exec_branch_right; eauto.
  eapply exec_branch_left; eauto.
  econstructor; eauto.
  eapply exec_branch_right; eauto.
  eapply exec_branch_right; eauto.
Qed.

Lemma refines_skip_stmt : forall stmt,
  refines (Sseq Sskip stmt) stmt.
Proof.
  unfold refines; intros.
  inv H.
  inv H0.
  inv H3.
  simpl.
  econstructor; eauto.
  econstructor; eauto.
  inv H4.
  eelim H8; eauto.
Qed.

Lemma refines_stmt_skipstmt : forall stmt,
  refines stmt (Sseq Sskip stmt).
Proof.
  unfold refines; intros.
  inv H.
  econstructor; eauto.
  replace tr0 with (nil ++ tr0) by auto with datatypes.
  econstructor; eauto.
  econstructor; eauto.
Qed.

Lemma refines_stmt_skip : forall stmt,
  refines (Sseq stmt Sskip) stmt.
Proof.
  unfold refines; intros.
  inv H.
  inv H0.
  inv H5.
  simpl.
  econstructor; eauto.
  replace (l1 ++ nil) with l1 by auto with datatypes; auto.
  econstructor; eauto.
Qed.

Lemma refines_atomic_abort : forall r e,
  refines
    (Sseq (Sfence true) (Sabort Interleaved r e))
    (Satomic true (Sseq Srelease (Sabort Atomic r e))).
Proof.
  unfold refines; intros.
  inv H; econstructor; eauto.
  clear H1.
  inv H0.
  > inv H2; inv H4.
    rewrite app_nil_r.
    econstructor; eauto.
    simpl; auto.
    change (@nil (positive * ext_event)) with (nil ++ @nil (positive * ext_event)).
    econstructor; eauto.
    econstructor; eauto.
    econstructor.
  > inv H3; eelim H7; eauto.
Qed.