(** Translation of parallel moves into sequences of individual moves *) (** The ``parallel move'' problem, also known as ``parallel assignment'', is the following. We are given a list of (source, destination) pairs of locations. The goal is to find a sequence of elementary moves ([loc <- loc] assignments) such that, at the end of the sequence, location [dst] contains the value of location [src] at the beginning of the sequence, for each ([src], [dst]) pairs in the given problem. Moreover, other locations should keep their values, except one register of each type, which can be used as temporaries in the generated sequences. The parallel move problem is trivial if the sources and destinations do not overlap. For instance, << (R1, R2) <- (R3, R4) becomes R1 <- R3; R2 <- R4 >> However, arbitrary overlap is allowed between sources and destinations. This requires some care in ordering the individual moves, as in << (R1, R2) <- (R3, R1) becomes R2 <- R1; R1 <- R3 >> Worse, cycles (permutations) can require the use of temporaries, as in << (R1, R2, R3) <- (R2, R3, R1) becomes T <- R1; R1 <- R2; R2 <- R3; R3 <- T; >> An amazing fact is that for any parallel move problem, at most one temporary (or in our case one integer temporary and one float temporary) is needed. The development in this section was contributed by Laurence Rideau and Bernard Serpette. It is described in their paper ``Coq à la conquête des moulins'', JFLA 2005, ## http://www-sop.inria.fr/lemme/Laurence.Rideau/RideauSerpetteJFLA05.ps ## *) Require Omega. Require Import Wf_nat. Require Import Conventions. Require Import Coqlib. Require Import Bool_nat. Require Import TheoryList. Require Import Bool. Require Import Arith. Require Import Peano_dec. Require Import EqNat. Require Import Values. Require Import LTL. Require Import EqNat. Require Import Locations. Require Import AST. Section pmov. Ltac caseEq name := generalize (refl_equal name); pattern name at -1; case name. Hint Resolve beq_nat_eq . Lemma neq_is_neq: forall (x y : nat), x <> y -> beq_nat x y = false. Proof. unfold not; intros. caseEq (beq_nat x y); auto. intro. elim H; auto. Qed. Hint Resolve neq_is_neq . Lemma app_nil: forall (A : Set) (l : list A), l ++ nil = l. Proof. intros A l; induction l as [|a l Hrecl]; auto; simpl; rewrite Hrecl; auto. Qed. Lemma app_cons: forall (A : Set) (l1 l2 : list A) (a : A), (a :: l1) ++ l2 = a :: (l1 ++ l2). Proof. auto. Qed. Lemma app_app: forall (A : Set) (l1 l2 l3 : list A), l1 ++ (l2 ++ l3) = (l1 ++ l2) ++ l3. Proof. intros A l1; induction l1 as [|a l1 Hrecl1]; simpl; auto; intros; rewrite Hrecl1; auto. Qed. Lemma app_rewrite: forall (A : Set) (l : list A) (x : A), (exists y : A , exists r : list A , l ++ (x :: nil) = y :: r ). Proof. intros A l x; induction l as [|a l Hrecl]. exists x; exists (nil (A:=A)); auto. inversion Hrecl; inversion H. exists a; exists (l ++ (x :: nil)); auto. Qed. Lemma app_rewrite2: forall (A : Set) (l l2 : list A) (x : A), (exists y : A , exists r : list A , l ++ (x :: l2) = y :: r ). Proof. intros A l l2 x; induction l as [|a l Hrecl]. exists x; exists l2; auto. inversion Hrecl; inversion H. exists a; exists (l ++ (x :: l2)); auto. Qed. Lemma app_rewriter: forall (A : Set) (l : list A) (x : A), (exists y : A , exists r : list A , x :: l = r ++ (y :: nil) ). Proof. intros A l x; induction l as [|a l Hrecl]. exists x; exists (nil (A:=A)); auto. inversion Hrecl; inversion H. generalize H0; case x1; simpl; intros; inversion H1. exists a; exists (x0 :: nil); simpl; auto. exists x0; exists (a0 :: (a :: l0)); simpl; auto. Qed. Hint Resolve app_rewriter . Definition Reg := loc. Definition T := fun (r : loc) => match Loc.type r with Tint => R IT2 | Tfloat => R FT2 end. Definition notemporary := fun (r : loc) => forall x, Loc.diff r (T x). Definition Move := (Reg * Reg)%type. Definition Moves := list Move. Definition State := ((Moves * Moves) * Moves)%type. Definition StateToMove (r : State) : Moves := match r with ((t, b), l) => t end. Definition StateBeing (r : State) : Moves := match r with ((t, b), l) => b end. Definition StateDone (r : State) : Moves := match r with ((t, b), l) => l end. Fixpoint noRead (p : Moves) (r : Reg) {struct p} : Prop := match p with nil => True | (s, d) :: l => Loc.diff s r /\ noRead l r end. Lemma noRead_app: forall (l1 l2 : Moves) (r : Reg), noRead l1 r -> noRead l2 r -> noRead (l1 ++ l2) r. Proof. intros; induction l1 as [|a l1 Hrecl1]; simpl; auto. destruct a. elim H; intros; split; auto. Qed. Inductive step : State -> State -> Prop := step_nop: forall (r : Reg) (t1 t2 l : Moves), step (t1 ++ ((r, r) :: t2), nil, l) (t1 ++ t2, nil, l) | step_start: forall (t1 t2 l : Moves) (m : Move), step (t1 ++ (m :: t2), nil, l) (t1 ++ t2, m :: nil, l) | step_push: forall (t1 t2 b l : Moves) (s d r : Reg), step (t1 ++ ((d, r) :: t2), (s, d) :: b, l) (t1 ++ t2, (d, r) :: ((s, d) :: b), l) | step_loop: forall (t b l : Moves) (s d r0 r0ounon : Reg), step (t, (s, r0ounon) :: (b ++ ((r0, d) :: nil)), l) (t, (s, r0ounon) :: (b ++ ((T r0, d) :: nil)), (r0, T r0) :: l) | step_pop: forall (t b l : Moves) (s0 d0 sn dn : Reg), noRead t dn -> Loc.diff dn s0 -> step (t, (sn, dn) :: (b ++ ((s0, d0) :: nil)), l) (t, b ++ ((s0, d0) :: nil), (sn, dn) :: l) | step_last: forall (t l : Moves) (s d : Reg), noRead t d -> step (t, (s, d) :: nil, l) (t, nil, (s, d) :: l) . Hint Resolve step_nop step_start step_push step_loop step_pop step_last . Fixpoint path (l : Moves) : Prop := match l with nil => True | (s, d) :: l => match l with nil => True | (ss, dd) :: l2 => s = dd /\ path l end end. Lemma path_pop: forall (m : Move) (l : Moves), path (m :: l) -> path l. Proof. simpl; intros m l; destruct m as [ms md]; case l; auto. intros m0; destruct m0; intros; inversion H; auto. Qed. Fixpoint noWrite (p : Moves) (r : Reg) {struct p} : Prop := match p with nil => True | (s, d) :: l => Loc.diff d r /\ noWrite l r end. Lemma noWrite_pop: forall (p1 p2 : Moves) (m : Move) (r : Reg), noWrite (p1 ++ (m :: p2)) r -> noWrite (p1 ++ p2) r. Proof. intros; induction p1 as [|a p1 Hrecp1]. generalize H; simpl; case m; intros; inversion H0; auto. generalize H; rewrite app_cons; rewrite app_cons. simpl; case a; intros. inversion H0; split; auto. Qed. Lemma noWrite_in: forall (p1 p2 : Moves) (r0 r1 r2 : Reg), noWrite (p1 ++ ((r1, r2) :: p2)) r0 -> Loc.diff r0 r2. Proof. intros; induction p1 as [|a p1 Hrecp1]; simpl; auto. generalize H; simpl; intros; inversion H0; auto. apply Loc.diff_sym; auto. generalize H; rewrite app_cons; simpl; case a; intros. apply Hrecp1; inversion H0; auto. Qed. Lemma noWrite_swap: forall (p : Moves) (m1 m2 : Move) (r : Reg), noWrite (m1 :: (m2 :: p)) r -> noWrite (m2 :: (m1 :: p)) r. Proof. intros p m1 m2 r; simpl; case m1; case m2. intros; inversion H; inversion H1; split; auto. Qed. Lemma noWrite_movFront: forall (p1 p2 : Moves) (m : Move) (r0 : Reg), noWrite (p1 ++ (m :: p2)) r0 -> noWrite (m :: (p1 ++ p2)) r0. Proof. intros p1 p2 m r0; induction p1 as [|a p1 Hrecp1]; auto. case a; intros r1 r2; rewrite app_cons; rewrite app_cons. intros; apply noWrite_swap; rewrite <- app_cons. simpl in H |-; inversion H; unfold noWrite; fold noWrite; auto. Qed. Lemma noWrite_insert: forall (p1 p2 : Moves) (m : Move) (r0 : Reg), noWrite (m :: (p1 ++ p2)) r0 -> noWrite (p1 ++ (m :: p2)) r0. Proof. intros p1 p2 m r0; induction p1 as [|a p1 Hrecp1]. simpl; auto. destruct a; simpl. destruct m. intros [H1 [H2 H3]]; split; auto. apply Hrecp1. simpl; auto. Qed. Lemma noWrite_tmpLast: forall (t : Moves) (r s d : Reg), noWrite (t ++ ((s, d) :: nil)) r -> forall (x : Reg), noWrite (t ++ ((x, d) :: nil)) r. Proof. intros; induction t as [|a t Hrect]. simpl; auto. generalize H; simpl; case a; intros; inversion H0; split; auto. Qed. Fixpoint simpleDest (p : Moves) : Prop := match p with nil => True | (s, d) :: l => noWrite l d /\ simpleDest l end. Lemma simpleDest_Pop: forall (m : Move) (l1 l2 : Moves), simpleDest (l1 ++ (m :: l2)) -> simpleDest (l1 ++ l2). Proof. intros; induction l1 as [|a l1 Hrecl1]. generalize H; simpl; case m; intros; inversion H0; auto. generalize H; rewrite app_cons; rewrite app_cons. simpl; case a; intros; inversion H0; split; auto. apply (noWrite_pop l1 l2 m); auto. Qed. Lemma simpleDest_pop: forall (m : Move) (l : Moves), simpleDest (m :: l) -> simpleDest l. Proof. intros m l; simpl; case m; intros _ r [X Y]; auto. Qed. Lemma simpleDest_right: forall (l1 l2 : Moves), simpleDest (l1 ++ l2) -> simpleDest l2. Proof. intros l1; induction l1 as [|a l1 Hrecl1]; auto. intros l2; rewrite app_cons; intros; apply Hrecl1. apply (simpleDest_pop a); auto. Qed. Lemma simpleDest_swap: forall (m1 m2 : Move) (l : Moves), simpleDest (m1 :: (m2 :: l)) -> simpleDest (m2 :: (m1 :: l)). Proof. intros m1 m2 l; simpl; case m1; case m2. intros _ r0 _ r2 [[X Y] [Z U]]; auto. (repeat split); auto. apply Loc.diff_sym; auto. Qed. Lemma simpleDest_pop2: forall (m1 m2 : Move) (l : Moves), simpleDest (m1 :: (m2 :: l)) -> simpleDest (m1 :: l). Proof. intros; apply (simpleDest_pop m2); apply simpleDest_swap; auto. Qed. Lemma simpleDest_movFront: forall (p1 p2 : Moves) (m : Move), simpleDest (p1 ++ (m :: p2)) -> simpleDest (m :: (p1 ++ p2)). Proof. intros p1 p2 m; induction p1 as [|a p1 Hrecp1]. simpl; auto. rewrite app_cons; rewrite app_cons. case a; intros; simpl in H |-; inversion H. apply simpleDest_swap; simpl; auto. destruct m. cut (noWrite ((r1, r2) :: (p1 ++ p2)) r0). cut (simpleDest ((r1, r2) :: (p1 ++ p2))). intro; (repeat split); elim H3; elim H2; intros; auto. apply Hrecp1; auto. apply noWrite_movFront; auto. Qed. Lemma simpleDest_insert: forall (p1 p2 : Moves) (m : Move), simpleDest (m :: (p1 ++ p2)) -> simpleDest (p1 ++ (m :: p2)). Proof. intros p1 p2 m; induction p1 as [|a p1 Hrecp1]. simpl; auto. rewrite app_cons; intros. simpl. destruct a as [a1 a2]. split. destruct m; simpl in H |-. apply noWrite_insert. simpl; split; elim H; intros [H1 H2] [H3 H4]; auto. apply Loc.diff_sym; auto. apply Hrecp1. apply simpleDest_pop2 with (a1, a2); auto. Qed. Lemma simpleDest_movBack: forall (p1 p2 : Moves) (m : Move), simpleDest (p1 ++ (m :: p2)) -> simpleDest ((p1 ++ p2) ++ (m :: nil)). Proof. intros. apply (simpleDest_insert (p1 ++ p2) nil m). rewrite app_nil; apply simpleDest_movFront; auto. Qed. Lemma simpleDest_swap_app: forall (t1 t2 t3 : Moves) (m : Move), simpleDest (t1 ++ (m :: (t2 ++ t3))) -> simpleDest ((t1 ++ t2) ++ (m :: t3)). Proof. intros. apply (simpleDest_insert (t1 ++ t2) t3 m). rewrite <- app_app. apply simpleDest_movFront; auto. Qed. Lemma simpleDest_tmpLast: forall (t : Moves) (s d : Reg), simpleDest (t ++ ((s, d) :: nil)) -> forall (r : Reg), simpleDest (t ++ ((r, d) :: nil)). Proof. intros t s d; induction t as [|a t Hrect]. simpl; auto. simpl; case a; intros; inversion H; split; auto. apply (noWrite_tmpLast t r0 s); auto. Qed. Fixpoint noTmp (b : Moves) : Prop := match b with nil => True | (s, d) :: l => (forall r, Loc.diff s (T r)) /\ ((forall r, Loc.diff d (T r)) /\ noTmp l) end. Fixpoint noTmpLast (b : Moves) : Prop := match b with nil => True | (s, d) :: nil => forall r, Loc.diff d (T r) | (s, d) :: l => (forall r, Loc.diff s (T r)) /\ ((forall r, Loc.diff d (T r)) /\ noTmpLast l) end. Lemma noTmp_app: forall (l1 l2 : Moves) (m : Move), noTmp l1 -> noTmpLast (m :: l2) -> noTmpLast (l1 ++ (m :: l2)). Proof. intros. induction l1 as [|a l1 Hrecl1]. simpl; auto. simpl. caseEq (l1 ++ (m :: l2)); intro. destruct a. elim H; intros; auto. inversion H; auto. elim H3; auto. intros; destruct a as [a1 a2]. elim H; intros H2 [H3 H4]; auto. (repeat split); auto. rewrite H1 in Hrecl1; apply Hrecl1; auto. Qed. Lemma noTmpLast_popBack: forall (t : Moves) (m : Move), noTmpLast (t ++ (m :: nil)) -> noTmp t. Proof. intros. induction t as [|a t Hrect]. simpl; auto. destruct a as [a1 a2]. rewrite app_cons in H. simpl. simpl in H |-. generalize H; caseEq (t ++ (m :: nil)); intros. destruct t; inversion H0. elim H1. intros H2 [H3 H4]; (repeat split); auto. rewrite <- H0 in H4. apply Hrect; auto. Qed. Fixpoint getsrc (p : Moves) : list Reg := match p with nil => nil | (s, d) :: l => s :: getsrc l end. Fixpoint getdst (p : Moves) : list Reg := match p with nil => nil | (s, d) :: l => d :: getdst l end. Fixpoint noOverlap_aux (r : Reg) (l : list Reg) {struct l} : Prop := match l with nil => True | b :: m => (b = r \/ Loc.diff b r) /\ noOverlap_aux r m end. Definition noOverlap (p : Moves) : Prop := forall l, In l (getsrc p) -> noOverlap_aux l (getdst p). Definition stepInv (r : State) : Prop := path (StateBeing r) /\ (simpleDest (StateToMove r ++ StateBeing r) /\ (noOverlap (StateToMove r ++ StateBeing r) /\ (noTmp (StateToMove r) /\ noTmpLast (StateBeing r)))). Definition Value := val. Definition Env := locset. Definition get (e : Env) (r : Reg) := Locmap.get r e. Definition update (e : Env) (r : Reg) (v : Value) : Env := Locmap.set r v e. Fixpoint sexec (p : Moves) (e : Env) {struct p} : Env := match p with nil => e | (s, d) :: l => let e' := sexec l e in update e' d (get e' s) end. Fixpoint pexec (p : Moves) (e : Env) {struct p} : Env := match p with nil => e | (s, d) :: l => update (pexec l e) d (get e s) end. Lemma get_update: forall (e : Env) (r1 r2 : Reg) (v : Value), get (update e r1 v) r2 = (if Loc.eq r1 r2 then v else if Loc.overlap r1 r2 then Vundef else get e r2). Proof. intros. unfold update, get, Locmap.get, Locmap.set; trivial. Qed. Lemma get_update_id: forall (e : Env) (r1 : Reg) (v : Value), get (update e r1 v) r1 = v. Proof. intros e r1 v; rewrite (get_update e r1 r1); auto. case (Loc.eq r1 r1); auto. intros H; elim H; trivial. Qed. Lemma get_update_diff: forall (e : Env) (r1 r2 : Reg) (v : Value), Loc.diff r1 r2 -> get (update e r1 v) r2 = get e r2. Proof. intros; unfold update, get, Locmap.get, Locmap.set. case (Loc.eq r1 r2); intro. absurd (r1 = r2); [apply Loc.diff_not_eq; trivial | trivial]. caseEq (Loc.overlap r1 r2); intro; trivial. absurd (Loc.diff r1 r2); [apply Loc.overlap_not_diff; assumption | assumption]. Qed. Lemma get_update_ndiff: forall (e : Env) (r1 r2 : Reg) (v : Value), r1 <> r2 -> not (Loc.diff r1 r2) -> get (update e r1 v) r2 = Vundef. Proof. intros; unfold update, get, Locmap.get, Locmap.set. case (Loc.eq r1 r2); intro. absurd (r1 = r2); assumption. caseEq (Loc.overlap r1 r2); intro; trivial. absurd (Loc.diff r1 r2); (try assumption). apply Loc.non_overlap_diff; assumption. Qed. Lemma pexec_swap: forall (m1 m2 : Move) (t : Moves), simpleDest (m1 :: (m2 :: t)) -> forall (e : Env) (r : Reg), get (pexec (m1 :: (m2 :: t)) e) r = get (pexec (m2 :: (m1 :: t)) e) r. Proof. intros; destruct m1 as [m1s m1d]; destruct m2 as [m2s m2d]. generalize H; simpl; intros [[NEQ NW] [NW2 HSD]]; clear H. case (Loc.eq m1d r); case (Loc.eq m2d r); intros. absurd (m1d = m2d); [apply Loc.diff_not_eq; apply Loc.diff_sym; assumption | rewrite e0; rewrite e1; trivial]. caseEq (Loc.overlap m2d r); intro. absurd (Loc.diff m2d m1d); [apply Loc.overlap_not_diff; rewrite e0 | idtac]; (try assumption). subst m1d; rewrite get_update_id; rewrite get_update_diff; (try rewrite get_update_id); auto. caseEq (Loc.overlap m1d r); intro. absurd (Loc.diff m1d m2d); [apply Loc.overlap_not_diff; rewrite e0 | apply Loc.diff_sym]; assumption. subst m2d; (repeat rewrite get_update_id); rewrite get_update_diff; [rewrite get_update_id; trivial | apply Loc.diff_sym; trivial]. caseEq (Loc.overlap m1d r); caseEq (Loc.overlap m2d r); intros. (repeat rewrite get_update_ndiff); (try (apply Loc.overlap_not_diff; assumption)); trivial. assert (~ Loc.diff m1d r); [apply Loc.overlap_not_diff; assumption | intros; rewrite get_update_ndiff; auto]. rewrite get_update_diff; [rewrite get_update_ndiff; auto | apply Loc.non_overlap_diff; auto]. cut (~ Loc.diff m2d r); [idtac | apply Loc.overlap_not_diff; auto]. cut (Loc.diff m1d r); [idtac | apply Loc.non_overlap_diff; auto]. intros; rewrite get_update_diff; auto. (repeat rewrite get_update_ndiff); auto. cut (Loc.diff m1d r); [idtac | apply Loc.non_overlap_diff; auto]. cut (Loc.diff m2d r); [idtac | apply Loc.non_overlap_diff; auto]. intros; (repeat rewrite get_update_diff); auto. Qed. Lemma pexec_add: forall (t1 t2 : Moves) (r : Reg) (e : Env), get (pexec t1 e) r = get (pexec t2 e) r -> forall (a : Move), get (pexec (a :: t1) e) r = get (pexec (a :: t2) e) r. Proof. intros. case a. simpl. intros a1 a2. unfold get, update, Locmap.set, Locmap.get. case (Loc.eq a2 r); case (Loc.overlap a2 r); auto. Qed. Lemma pexec_movBack: forall (t1 t2 : Moves) (m : Move), simpleDest (m :: (t1 ++ t2)) -> forall (e : Env) (r : Reg), get (pexec (m :: (t1 ++ t2)) e) r = get (pexec (t1 ++ (m :: t2)) e) r. Proof. intros t1 t2 m; induction t1 as [|a t1 Hrect1]. simpl; auto. rewrite app_cons. intros; rewrite pexec_swap; auto; rewrite app_cons; auto. apply pexec_add. apply Hrect1. apply (simpleDest_pop2 m a); auto. Qed. Lemma pexec_movFront: forall (t1 t2 : Moves) (m : Move), simpleDest (t1 ++ (m :: t2)) -> forall (e : Env) (r : Reg), get (pexec (t1 ++ (m :: t2)) e) r = get (pexec (m :: (t1 ++ t2)) e) r. Proof. intros; rewrite <- pexec_movBack; eauto. apply simpleDest_movFront; auto. Qed. Lemma pexec_mov: forall (t1 t2 t3 : Moves) (m : Move), simpleDest ((t1 ++ (m :: t2)) ++ t3) -> forall (e : Env) (r : Reg), get (pexec ((t1 ++ (m :: t2)) ++ t3) e) r = get (pexec ((t1 ++ t2) ++ (m :: t3)) e) r. Proof. intros t1 t2 t3 m. rewrite <- app_app. rewrite app_cons. intros. rewrite pexec_movFront; auto. cut (simpleDest (m :: (t1 ++ (t2 ++ t3)))). rewrite app_app. rewrite <- pexec_movFront; auto. apply simpleDest_swap_app; auto. apply simpleDest_movFront; auto. Qed. Definition diff_dec: forall (x y : Reg), ({ Loc.diff x y }) + ({ not (Loc.diff x y) }). intros. case (Loc.eq x y). intros heq; right. red; intro; absurd (x = y); auto. apply Loc.diff_not_eq; auto. intro; caseEq (Loc.overlap x y). intro; right. apply Loc.overlap_not_diff; auto. intro; left; apply Loc.non_overlap_diff; auto. Defined. Lemma get_pexec_id_noWrite: forall (t : Moves) (d : Reg), noWrite t d -> forall (e : Env) (v : Value), v = get (pexec t (update e d v)) d. Proof. intros. induction t as [|a t Hrect]. simpl. rewrite get_update_id; auto. generalize H; destruct a as [a1 a2]; simpl; intros [NEQ R]. rewrite get_update_diff; auto. Qed. Lemma pexec_nop: forall (t : Moves) (r : Reg) (e : Env) (x : Reg), Loc.diff r x -> get (pexec ((r, r) :: t) e) x = get (pexec t e) x. Proof. intros. simpl. rewrite get_update_diff; auto. Qed. Lemma sD_nW: forall t r s, simpleDest ((s, r) :: t) -> noWrite t r. Proof. induction t. simpl; auto. simpl. destruct a. intros r1 r2 H; split; [try assumption | idtac]. elim H; [intros H0 H1; elim H0; [intros H2 H3; (try clear H0 H); (try exact H2)]]. elim H; [intros H0 H1; elim H0; [intros H2 H3; (try clear H0 H); (try exact H3)]]. Qed. Lemma sD_pexec: forall (t : Moves) (s d : Reg), simpleDest ((s, d) :: t) -> forall (e : Env), get (pexec t e) d = get e d. Proof. intros. induction t as [|a t Hrect]; simpl; auto. destruct a as [a1 a2]. simpl in H |-; elim H; intros [H0 H1] [H2 H3]; clear H. case (Loc.eq a2 d); intro. absurd (a2 = d); [apply Loc.diff_not_eq | trivial]; assumption. rewrite get_update_diff; (try assumption). apply Hrect. simpl; (split; assumption). Qed. Lemma noOverlap_nil: noOverlap nil. Proof. unfold noOverlap, noOverlap_aux, getsrc, getdst; trivial. Qed. Lemma getsrc_add: forall (m : Move) (l1 l2 : Moves) (l : Reg), In l (getsrc (l1 ++ l2)) -> In l (getsrc (l1 ++ (m :: l2))). Proof. intros m l1 l2 l; destruct m; induction l1; simpl; auto. destruct a; simpl; intros. elim H; intros H0; [left | right]; auto. Qed. Lemma getdst_add: forall (r1 r2 : Reg) (l1 l2 : Moves), getdst (l1 ++ ((r1, r2) :: l2)) = getdst l1 ++ (r2 :: getdst l2). Proof. intros r1 r2 l1 l2; induction l1; simpl; auto. destruct a; simpl; rewrite IHl1; auto. Qed. Lemma getdst_app: forall (l1 l2 : Moves), getdst (l1 ++ l2) = getdst l1 ++ getdst l2. Proof. intros; induction l1; simpl; auto. destruct a; simpl; rewrite IHl1; auto. Qed. Lemma noOverlap_auxpop: forall (x r : Reg) (l : list Reg), noOverlap_aux x (r :: l) -> noOverlap_aux x l. Proof. induction l; simpl; auto. intros [H1 [H2 H3]]; split; auto. Qed. Lemma noOverlap_auxPop: forall (x r : Reg) (l1 l2 : list Reg), noOverlap_aux x (l1 ++ (r :: l2)) -> noOverlap_aux x (l1 ++ l2). Proof. intros x r l1 l2; (try assumption). induction l1 as [|a l1 Hrecl1]; simpl app. intro; apply (noOverlap_auxpop x r); auto. (repeat rewrite app_cons); simpl. intros [H1 H2]; split; auto. Qed. Lemma noOverlap_pop: forall (m : Move) (l : Moves), noOverlap (m :: l) -> noOverlap l. Proof. induction l. intro; apply noOverlap_nil. unfold noOverlap; simpl; destruct m; destruct a; simpl; intros. elim (H l0); intros; (try assumption). elim H0; intros H1; right; [left | right]; assumption. Qed. Lemma noOverlap_Pop: forall (m : Move) (l1 l2 : Moves), noOverlap (l1 ++ (m :: l2)) -> noOverlap (l1 ++ l2). Proof. intros m l1 l2; induction l1 as [|a l1 Hrecl1]; simpl. simpl; apply noOverlap_pop. (repeat rewrite app_cons); unfold noOverlap; destruct a; simpl. intros H l H0; split. elim (H l); [intros H1 H2 | idtac]; auto. elim H0; [intros H3; left | intros H3; right; apply getsrc_add]; auto. unfold noOverlap in Hrecl1 |-. elim H0; intros H1; clear H0. destruct m; rewrite getdst_app; apply noOverlap_auxPop with ( r := r2 ). rewrite getdst_add in H. elim H with ( l := l ); [intros H0 H2; (try clear H); (try exact H2) | idtac]. left; (try assumption). apply Hrecl1 with ( l := l ); auto. intros l0 H0; (try assumption). elim H with ( l := l0 ); [intros H2 H3; (try clear H); (try exact H3) | idtac]; auto. Qed. Lemma noOverlap_right: forall (l1 l2 : Moves), noOverlap (l1 ++ l2) -> noOverlap l2. Proof. intros l1; induction l1 as [|a l1 Hrecl1]; auto. intros l2; rewrite app_cons; intros; apply Hrecl1. apply (noOverlap_pop a); auto. Qed. Lemma pexec_update: forall t e d r v, Loc.diff d r -> noRead t d -> get (pexec t (update e d v)) r = get (pexec t e) r. Proof. induction t; simpl. intros; rewrite get_update_diff; auto. destruct a as [a1 a2]; intros; case (Loc.eq a2 r); intro. subst a2; (repeat rewrite get_update_id). rewrite get_update_diff; auto; apply Loc.diff_sym; elim H0; auto. case (diff_dec a2 r); intro. (repeat rewrite get_update_diff); auto. apply IHt; auto. elim H0; auto. (repeat rewrite get_update_ndiff); auto. Qed. Lemma pexec_push: forall (t l : Moves) (s d : Reg), noRead t d -> simpleDest ((s, d) :: t) -> forall (e : Env) (r : Reg), r = d \/ Loc.diff d r -> get (pexec ((s, d) :: t) (sexec l e)) r = get (pexec t (sexec ((s, d) :: l) e)) r. Proof. intros; simpl. elim H1; intros e1. rewrite e1; rewrite get_update_id; auto. rewrite (sD_pexec t s d); auto; rewrite get_update_id; auto. rewrite pexec_update; auto. rewrite get_update_diff; auto. Qed. Definition exec (s : State) (e : Env) := pexec (StateToMove s ++ StateBeing s) (sexec (StateDone s) e). Definition sameEnv (e1 e2 : Env) := forall (r : Reg), notemporary r -> get e1 r = get e2 r. Definition NoOverlap (r : Reg) (s : State) := noOverlap ((r, r) :: (StateToMove s ++ StateBeing s)). Lemma noOverlapaux_swap2: forall (l1 l2 : list Reg) (m l : Reg), noOverlap_aux l (l1 ++ (m :: l2)) -> noOverlap_aux l (m :: (l1 ++ l2)). Proof. intros l1 l2 m l; induction l1; simpl noOverlap_aux; auto. intros; elim H; intros H0 H1; (repeat split); auto. simpl in IHl1 |-. elim IHl1; [intros H2 H3; (try exact H2) | idtac]; auto. apply (noOverlap_auxpop l m). apply IHl1; auto. Qed. Lemma noTmp_noReadTmp: forall t, noTmp t -> forall s, noRead t (T s). Proof. induction t; simpl; auto. destruct a as [a1 a2]; intros. split; [idtac | apply IHt]; elim H; intros H1 [H2 H3]; auto. Qed. Lemma noRead_by_path: forall (b t : Moves) (r0 r1 r7 r8 : Reg), simpleDest ((r7, r8) :: (b ++ ((r0, r1) :: nil))) -> path (b ++ ((r0, r1) :: nil)) -> Loc.diff r8 r0 -> noRead b r8. Proof. intros; induction b as [|a b Hrecb]; simpl; auto. destruct a as [a1 a2]; generalize H H0; rewrite app_cons; intros; split. simpl in H3 |-; caseEq (b ++ ((r0, r1) :: nil)); intro. destruct b; inversion H4. intros l H4. rewrite H4 in H3. destruct m. rewrite H4 in H2; simpl in H2 |-. elim H3; [intros H5 H6; (try clear H3); (try exact H5)]. rewrite H5. elim H2; intros [H3 [H7 H8]] [H9 [H10 H11]]; (try assumption). apply Hrecb. apply (simpleDest_pop (a1, a2)); apply simpleDest_swap; auto. apply (path_pop (a1, a2)); auto. Qed. Lemma noOverlap_swap: forall (m1 m2 : Move) (l : Moves), noOverlap (m1 :: (m2 :: l)) -> noOverlap (m2 :: (m1 :: l)). Proof. intros m1 m2 l; simpl; destruct m1 as [m1s m1d]; destruct m2 as [m2s m2d]. unfold noOverlap; simpl; intros. assert (m1s = l0 \/ (m2s = l0 \/ In l0 (getsrc l))). elim H0; [intros H1 | intros [H1|H2]]. right; left; (try assumption). left; (try assumption). right; right; (try assumption). (repeat split); (elim (H l0); [intros H2 H3; elim H3; [intros H4 H5] | idtac]; auto). Qed. Lemma getsrc_add1: forall (r1 r2 : Reg) (l1 l2 : Moves), getsrc (l1 ++ ((r1, r2) :: l2)) = getsrc l1 ++ (r1 :: getsrc l2). Proof. intros r1 r2 l1 l2; induction l1; simpl; auto. destruct a; simpl; rewrite IHl1; auto. Qed. Lemma getsrc_app: forall (l1 l2 : Moves), getsrc (l1 ++ l2) = getsrc l1 ++ getsrc l2. Proof. intros; induction l1; simpl; auto. destruct a; simpl; rewrite IHl1; auto. Qed. Lemma Ingetsrc_swap: forall (m : Move) (l1 l2 : Moves) (l : Reg), In l (getsrc (m :: (l1 ++ l2))) -> In l (getsrc (l1 ++ (m :: l2))). Proof. intros; destruct m as [m1 m2]; simpl; auto. simpl in H |-. elim H; intros H0; auto. rewrite H0; rewrite getsrc_add1; auto. apply (in_or_app (getsrc l1) (l :: getsrc l2)); auto. right; apply in_eq; auto. apply getsrc_add; auto. Qed. Lemma noOverlap_movFront: forall (p1 p2 : Moves) (m : Move), noOverlap (p1 ++ (m :: p2)) -> noOverlap (m :: (p1 ++ p2)). Proof. intros p1 p2 m; unfold noOverlap. destruct m; rewrite getdst_add; simpl getdst; rewrite getdst_app; intros. apply noOverlapaux_swap2. apply (H l); apply Ingetsrc_swap; auto. Qed. Lemma step_inv_loop_aux: forall (t l : Moves) (s d : Reg), simpleDest (t ++ ((s, d) :: nil)) -> noTmp t -> forall (e : Env) (r : Reg), notemporary r -> d = r \/ Loc.diff d r -> get (pexec (t ++ ((s, d) :: nil)) (sexec l e)) r = get (pexec (t ++ ((T s, d) :: nil)) (sexec ((s, T s) :: l) e)) r. Proof. intros; (repeat rewrite pexec_movFront); auto. (repeat rewrite app_nil); simpl; elim H2; intros e1. subst d; (repeat rewrite get_update_id); auto. (repeat rewrite get_update_diff); auto. rewrite pexec_update; auto. apply Loc.diff_sym; unfold notemporary in H1 |-; auto. apply noTmp_noReadTmp; auto. apply (simpleDest_tmpLast t s); auto. Qed. Lemma step_inv_loop: forall (t l : Moves) (s d : Reg), simpleDest (t ++ ((s, d) :: nil)) -> noTmpLast (t ++ ((s, d) :: nil)) -> forall (e : Env) (r : Reg), notemporary r -> d = r \/ Loc.diff d r -> get (pexec (t ++ ((s, d) :: nil)) (sexec l e)) r = get (pexec (t ++ ((T s, d) :: nil)) (sexec ((s, T s) :: l) e)) r. Proof. intros; apply step_inv_loop_aux; auto. apply (noTmpLast_popBack t (s, d)); auto. Qed. Definition sameExec (s1 s2 : State) := forall (e : Env) (r : Reg), (let A := getdst ((StateToMove s1 ++ StateBeing s1) ++ (StateToMove s2 ++ StateBeing s2)) in notemporary r -> (forall x, In x A -> r = x \/ Loc.diff r x) -> get (exec s1 e) r = get (exec s2 e) r). Lemma get_noWrite: forall (t : Moves) (d : Reg), noWrite t d -> forall (e : Env), get e d = get (pexec t e) d. Proof. intros; induction t as [|a t Hrect]; simpl; auto. generalize H; destruct a as [a1 a2]; simpl; intros [NEQ R]. unfold get, Locmap.get, update, Locmap.set. case (Loc.eq a2 d); intro; auto. absurd (a2 = d); auto; apply Loc.diff_not_eq; (try assumption). caseEq (Loc.overlap a2 d); intro. absurd (Loc.diff a2 d); auto; apply Loc.overlap_not_diff; auto. unfold get, Locmap.get in Hrect |-; apply Hrect; auto. Qed. Lemma step_sameExec: forall (r1 r2 : State), step r1 r2 -> stepInv r1 -> sameExec r1 r2. Proof. intros r1 r2 STEP; inversion STEP; unfold stepInv, sameExec, NoOverlap, exec, StateToMove, StateBeing, StateDone; (repeat rewrite app_nil); intros [P [SD [NO [TT TB]]]]; intros. rewrite pexec_movFront; simpl; auto. case (Loc.eq r r0); intros e0. subst r0; rewrite get_update_id; apply get_noWrite; apply sD_nW with r; apply simpleDest_movFront; auto. elim H2 with ( x := r ); [intros H3; absurd (r = r0); auto | intros H3; rewrite get_update_diff; auto; apply Loc.diff_sym; auto | idtac]. (repeat (rewrite getdst_app; simpl)); apply in_or_app; left; apply in_or_app; right; simpl; auto. (repeat rewrite pexec_movFront); auto. rewrite app_nil; auto. apply simpleDest_movBack; auto. apply pexec_mov; auto. repeat (rewrite <- app_cons; rewrite app_app). apply step_inv_loop; auto. repeat (rewrite <- app_app; rewrite app_cons; auto). repeat (rewrite <- app_app; rewrite app_cons; auto). apply noTmp_app; auto. elim H2 with ( x := d ); [intros H3; left; auto | intros H3; right; apply Loc.diff_sym; auto | try clear H2]. repeat (rewrite getdst_app; simpl). apply in_or_app; left; apply in_or_app; right; simpl; right; apply in_or_app; right; simpl; left; trivial. rewrite pexec_movFront; auto; apply pexec_push; auto. apply noRead_app; auto. apply noRead_app. apply (noRead_by_path b b s0 d0 sn dn); auto. apply (simpleDest_right t); auto. apply (path_pop (sn, dn)); auto. simpl; split; [apply Loc.diff_sym | idtac]; auto. apply simpleDest_movFront; auto. elim H4 with ( x := dn ); [intros H5 | intros H5 | try clear H4]. left; (try assumption). right; apply Loc.diff_sym; (try assumption). repeat (rewrite getdst_app; simpl). apply in_or_app; left; apply in_or_app; right; simpl; left; trivial. rewrite pexec_movFront; auto. rewrite app_nil; auto. apply pexec_push; auto. rewrite <- (app_nil _ t). apply simpleDest_movFront; auto. elim (H3 d); (try intros H4). left; (try assumption). right; apply Loc.diff_sym; (try assumption). (repeat rewrite getdst_app); simpl; apply in_or_app; left; apply in_or_app; right; simpl; left; trivial. Qed. Lemma path_tmpLast: forall (s d : Reg) (l : Moves), path (l ++ ((s, d) :: nil)) -> path (l ++ ((T s, d) :: nil)). Proof. intros; induction l as [|a l Hrecl]. simpl; auto. generalize H; (repeat rewrite app_cons). case a; generalize Hrecl; case l; intros; auto. destruct m; intros. inversion H0; split; auto. Qed. Lemma step_inv_path: forall (r1 r2 : State), step r1 r2 -> stepInv r1 -> path (StateBeing r2). Proof. intros r1 r2 STEP; inversion_clear STEP; unfold stepInv; unfold stepInv, sameExec, sameEnv, exec, StateToMove, StateBeing, StateDone; intros [P [SD [TT TB]]]; (try (simpl; auto; fail)). simpl; case m; auto. generalize P; rewrite <- app_cons; rewrite <- app_cons. apply (path_tmpLast r0). generalize P; apply path_pop. Qed. Lemma step_inv_simpleDest: forall (r1 r2 : State), step r1 r2 -> stepInv r1 -> simpleDest (StateToMove r2 ++ StateBeing r2). Proof. intros r1 r2 STEP; inversion_clear STEP; unfold stepInv; unfold stepInv, sameExec, sameEnv, exec, StateToMove, StateBeing, StateDone; (repeat rewrite app_nil); intros [P [SD [TT TB]]]. apply (simpleDest_Pop (r, r)); assumption. apply simpleDest_movBack; assumption. apply simpleDest_insert; rewrite <- app_app; apply simpleDest_movFront. rewrite <- app_cons; rewrite app_app; auto. generalize SD; (repeat rewrite <- app_cons); (repeat rewrite app_app). generalize (simpleDest_tmpLast (t ++ ((s, r0ounon) :: b)) r0 d); auto. generalize SD; apply simpleDest_Pop. rewrite <- (app_nil _ t); generalize SD; apply simpleDest_Pop. Qed. Lemma noTmp_pop: forall (m : Move) (l1 l2 : Moves), noTmp (l1 ++ (m :: l2)) -> noTmp (l1 ++ l2). Proof. intros; induction l1 as [|a l1 Hrecl1]; generalize H. simpl; case m; intros; inversion H0; inversion H2; auto. rewrite app_cons; rewrite app_cons; simpl; case a. intros; inversion H0; inversion H2; auto. Qed. Lemma step_inv_noTmp: forall (r1 r2 : State), step r1 r2 -> stepInv r1 -> noTmp (StateToMove r2). Proof. intros r1 r2 STEP; inversion_clear STEP; unfold stepInv; unfold stepInv, sameExec, sameEnv, exec, StateToMove, StateBeing, StateDone; intros [P [SD [NO [TT TB]]]]; generalize TT; (try apply noTmp_pop); auto. Qed. Lemma noTmp_noTmpLast: forall (l : Moves), noTmp l -> noTmpLast l. Proof. intros; induction l as [|a l Hrecl]; (try (simpl; auto; fail)). generalize H; simpl; case a; generalize Hrecl; case l; (intros; inversion H0; inversion H2; auto). Qed. Lemma noTmpLast_pop: forall (m : Move) (l : Moves), noTmpLast (m :: l) -> noTmpLast l. Proof. intros m l; simpl; case m; case l. simpl; auto. intros; inversion H; inversion H1; auto. Qed. Lemma noTmpLast_Pop: forall (m : Move) (l1 l2 : Moves), noTmpLast (l1 ++ (m :: l2)) -> noTmpLast (l1 ++ l2). Proof. intros; induction l1 as [|a l1 Hrecl1]; generalize H. simpl; case m; case l2. simpl; auto. intros. elim H0; [intros H1 H2; elim H2; [intros H3 H4; (try exact H4)]]. (repeat rewrite app_cons); simpl; case a. generalize Hrecl1; case l1. simpl; case m; case l2; intros; inversion H0; inversion H2; auto. intros m0 l R r r0; rewrite app_cons; rewrite app_cons. intros; inversion H0; inversion H2; auto. Qed. Lemma noTmpLast_push: forall (m : Move) (t1 t2 t3 : Moves), noTmp (t1 ++ (m :: t2)) -> noTmpLast t3 -> noTmpLast (m :: t3). Proof. intros; induction t1 as [|a t1 Hrect1]; generalize H. simpl; case m; intros r r0 [N1 [N2 NT]]; generalize H0; case t3; auto. rewrite app_cons; intros; apply Hrect1. generalize H1. simpl; case m; case a; intros; inversion H2; inversion H4; auto. Qed. Lemma noTmpLast_tmpLast: forall (s d : Reg) (l : Moves), noTmpLast (l ++ ((s, d) :: nil)) -> noTmpLast (l ++ ((T s, d) :: nil)). Proof. intros; induction l as [|a l Hrecl]. simpl; auto. generalize H; rewrite app_cons; rewrite app_cons; simpl. case a; generalize Hrecl; case l. simpl; auto. intros m l0 REC r r0; generalize REC; rewrite app_cons; rewrite app_cons. case m; intros; inversion H0; inversion H2; split; auto. Qed. Lemma step_inv_noTmpLast: forall (r1 r2 : State), step r1 r2 -> stepInv r1 -> noTmpLast (StateBeing r2). Proof. intros r1 r2 STEP; inversion_clear STEP; unfold stepInv; unfold stepInv, sameExec, sameEnv, exec, StateToMove, StateBeing, StateDone; intros [P [SD [NO [TT TB]]]]; auto. apply (noTmpLast_push m t1 t2); auto. apply (noTmpLast_push (d, r) t1 t2); auto. generalize TB; rewrite <- app_cons; rewrite <- app_cons; apply noTmpLast_tmpLast. apply (noTmpLast_pop (sn, dn)); auto. Qed. Lemma noOverlapaux_insert: forall (l1 l2 : list Reg) (r x : Reg), noOverlap_aux x (r :: (l1 ++ l2)) -> noOverlap_aux x (l1 ++ (r :: l2)). Proof. simpl; intros; induction l1; simpl; split. elim H; [intros H0 H1; (try exact H0)]. elim H; [intros H0 H1; (try exact H1)]. simpl in H |-. elim H; [intros H0 H1; elim H1; [intros H2 H3; (try clear H1 H); (try exact H2)]]. apply IHl1. split. elim H; [intros H0 H1; (try exact H0)]. rewrite app_cons in H. apply noOverlap_auxpop with ( r := a ). elim H; [intros H0 H1; (try exact H1)]. Qed. Lemma Ingetsrc_swap2: forall (m : Move) (l1 l2 : Moves) (l : Reg), In l (getsrc (l1 ++ (m :: l2))) -> In l (getsrc (m :: (l1 ++ l2))). Proof. intros; destruct m as [m1 m2]; simpl; auto. induction l1; simpl. simpl in H |-; auto. destruct a; simpl. simpl in H |-. elim H; [intros H0 | intros H0; (try exact H0)]. right; left; (try assumption). elim IHl1; intros; auto. Qed. Lemma noOverlap_insert: forall (p1 p2 : Moves) (m : Move), noOverlap (m :: (p1 ++ p2)) -> noOverlap (p1 ++ (m :: p2)). Proof. unfold noOverlap; destruct m; rewrite getdst_add; simpl getdst; rewrite getdst_app. intros. apply noOverlapaux_insert. generalize (H l); intros H1; lapply H1; [intros H2; (try clear H1); (try exact H2) | idtac]. simpl getsrc. generalize (Ingetsrc_swap2 (r, r0)); simpl; (intros; auto). Qed. Lemma noOverlap_movBack: forall (p1 p2 : Moves) (m : Move), noOverlap (p1 ++ (m :: p2)) -> noOverlap ((p1 ++ p2) ++ (m :: nil)). Proof. intros. apply (noOverlap_insert (p1 ++ p2) nil m). rewrite app_nil; apply noOverlap_movFront; auto. Qed. Lemma noOverlap_movBack0: forall (t : Moves) (s d : Reg), noOverlap ((s, d) :: t) -> noOverlap (t ++ ((s, d) :: nil)). Proof. intros t s d H; (try assumption). apply noOverlap_insert. rewrite app_nil; auto. Qed. Lemma noOverlap_Front0: forall (t : Moves) (s d : Reg), noOverlap (t ++ ((s, d) :: nil)) -> noOverlap ((s, d) :: t). Proof. intros t s d H; (try assumption). cut ((s, d) :: t = (s, d) :: (t ++ nil)). intros e; rewrite e. apply noOverlap_movFront; auto. rewrite app_nil; auto. Qed. Lemma noTmpL_diff: forall (t : Moves) (s d : Reg), noTmpLast (t ++ ((s, d) :: nil)) -> notemporary d. Proof. intros t s d; unfold notemporary; induction t; (try (simpl; intros; auto; fail)). rewrite app_cons. intros; apply IHt. apply (noTmpLast_pop a); auto. Qed. Lemma noOverlap_aux_app: forall l1 l2 (r : Reg), noOverlap_aux r l1 -> noOverlap_aux r l2 -> noOverlap_aux r (l1 ++ l2). Proof. induction l1; simpl; auto. intros; split. elim H; [intros H1 H2; (try clear H); (try exact H1)]. apply IHl1; auto. elim H; [intros H1 H2; (try clear H); (try exact H2)]. Qed. Lemma noTmP_noOverlap_aux: forall t (r : Reg), noTmp t -> noOverlap_aux (T r) (getdst t). Proof. induction t; simpl; auto. destruct a; simpl; (intros; split). elim H; intros; elim H1; intros. right; apply H2. apply IHt; auto. elim H; [intros H0 H1; elim H1; [intros H2 H3; (try clear H1 H); (try exact H3)]]. Qed. Lemma noTmp_append: forall l1 l2, noTmp l1 -> noTmp l2 -> noTmp (l1 ++ l2). Proof. induction l1; simpl; auto. destruct a. intros l2 [H1 [H2 H3]] H4. (repeat split); auto. Qed. Lemma step_inv_noOverlap: forall (r1 r2 : State), step r1 r2 -> stepInv r1 -> noOverlap (StateToMove r2 ++ StateBeing r2). Proof. intros r1 r2 STEP; inversion_clear STEP; unfold stepInv; unfold stepInv, sameExec, sameEnv, exec, StateToMove, StateBeing, StateDone; (repeat rewrite app_nil); intros [P [SD [NO [TT TB]]]]; (try (generalize NO; apply noOverlap_Pop; auto; fail)). apply noOverlap_movBack; auto. apply noOverlap_insert; rewrite <- app_app; apply noOverlap_movFront; rewrite <- app_cons; rewrite app_app; auto. generalize NO; (repeat rewrite <- app_cons); (repeat rewrite app_app); (clear NO; intros NO); apply noOverlap_movBack0. assert (noOverlap ((r0, d) :: (t ++ ((s, r0ounon) :: b)))); [apply noOverlap_Front0; auto | idtac]. generalize H; unfold noOverlap; simpl; clear H; intros. elim H0; intros; [idtac | apply (H l0); (right; (try assumption))]. split; [right; (try assumption) | idtac]. generalize TB; simpl; caseEq (b ++ ((r0, d) :: nil)); intro. elim (app_eq_nil b ((r0, d) :: nil)); intros; auto; inversion H4. subst l0; intros; rewrite <- H1 in TB0. elim TB0; [intros H2 H3; elim H3; [intros H4 H5; (try clear H3 TB0)]]. generalize (noTmpL_diff b r0 d); unfold notemporary; intro; apply H3; auto. rewrite <- H1; apply noTmP_noOverlap_aux; apply noTmp_append; auto; rewrite <- app_cons in TB; apply noTmpLast_popBack with (r0, d); auto. rewrite <- (app_nil _ t); apply (noOverlap_Pop (s, d)); assumption. Qed. Lemma step_inv: forall (r1 r2 : State), step r1 r2 -> stepInv r1 -> stepInv r2. Proof. intros; unfold stepInv; (repeat split). apply (step_inv_path r1 r2); auto. apply (step_inv_simpleDest r1 r2); auto. apply (step_inv_noOverlap r1 r2); auto. apply (step_inv_noTmp r1 r2); auto. apply (step_inv_noTmpLast r1 r2); auto. Qed. Definition step_NF (r : State) : Prop := ~ (exists s : State , step r s ). Inductive stepp : State -> State -> Prop := stepp_refl: forall (r : State), stepp r r | stepp_trans: forall (r1 r2 r3 : State), step r1 r2 -> stepp r2 r3 -> stepp r1 r3 . Hint Resolve stepp_refl stepp_trans . Lemma stepp_transitive: forall (r1 r2 r3 : State), stepp r1 r2 -> stepp r2 r3 -> stepp r1 r3. Proof. intros; induction H as [r|r1 r2 r0 H H1 HrecH]; eauto. Qed. Lemma step_stepp: forall (s1 s2 : State), step s1 s2 -> stepp s1 s2. Proof. eauto. Qed. Lemma stepp_inv: forall (r1 r2 : State), stepp r1 r2 -> stepInv r1 -> stepInv r2. Proof. intros; induction H as [r|r1 r2 r3 H H1 HrecH]; auto. apply HrecH; auto. apply (step_inv r1 r2); auto. Qed. Lemma noTmpLast_lastnoTmp: forall l s d, noTmpLast (l ++ ((s, d) :: nil)) -> notemporary d. Proof. induction l. simpl. intros; unfold notemporary; auto. destruct a as [a1 a2]; intros. change (noTmpLast ((a1, a2) :: (l ++ ((s, d) :: nil)))) in H |-. apply IHl with s. apply noTmpLast_pop with (a1, a2); auto. Qed. Lemma step_inv_NoOverlap: forall (s1 s2 : State) r, step s1 s2 -> notemporary r -> stepInv s1 -> NoOverlap r s1 -> NoOverlap r s2. Proof. intros s1 s2 r STEP notempr; inversion_clear STEP; unfold stepInv; unfold stepInv, sameExec, sameEnv, exec, StateToMove, StateBeing, StateDone; intros [P [SD [NO [TT TB]]]]; unfold NoOverlap; simpl. simpl; (repeat rewrite app_nil); simpl; (repeat rewrite <- app_cons); intro; apply noOverlap_Pop with ( m := (r0, r0) ); auto. (repeat rewrite app_nil); simpl; rewrite app_ass; (repeat rewrite <- app_cons); intro; rewrite ass_app; apply noOverlap_movBack; auto. simpl; (repeat (rewrite app_ass; simpl)); (repeat rewrite <- app_cons); intro. rewrite ass_app; apply noOverlap_insert; rewrite app_ass; apply noOverlap_movFront; auto. simpl; (repeat rewrite <- app_cons); intro; rewrite ass_app; apply noOverlap_movBack0; auto. generalize H; (repeat (rewrite app_ass; simpl)); intro. assert (noOverlap ((r0, d) :: (((r, r) :: t) ++ ((s, r0ounon) :: b)))); [apply noOverlap_Front0 | idtac]; auto. generalize H0; (repeat (rewrite app_ass; simpl)); auto. generalize H1; unfold noOverlap; simpl; intros. elim H3; intros H4; clear H3. split. right; assert (notemporary d). change (noTmpLast (((s, r0ounon) :: b) ++ ((r0, d) :: nil))) in TB |-; apply (noTmpLast_lastnoTmp ((s, r0ounon) :: b) r0); auto. rewrite <- H4; unfold notemporary in H3 |-; apply H3. split. right; rewrite <- H4; unfold notemporary in notempr |-; apply notempr. rewrite <- H4; apply noTmP_noOverlap_aux; auto. apply noTmp_append; auto. change (noTmpLast (((s, r0ounon) :: b) ++ ((r0, d) :: nil))) in TB |-; apply noTmpLast_popBack with ( m := (r0, d) ); auto. apply (H2 l0). elim H4; intros H3; right; [left | right]; assumption. intro; change (noOverlap (((r, r) :: t) ++ ((sn, dn) :: (b ++ ((s0, d0) :: nil))))) in H1 |-. change (noOverlap (((r, r) :: t) ++ (b ++ ((s0, d0) :: nil)))); apply (noOverlap_Pop (sn, dn)); auto. (repeat rewrite <- app_cons); apply noOverlap_Pop. Qed. Lemma step_inv_getdst: forall (s1 s2 : State) r, step s1 s2 -> In r (getdst (StateToMove s2 ++ StateBeing s2)) -> In r (getdst (StateToMove s1 ++ StateBeing s1)). Proof. intros s1 s2 r STEP; inversion_clear STEP; unfold StateToMove, StateBeing, StateDone. (repeat rewrite getdst_app); simpl; (repeat rewrite app_nil); intro; apply in_or_app. elim (in_app_or (getdst t1) (getdst t2) r); auto. intro; right; simpl; right; assumption. (repeat rewrite getdst_app); destruct m as [m1 m2]; simpl; (repeat rewrite app_nil); intro; apply in_or_app. elim (in_app_or (getdst t1 ++ getdst t2) (m2 :: nil) r); auto; intro. elim (in_app_or (getdst t1) (getdst t2) r); auto; intro. right; simpl; right; assumption. elim H0; intros H1; [right; simpl; left; (try assumption) | inversion H1]. (repeat rewrite getdst_app); simpl; (repeat rewrite app_nil); intro; apply in_or_app. elim (in_app_or (getdst t1 ++ getdst t2) (r0 :: (d :: getdst b)) r); auto; intro. elim (in_app_or (getdst t1) (getdst t2) r); auto; intro. left; apply in_or_app; left; assumption. left; apply in_or_app; right; simpl; right; assumption. elim H0; intro. left; apply in_or_app; right; simpl; left; trivial. elim H1; intro. right; (simpl; left; trivial). right; simpl; right; assumption. (repeat (rewrite getdst_app; simpl)); trivial. (repeat (rewrite getdst_app; simpl)); intro. elim (in_app_or (getdst t) (getdst b ++ (d0 :: nil)) r); auto; intro; apply in_or_app; auto. elim (in_app_or (getdst b) (d0 :: nil) r); auto; intro. right; simpl; right; apply in_or_app; auto. elim H3; intro. right; simpl; right; apply in_or_app; right; simpl; auto. inversion H4. rewrite app_nil; (repeat (rewrite getdst_app; simpl)); intro. apply in_or_app; left; assumption. Qed. Lemma stepp_sameExec: forall (r1 r2 : State), stepp r1 r2 -> stepInv r1 -> sameExec r1 r2. Proof. intros; induction H as [r|r1 r2 r3 H H1 HrecH]. unfold sameExec; intros; auto. cut (sameExec r1 r2); [idtac | apply (step_sameExec r1); auto]. unfold sameExec; unfold sameExec in HrecH |-; intros. rewrite H2; auto. rewrite HrecH; auto. apply (step_inv r1); auto. intros x H5; apply H4. generalize H5; (repeat rewrite getdst_app); intros; apply in_or_app. elim (in_app_or (getdst (StateToMove r2) ++ getdst (StateBeing r2)) (getdst (StateToMove r3) ++ getdst (StateBeing r3)) x); auto; intro. generalize (step_inv_getdst r1 r2 x); (repeat rewrite getdst_app); intro. left; apply H8; auto. intros x H5; apply H4. generalize H5; (repeat rewrite getdst_app); intros; apply in_or_app. elim (in_app_or (getdst (StateToMove r1) ++ getdst (StateBeing r1)) (getdst (StateToMove r2) ++ getdst (StateBeing r2)) x); auto; intro. generalize (step_inv_getdst r1 r2 x); (repeat rewrite getdst_app); intro. left; apply H8; auto. Qed. Inductive dstep : State -> State -> Prop := dstep_nop: forall (r : Reg) (t l : Moves), dstep ((r, r) :: t, nil, l) (t, nil, l) | dstep_start: forall (t l : Moves) (s d : Reg), s <> d -> dstep ((s, d) :: t, nil, l) (t, (s, d) :: nil, l) | dstep_push: forall (t1 t2 b l : Moves) (s d r : Reg), noRead t1 d -> dstep (t1 ++ ((d, r) :: t2), (s, d) :: b, l) (t1 ++ t2, (d, r) :: ((s, d) :: b), l) | dstep_pop_loop: forall (t b l : Moves) (s d r0 : Reg), noRead t r0 -> dstep (t, (s, r0) :: (b ++ ((r0, d) :: nil)), l) (t, b ++ ((T r0, d) :: nil), (s, r0) :: ((r0, T r0) :: l)) | dstep_pop: forall (t b l : Moves) (s0 d0 sn dn : Reg), noRead t dn -> Loc.diff dn s0 -> dstep (t, (sn, dn) :: (b ++ ((s0, d0) :: nil)), l) (t, b ++ ((s0, d0) :: nil), (sn, dn) :: l) | dstep_last: forall (t l : Moves) (s d : Reg), noRead t d -> dstep (t, (s, d) :: nil, l) (t, nil, (s, d) :: l) . Hint Resolve dstep_nop dstep_start dstep_push . Hint Resolve dstep_pop_loop dstep_pop dstep_last . Lemma dstep_step: forall (r1 r2 : State), dstep r1 r2 -> stepInv r1 -> stepp r1 r2. Proof. intros r1 r2 DS; inversion_clear DS; intros SI; eauto. change (stepp (nil ++ ((r, r) :: t), nil, l) (t, nil, l)); apply step_stepp; apply (step_nop r nil t). change (stepp (nil ++ ((s, d) :: t), nil, l) (t, (s, d) :: nil, l)); apply step_stepp; apply (step_start nil t l). apply (stepp_trans (t, (s, r0) :: (b ++ ((r0, d) :: nil)), l) (t, (s, r0) :: (b ++ ((T r0, d) :: nil)), (r0, T r0) :: l) (t, b ++ ((T r0, d) :: nil), (s, r0) :: ((r0, T r0) :: l))); auto. apply step_stepp; apply step_pop; auto. unfold stepInv in SI |-; generalize SI; intros [X [Y [Z [U V]]]]. generalize V; unfold StateBeing, noTmpLast. case (b ++ ((r0, d) :: nil)); auto. intros m l0 [R1 [OK PP]]; auto. Qed. Lemma dstep_inv: forall (r1 r2 : State), dstep r1 r2 -> stepInv r1 -> stepInv r2. Proof. intros. apply (stepp_inv r1 r2); auto. apply dstep_step; auto. Qed. Inductive dstepp : State -> State -> Prop := dstepp_refl: forall (r : State), dstepp r r | dstepp_trans: forall (r1 r2 r3 : State), dstep r1 r2 -> dstepp r2 r3 -> dstepp r1 r3 . Hint Resolve dstepp_refl dstepp_trans . Lemma dstepp_stepp: forall (s1 s2 : State), stepInv s1 -> dstepp s1 s2 -> stepp s1 s2. Proof. intros; induction H0 as [r|r1 r2 r3 H0 H1 HrecH0]; auto. apply (stepp_transitive r1 r2 r3); auto. apply dstep_step; auto. apply HrecH0; auto. apply (dstep_inv r1 r2); auto. Qed. Lemma dstepp_sameExec: forall (r1 r2 : State), dstepp r1 r2 -> stepInv r1 -> sameExec r1 r2. Proof. intros; apply stepp_sameExec; auto. apply dstepp_stepp; auto. Qed. End pmov. Fixpoint split_move' (m : Moves) (r : Reg) {struct m} : option ((Moves * Reg) * Moves) := match m with (s, d) :: tail => match diff_dec s r with right _ => Some (nil, d, tail) | left _ => match split_move' tail r with Some ((t1, r2, t2)) => Some ((s, d) :: t1, r2, t2) | None => None end end | nil => None end. Fixpoint split_move (m : Moves) (r : Reg) {struct m} : option ((Moves * Reg) * Moves) := match m with (s, d) :: tail => match Loc.eq s r with left _ => Some (nil, d, tail) | right _ => match split_move tail r with Some ((t1, r2, t2)) => Some ((s, d) :: t1, r2, t2) | None => None end end | nil => None end. Definition def : Move := (R IT1, R IT1). Fixpoint last (M : Moves) : Move := match M with nil => def | m :: nil => m | m :: tail => last tail end. Fixpoint head_but_last (M : Moves) : Moves := match M with nil => nil | m' :: nil => nil | m' :: tail => m' :: head_but_last tail end. Fixpoint replace_last_s (M : Moves) : Moves := match M with nil => nil | m :: nil => match m with (s, d) => (T s, d) :: nil end | m :: tail => m :: replace_last_s tail end. Ltac CaseEq name := generalize (refl_equal name); pattern name at -1; case name. Definition stepf' (S1 : State) : State := match S1 with (nil, nil, _) => S1 | ((s, d) :: tl, nil, l) => match diff_dec s d with right _ => (tl, nil, l) | left _ => (tl, (s, d) :: nil, l) end | (t, (s, d) :: b, l) => match split_move t d with Some ((t1, r, t2)) => (t1 ++ t2, (d, r) :: ((s, d) :: b), l) | None => match b with nil => (t, nil, (s, d) :: l) | _ => match diff_dec d (fst (last b)) with right _ => (t, replace_last_s b, (s, d) :: ((d, T d) :: l)) | left _ => (t, b, (s, d) :: l) end end end end. Definition stepf (S1 : State) : State := match S1 with (nil, nil, _) => S1 | ((s, d) :: tl, nil, l) => match Loc.eq s d with left _ => (tl, nil, l) | right _ => (tl, (s, d) :: nil, l) end | (t, (s, d) :: b, l) => match split_move t d with Some ((t1, r, t2)) => (t1 ++ t2, (d, r) :: ((s, d) :: b), l) | None => match b with nil => (t, nil, (s, d) :: l) | _ => match Loc.eq d (fst (last b)) with left _ => (t, replace_last_s b, (s, d) :: ((d, T d) :: l)) | right _ => (t, b, (s, d) :: l) end end end end. Lemma rebuild_l: forall (l : Moves) (m : Move), m :: l = head_but_last (m :: l) ++ (last (m :: l) :: nil). Proof. induction l; simpl; auto. intros m; rewrite (IHl a); auto. Qed. Lemma splitSome: forall (l t1 t2 : Moves) (s d r : Reg), noOverlap (l ++ ((r, s) :: nil)) -> split_move l s = Some (t1, d, t2) -> noRead t1 s. Proof. induction l; simpl. intros; discriminate. destruct a as [a1 a2]. intros t1 t2 s d r Hno; case (Loc.eq a1 s). intros e H1; inversion H1. simpl; auto. CaseEq (split_move l s). intros; (repeat destruct p). inversion H0; auto. simpl; split; auto. change (noOverlap (((a1, a2) :: l) ++ ((r, s) :: nil))) in Hno |-. assert (noOverlap ((r, s) :: ((a1, a2) :: l))). apply noOverlap_Front0; auto. unfold noOverlap in H1 |-; simpl in H1 |-. elim H1 with ( l0 := a1 ); [intros H5 H6; (try clear H1); (try exact H5) | idtac]. elim H5; [intros H1; (try clear H5); (try exact H1) | intros H1; (try clear H5)]. absurd (a1 = s); auto. apply Loc.diff_sym; auto. right; left; trivial. apply (IHl m0 m s r0 r); auto. apply (noOverlap_pop (a1, a2)); auto. intros; discriminate. Qed. Lemma unsplit_move: forall (l t1 t2 : Moves) (s d r : Reg), noOverlap (l ++ ((r, s) :: nil)) -> split_move l s = Some (t1, d, t2) -> l = t1 ++ ((s, d) :: t2). Proof. induction l. simpl; intros; discriminate. intros t1 t2 s d r HnoO; destruct a as [a1 a2]; simpl; case (diff_dec a1 s); intro. case (Loc.eq a1 s); intro. absurd (Loc.diff a1 s); auto. rewrite e; apply Loc.same_not_diff. CaseEq (split_move l s); intros; (try discriminate). (repeat destruct p); inversion H0. rewrite app_cons; subst t2; subst d; rewrite (IHl m0 m s r0 r); auto. apply (noOverlap_pop (a1, a2)); auto. case (Loc.eq a1 s); intros e H; inversion H; simpl. rewrite e; auto. cut (noOverlap_aux a1 (getdst ((r, s) :: nil))). intros [[H5|H4] H0]; [try exact H5 | idtac]. absurd (s = a1); auto. absurd (Loc.diff a1 s); auto; apply Loc.diff_sym; auto. generalize HnoO; rewrite app_cons; intro. assert (noOverlap (l ++ ((a1, a2) :: ((r, s) :: nil)))); (try (apply noOverlap_insert; assumption)). assert (noOverlap ((a1, a2) :: ((r, s) :: nil))). apply (noOverlap_right l); auto. generalize H2; unfold noOverlap; simpl. intros H5; elim (H5 a1); [idtac | left; trivial]. intros H6 [[H7|H8] H9]. absurd (s = a1); auto. split; [right; (try assumption) | auto]. Qed. Lemma cons_replace: forall (a : Move) (l : Moves), l <> nil -> replace_last_s (a :: l) = a :: replace_last_s l. Proof. intros; simpl. CaseEq l. intro; contradiction. intros m l0 H0; auto. Qed. Lemma last_replace: forall (l : Moves) (s d : Reg), replace_last_s (l ++ ((s, d) :: nil)) = l ++ ((T s, d) :: nil). Proof. induction l; (try (simpl; auto; fail)). intros; (repeat rewrite <- app_comm_cons). rewrite cons_replace. rewrite IHl; auto. red; intro. elim (app_eq_nil l ((s, d) :: nil)); auto; intros; discriminate. Qed. Lemma last_app: forall (l : Moves) (m : Move), last (l ++ (m :: nil)) = m. Proof. induction l; simpl; auto. intros m; CaseEq (l ++ (m :: nil)). intro; elim (app_eq_nil l (m :: nil)); auto; intros; discriminate. intros m0 l0 H; (rewrite <- H; apply IHl). Qed. Lemma last_cons: forall (l : Moves) (m m0 : Move), last (m0 :: (m :: l)) = last (m :: l). Proof. intros; simpl; auto. Qed. Lemma stepf_popLoop: forall (t b l : Moves) (s d r0 : Reg), split_move t d = None -> stepf (t, (s, d) :: (b ++ ((d, r0) :: nil)), l) = (t, b ++ ((T d, r0) :: nil), (s, d) :: ((d, T d) :: l)). Proof. intros; simpl; rewrite H; CaseEq (b ++ ((d, r0) :: nil)); intros. destruct b; discriminate. rewrite <- H0; rewrite last_app; simpl; rewrite last_replace. case (Loc.eq d d); intro; intuition. destruct t; (try destruct m0); simpl; auto. Qed. Lemma stepf_pop: forall (t b l : Moves) (s d r r0 : Reg), split_move t d = None -> d <> r -> stepf (t, (s, d) :: (b ++ ((r, r0) :: nil)), l) = (t, b ++ ((r, r0) :: nil), (s, d) :: l). Proof. intros; simpl; rewrite H; CaseEq (b ++ ((r, r0) :: nil)); intros. destruct b; discriminate. rewrite <- H1; rewrite last_app; simpl. case (Loc.eq d r); intro. absurd (d = r); auto. destruct t; (try destruct m0); simpl; auto. Qed. Lemma noOverlap_head: forall l1 l2 m, noOverlap (l1 ++ (m :: l2)) -> noOverlap (l1 ++ (m :: nil)). Proof. induction l2; simpl; auto. intros; apply IHl2. cut (l1 ++ (m :: (a :: l2)) = (l1 ++ (m :: nil)) ++ (a :: l2)); [idtac | rewrite app_ass; auto]. intros e; rewrite e in H. cut (l1 ++ (m :: l2) = (l1 ++ (m :: nil)) ++ l2); [idtac | rewrite app_ass; auto]. intros e'; rewrite e'; auto. apply noOverlap_Pop with a; auto. Qed. Lemma splitNone: forall (l : Moves) (s d : Reg), split_move l d = None -> noOverlap (l ++ ((s, d) :: nil)) -> noRead l d. Proof. induction l; intros s d; simpl; auto. destruct a as [a1 a2]; case (Loc.eq a1 d); intro; (try (intro; discriminate)). CaseEq (split_move l d); intros. (repeat destruct p); discriminate. split; (try assumption). change (noOverlap (((a1, a2) :: l) ++ ((s, d) :: nil))) in H1 |-. assert (noOverlap ((s, d) :: ((a1, a2) :: l))). apply noOverlap_Front0; auto. assert (noOverlap ((a1, a2) :: ((s, d) :: l))). apply noOverlap_swap; auto. unfold noOverlap in H3 |-; simpl in H3 |-. elim H3 with ( l0 := a1 ); [intros H5 H6; (try clear H1); (try exact H5) | idtac]. elim H6; [intros H1 H4; elim H1; [intros H7; (try clear H1 H6); (try exact H7) | intros H7; (try clear H1 H6)]]. absurd (a1 = d); auto. apply Loc.diff_sym; auto. left; trivial. apply IHl with s; auto. apply noOverlap_pop with (a1, a2); auto. Qed. Lemma noO_diff: forall l1 l2 s d r r0, noOverlap (l1 ++ ((s, d) :: (l2 ++ ((r, r0) :: nil)))) -> r = d \/ Loc.diff d r. Proof. intros. assert (noOverlap ((s, d) :: (l2 ++ ((r, r0) :: nil)))); auto. apply (noOverlap_right l1); auto. assert (noOverlap ((l2 ++ ((r, r0) :: nil)) ++ ((s, d) :: nil))); auto. apply (noOverlap_movBack0 (l2 ++ ((r, r0) :: nil))); auto. assert ((l2 ++ ((r, r0) :: nil)) ++ ((s, d) :: nil) = l2 ++ (((r, r0) :: nil) ++ ((s, d) :: nil))); auto. rewrite app_ass; auto. rewrite H2 in H1. simpl in H1 |-. assert (noOverlap ((r, r0) :: ((s, d) :: nil))); auto. apply (noOverlap_right l2); auto. unfold noOverlap in H3 |-. generalize (H3 r); simpl. intros H4; elim H4; intros; [idtac | left; trivial]. elim H6; intros [H9|H9] H10; [left | right]; auto. Qed. Lemma f2ind: forall (S1 S2 : State), (forall (l : Moves), (S1 <> (nil, nil, l))) -> noOverlap (StateToMove S1 ++ StateBeing S1) -> stepf S1 = S2 -> dstep S1 S2. Proof. intros S1 S2 Hneq HnoO; destruct S1 as [[t b] l]; destruct b. destruct t. elim (Hneq l); auto. destruct m; simpl; case (Loc.eq r r0). intros. rewrite e; rewrite <- H; apply dstep_nop. intros n H; rewrite <- H; generalize (dstep_start t l r r0); auto. intros H; rewrite <- H; destruct m as [s d]. CaseEq (split_move t d). intros p H0; destruct p as [[t1 s0] t2]; simpl; rewrite H0; destruct t; simpl. simpl in H0 |-; discriminate. rewrite (unsplit_move (m :: t) t1 t2 d s0 s); auto. destruct m; generalize dstep_push; intros H1; apply H1. unfold StateToMove, StateBeing in HnoO |-. apply (splitSome ((r, r0) :: t) t1 t2 d s0 s); auto. apply noOverlap_head with b; auto. unfold StateToMove, StateBeing in HnoO |-. apply noOverlap_head with b; auto. intros H0; destruct b. simpl. rewrite H0. destruct t; (try destruct m); generalize dstep_last; intros H1; apply H1. simpl; auto. unfold StateToMove, StateBeing in HnoO |-. apply splitNone with s; auto. unfold StateToMove, StateBeing in HnoO |-. generalize HnoO; clear HnoO; rewrite (rebuild_l b m); intros HnoO. destruct (last (m :: b)). case (Loc.eq d r). intros e; rewrite <- e. CaseEq (head_but_last (m :: b)); intros; [simpl | idtac]; (try (destruct t; (try destruct m0); rewrite H0; (case (Loc.eq d d); intros h; (try (elim h; auto))))). generalize (dstep_pop_loop nil nil); simpl; intros H3; apply H3; auto. generalize (dstep_pop_loop ((r1, r2) :: t) nil); unfold T; simpl app; intros H3; apply H3; clear H3; apply splitNone with s; (try assumption). apply noOverlap_head with (head_but_last (m :: b) ++ ((r, r0) :: nil)); auto. rewrite stepf_popLoop; auto. generalize (dstep_pop_loop t (m0 :: l0)); simpl; intros H3; apply H3; clear H3; apply splitNone with s; (try assumption). apply noOverlap_head with (head_but_last (m :: b) ++ ((r, r0) :: nil)); auto. intro; assert (Loc.diff d r). assert (r = d \/ Loc.diff d r). apply (noO_diff t (head_but_last (m :: b)) s d r r0); auto. elim H1; [intros H2; absurd (d = r); auto | intros H2; auto]. rewrite stepf_pop; auto. generalize (dstep_pop t (head_but_last (m :: b))); intros H3; apply H3; auto. clear H3; apply splitNone with s; (try assumption). apply noOverlap_head with (head_but_last (m :: b) ++ ((r, r0) :: nil)); auto. Qed. Lemma f2ind': forall (S1 : State), (forall (l : Moves), (S1 <> (nil, nil, l))) -> noOverlap (StateToMove S1 ++ StateBeing S1) -> dstep S1 (stepf S1). Proof. intros S1 H noO; apply f2ind; auto. Qed. Lemma appcons_length: forall (l1 l2 : Moves) (m : Move), length (l1 ++ (m :: l2)) = (length (l1 ++ l2) + 1%nat)%nat. Proof. induction l1; simpl; intros; [omega | idtac]. rewrite IHl1; omega. Qed. Definition mesure (S0 : State) : nat := let (p, _) := S0 in let (t, b) := p in (2 * length t + length b)%nat. Lemma step_dec0: forall (t1 t2 b1 b2 : Moves) (l1 l2 : Moves), dstep (t1, b1, l1) (t2, b2, l2) -> (2 * length t2 + length b2 < 2 * length t1 + length b1)%nat. Proof. intros t1 t2 b1 b2 l1 l2 H; inversion H; simpl; (try omega). rewrite appcons_length; omega. cut (length (b ++ ((T r0, d) :: nil)) = length (b ++ ((r0, d) :: nil))); (try omega). induction b; simpl; auto. (repeat rewrite appcons_length); auto. Qed. Lemma step_dec: forall (S1 S2 : State), dstep S1 S2 -> (mesure S2 < mesure S1)%nat. Proof. unfold mesure; destruct S1 as [[t1 b1] l1]; destruct S2 as [[t2 b2] l2]. intro; apply (step_dec0 t1 t2 b1 b2 l1 l2); trivial. Qed. Lemma stepf_dec0: forall (S1 S2 : State), (forall (l : Moves), (S1 <> (nil, nil, l))) /\ (S2 = stepf S1 /\ noOverlap (StateToMove S1 ++ StateBeing S1)) -> (mesure S2 < mesure S1)%nat. Proof. intros S1 S2 [H1 [H2 H3]]; apply step_dec. apply f2ind; trivial. rewrite H2; reflexivity. Qed. Lemma stepf_dec: forall (S1 S2 : State), S2 = stepf S1 /\ ((forall (l : Moves), (S1 <> (nil, nil, l))) /\ noOverlap (StateToMove S1 ++ StateBeing S1)) -> ltof _ mesure S2 S1. Proof. unfold ltof. intros S1 S2 [H1 [H2 H3]]; apply step_dec. apply f2ind; trivial. rewrite H1; reflexivity. Qed. Lemma replace_last_id: forall l m m0, replace_last_s (m :: (m0 :: l)) = m :: replace_last_s (m0 :: l). Proof. intros; case l; simpl. destruct m0; simpl; auto. intros; case l0; auto. Qed. Lemma length_replace: forall l, length (replace_last_s l) = length l. Proof. induction l; simpl; auto. destruct l; destruct a; simpl; auto. Qed. Lemma length_app: forall (A : Set) (l1 l2 : list A), (length (l1 ++ l2) = length l1 + length l2)%nat. Proof. intros A l1 l2; (try assumption). induction l1; simpl; auto. Qed. Lemma split_length: forall (l t1 t2 : Moves) (s d : Reg), split_move l s = Some (t1, d, t2) -> (length l = (length t1 + length t2) + 1)%nat. Proof. induction l. intros; discriminate. intros t1 t2 s d; destruct a as [r r0]; simpl; case (Loc.eq r s); intro. intros H; inversion H. simpl; omega. CaseEq (split_move l s); (try (intros; discriminate)). (repeat destruct p); intros H H0; inversion H0. rewrite H2; rewrite (IHl m0 m s r1); auto. rewrite H4; rewrite <- H2; simpl; omega. Qed. Lemma stepf_dec0': forall (S1 : State), (forall (l : Moves), (S1 <> (nil, nil, l))) -> (mesure (stepf S1) < mesure S1)%nat. Proof. intros S1 H. unfold mesure; destruct S1 as [[t1 b1] l1]. destruct t1. destruct b1. generalize (H l1); intros H1; elim H1; auto. destruct m; simpl. destruct b1. simpl; auto. case (Loc.eq r0 (fst (last (m :: b1)))). intros; rewrite length_replace; simpl; omega. simpl; case b1; intros; simpl; omega. destruct m. destruct b1. simpl. case (Loc.eq r r0); intros; simpl; omega. destruct m; simpl; case (Loc.eq r r2). intros; simpl; omega. CaseEq (split_move t1 r2); intros. destruct p; destruct p; simpl. rewrite (split_length t1 m0 m r2 r3); auto. rewrite length_app; auto. omega. destruct b1. simpl; omega. case (Loc.eq r2 (fst (last (m :: b1)))); intros. rewrite length_replace; simpl; omega. simpl; omega. Qed. Lemma stepf1_dec: forall (S1 S2 : State), (forall (l : Moves), (S1 <> (nil, nil, l))) -> S2 = stepf S1 -> ltof _ mesure S2 S1. Proof. unfold ltof; intros S1 S2 H H0; rewrite H0. apply stepf_dec0'; (try assumption). Qed. Lemma disc1: forall (a : Move) (l1 l2 l3 l4 : list Move), ((a :: l1, l2, l3) <> (nil, nil, l4)). Proof. intros; discriminate. Qed. Lemma disc2: forall (a : Move) (l1 l2 l3 l4 : list Move), ((l1, a :: l2, l3) <> (nil, nil, l4)). Proof. intros; discriminate. Qed. Hint Resolve disc1 disc2 . Lemma sameExec_reflexive: forall (r : State), sameExec r r. Proof. intros r; unfold sameExec, sameEnv, exec. destruct r as [[t b] d]; trivial. Qed. Definition base_case_Pmov_dec: forall (s : State), ({ exists l : list Move , s = (nil, nil, l) }) + ({ forall l, (s <> (nil, nil, l)) }). Proof. destruct s as [[[|x tl] [|y tl']] l]; (try (right; intro; discriminate)). left; exists l; auto. Defined. Definition Pmov := Fix (well_founded_ltof _ mesure) (fun _ => State) (fun (S1 : State) => fun (Pmov : forall x, ltof _ mesure x S1 -> State) => match base_case_Pmov_dec S1 with left h => S1 | right h => Pmov (stepf S1) (stepf_dec0' S1 h) end). Theorem Pmov_equation: forall S1, Pmov S1 = match S1 with ((nil, nil), _) => S1 | _ => Pmov (stepf S1) end. Proof. intros S1; unfold Pmov at 1; rewrite (Fix_eq (well_founded_ltof _ mesure) (fun _ => State) (fun (S1 : State) => fun (Pmov : forall x, ltof _ mesure x S1 -> State) => match base_case_Pmov_dec S1 with left h => S1 | right h => Pmov (stepf S1) (stepf_dec0' S1 h) end)). fold Pmov. destruct S1 as [[[|x tl] [|y tl']] l]; match goal with | |- match ?a with left _ => _ | right _ => _ end = _ => case a end; (try (intros [l0 Heq]; discriminate Heq)); auto. intros H; elim (H l); auto. intros x f g Hfg_ext. match goal with | |- match ?a with left _ => _ | right _ => _ end = _ => case a end; auto. Qed. Lemma sameExec_transitive: forall (r1 r2 r3 : State), (forall r, In r (getdst (StateToMove r2 ++ StateBeing r2)) -> In r (getdst (StateToMove r1 ++ StateBeing r1))) -> (forall r, In r (getdst (StateToMove r3 ++ StateBeing r3)) -> In r (getdst (StateToMove r2 ++ StateBeing r2))) -> sameExec r1 r2 -> sameExec r2 r3 -> sameExec r1 r3. Proof. intros r1 r2 r3; unfold sameExec, exec; (repeat rewrite getdst_app). destruct r1 as [[t1 b1] d1]; destruct r2 as [[t2 b2] d2]; destruct r3 as [[t3 b3] d3]; simpl. intros Hin; intros. rewrite H0; auto. rewrite H1; auto. intros. apply (H3 x). apply in_or_app; auto. elim (in_app_or (getdst t2 ++ getdst b2) (getdst t3 ++ getdst b3) x); auto. intros. apply (H3 x). apply in_or_app; auto. elim (in_app_or (getdst t1 ++ getdst b1) (getdst t2 ++ getdst b2) x); auto. Qed. Lemma dstep_inv_getdst: forall (s1 s2 : State) r, dstep s1 s2 -> In r (getdst (StateToMove s2 ++ StateBeing s2)) -> In r (getdst (StateToMove s1 ++ StateBeing s1)). intros s1 s2 r STEP; inversion_clear STEP; unfold StateToMove, StateBeing, StateDone; (repeat rewrite app_nil); (repeat (rewrite getdst_app; simpl)); intro; auto. Proof. right; (try assumption). elim (in_app_or (getdst t) (d :: nil) r); auto; (simpl; intros [H1|H1]); [left; assumption | inversion H1]. elim (in_app_or (getdst t1 ++ getdst t2) (r0 :: (d :: getdst b)) r); auto; (simpl; intros). elim (in_app_or (getdst t1) (getdst t2) r); auto; (simpl; intros). apply in_or_app; left; apply in_or_app; left; assumption. apply in_or_app; left; apply in_or_app; right; simpl; right; assumption. elim H1; [intros H2 | intros [H2|H2]]. apply in_or_app; left; apply in_or_app; right; simpl; left; auto. apply in_or_app; right; simpl; left; auto. apply in_or_app; right; simpl; right; assumption. elim (in_app_or (getdst t) (getdst b ++ (d :: nil)) r); auto; (simpl; intros). apply in_or_app; left; assumption. elim (in_app_or (getdst b) (d :: nil) r); auto; (simpl; intros). apply in_or_app; right; simpl; right; apply in_or_app; left; assumption. elim H2; [intros H3 | intros H3; inversion H3]. apply in_or_app; right; simpl; right; apply in_or_app; right; simpl; auto. elim (in_app_or (getdst t) (getdst b ++ (d0 :: nil)) r); auto; (simpl; intros). apply in_or_app; left; assumption. elim (in_app_or (getdst b) (d0 :: nil) r); auto; simpl; [intros H3 | intros [H3|H3]; [idtac | inversion H3]]. apply in_or_app; right; simpl; right; apply in_or_app; left; assumption. apply in_or_app; right; simpl; right; apply in_or_app; right; simpl; auto. apply in_or_app; left; assumption. Qed. Theorem STM_Pmov: forall (S1 : State), StateToMove (Pmov S1) = nil. Proof. intros S1; elim S1 using (well_founded_ind (Wf_nat.well_founded_ltof _ mesure)). clear S1; intros S1; intros Hrec; destruct S1 as [[t b] d]; rewrite Pmov_equation; destruct t. destruct b; auto. apply Hrec; apply stepf1_dec; auto. apply Hrec; apply stepf1_dec; auto. Qed. Theorem SB_Pmov: forall (S1 : State), StateBeing (Pmov S1) = nil. Proof. intros S1; elim S1 using (well_founded_ind (Wf_nat.well_founded_ltof _ mesure)). clear S1; intros S1; intros Hrec; destruct S1 as [[t b] d]; rewrite Pmov_equation; destruct t. destruct b; auto. apply Hrec; apply stepf1_dec; auto. apply Hrec; apply stepf1_dec; auto. Qed. Theorem Fpmov_correct: forall (S1 : State), stepInv S1 -> sameExec S1 (Pmov S1). Proof. intros S1; elim S1 using (well_founded_ind (Wf_nat.well_founded_ltof _ mesure)). clear S1; intros S1; intros Hrec Hinv; rewrite Pmov_equation; destruct S1 as [[t b] d]. assert (forall (r : Reg) S1, In r (getdst (StateToMove (Pmov (stepf S1)) ++ StateBeing (Pmov (stepf S1)))) -> In r (getdst (StateToMove (stepf S1) ++ StateBeing (stepf S1)))). intros r S1; rewrite (STM_Pmov (stepf S1)); rewrite SB_Pmov; simpl; intros. inversion H. destruct t. destruct b. apply sameExec_reflexive. set (S1:=(nil (A:=Move), m :: b, d)). assert (dstep S1 (stepf S1)); (try apply f2ind); unfold S1; auto. elim Hinv; intros Hpath [SD [NO NT]]; assumption. apply sameExec_transitive with (stepf S1); auto. intros r; apply dstep_inv_getdst; auto. apply dstepp_sameExec; auto; apply dstepp_trans with (stepf S1); auto. apply dstepp_refl; auto. apply Hrec; auto. unfold ltof; apply step_dec; assumption. apply (dstep_inv S1); assumption. set (S1:=(m :: t, b, d)). assert (dstep S1 (stepf S1)); (try apply f2ind); unfold S1; auto. elim Hinv; intros Hpath [SD [NO NT]]; assumption. apply sameExec_transitive with (stepf S1); auto. intros r; apply dstep_inv_getdst; auto. apply dstepp_sameExec; auto; apply dstepp_trans with (stepf S1); auto. apply dstepp_refl; auto. apply Hrec; auto. unfold ltof; apply step_dec; assumption. apply (dstep_inv S1); assumption. Qed. Definition P_move := fun (p : Moves) => StateDone (Pmov (p, nil, nil)). Definition Sexec := sexec. Definition Get := get. Fixpoint listsLoc2Moves (src dst : list loc) {struct src} : Moves := match src with nil => nil | s :: srcs => match dst with nil => nil | d :: dsts => (s, d) :: listsLoc2Moves srcs dsts end end. Definition no_overlap (l1 l2 : list loc) := forall r, In r l1 -> forall s, In s l2 -> r = s \/ Loc.diff r s. Definition no_overlap_state (S : State) := no_overlap (getsrc (StateToMove S ++ StateBeing S)) (getdst (StateToMove S ++ StateBeing S)). Definition no_overlap_list := fun l => no_overlap (getsrc l) (getdst l). Lemma Indst_noOverlap_aux: forall l1 l, (forall (s : Reg), In s (getdst l1) -> l = s \/ Loc.diff l s) -> noOverlap_aux l (getdst l1). Proof. intros; induction l1; simpl; auto. destruct a as [a1 a2]; simpl; split. elim (H a2); (try intros H0). left; auto. right; apply Loc.diff_sym; auto. simpl; left; trivial. apply IHl1; intros. apply H; simpl; right; (try assumption). Qed. Lemma no_overlap_noOverlap: forall r, no_overlap_state r -> noOverlap (StateToMove r ++ StateBeing r). Proof. intros r; unfold noOverlap, no_overlap_state. set (l1:=StateToMove r ++ StateBeing r). unfold no_overlap; intros H l H0. apply Indst_noOverlap_aux; intros; apply H; auto. Qed. Theorem Fpmov_correctMoves: forall p e r, simpleDest p -> no_overlap_list p -> noTmp p -> notemporary r -> (forall (x : Reg), In x (getdst p) -> r = x \/ Loc.diff r x) -> get (pexec p e) r = get (sexec (StateDone (Pmov (p, nil, nil))) e) r. Proof. intros p e r SD no_O notmp notempo. generalize (Fpmov_correct (p, nil, nil)); unfold sameExec, exec; simpl; rewrite SB_Pmov; rewrite STM_Pmov; simpl. (repeat rewrite app_nil); intro. apply H; auto. unfold stepInv; simpl; (repeat split); (try (rewrite app_nil; assumption)); auto. generalize (no_overlap_noOverlap (p, nil, nil)); simpl; intros; auto. apply H0; auto; unfold no_overlap_list in H0 |-. unfold no_overlap_state; simpl; (repeat rewrite app_nil); auto. Qed. Theorem Fpmov_correct1: forall (p : Moves) (e : Env) (r : Reg), simpleDest p -> no_overlap_list p -> noTmp p -> notemporary r -> (forall (x : Reg), In x (getdst p) -> r = x \/ Loc.diff r x) -> noWrite p r -> get e r = get (sexec (StateDone (Pmov (p, nil, nil))) e) r. Proof. intros p e r Hsd Hno_O HnoTmp Hrnotempo Hrno_Overlap Hnw. rewrite <- (Fpmov_correctMoves p e); (try assumption). destruct p; auto. destruct m as [m1 m2]; simpl; case (Loc.eq m2 r); intros. elim Hnw; intros; absurd (Loc.diff m2 r); auto. rewrite e0; apply Loc.same_not_diff. elim Hnw; intros H1 H2. rewrite get_update_diff; (try assumption). apply get_noWrite; (try assumption). Qed. Lemma In_SD_diff: forall (s d a1 a2 : Reg) (p : Moves), In (s, d) p -> simpleDest ((a1, a2) :: p) -> Loc.diff a2 d. Proof. intros; induction p. inversion H. elim H; auto. intro; subst a; elim H0; intros H1 H2; elim H1; intros; apply Loc.diff_sym; assumption. intro; apply IHp; auto. apply simpleDest_pop2 with a; (try assumption). Qed. Theorem pexec_correct: forall (e : Env) (m : Move) (p : Moves), In m p -> simpleDest p -> (let (s, d) := m in get (pexec p e) d = get e s). Proof. induction p; intros. elim H. destruct m. elim (in_inv H); intro. rewrite H1; simpl; rewrite get_update_id; auto. destruct a as [a1 a2]; simpl. rewrite get_update_diff. apply IHp; auto. apply (simpleDest_pop (a1, a2)); (try assumption). apply (In_SD_diff r) with ( p := p ) ( a1 := a1 ); auto. Qed. Lemma In_noTmp_notempo: forall (s d : Reg) (p : Moves), In (s, d) p -> noTmp p -> notemporary d. Proof. intros; unfold notemporary; induction p. inversion H. elim H; intro. subst a; elim H0; intros H1 [H3 H2]; (try assumption). intro; apply IHp; auto. destruct a; elim H0; intros _ [H2 H3]; (try assumption). Qed. Lemma In_Indst: forall s d p, In (s, d) p -> In d (getdst p). Proof. intros; induction p; auto. destruct a; simpl. elim H; intro. left; inversion H0; trivial. right; apply IHp; auto. Qed. Lemma In_SD_diff': forall (d a1 a2 : Reg) (p : Moves), In d (getdst p) -> simpleDest ((a1, a2) :: p) -> Loc.diff a2 d. Proof. intros d a1 a2 p H H0; induction p. inversion H. destruct a; elim H. elim H0; simpl; intros. subst r0. elim H1; intros H3 H4; apply Loc.diff_sym; assumption. intro; apply IHp; (try assumption). apply simpleDest_pop2 with (r, r0); (try assumption). Qed. Lemma In_SD_no_o: forall (s d : Reg) (p : Moves), In (s, d) p -> simpleDest p -> forall (x : Reg), In x (getdst p) -> d = x \/ Loc.diff d x. Proof. intros s d p Hin Hsd; induction p. inversion Hin. destruct a as [a1 a2]; elim Hin; intros. inversion H; subst d; subst s. elim H0; intros H1; [left | right]; (try assumption). apply (In_SD_diff' x a1 a2 p); auto. elim H0. intro; subst x. right; apply Loc.diff_sym; apply (In_SD_diff s d a1 a2 p); auto. intro; apply IHp; auto. apply (simpleDest_pop (a1, a2)); assumption. Qed. Lemma getdst_map: forall p, getdst p = map (fun x => snd x) p. Proof. induction p. simpl; auto. destruct a; simpl. rewrite IHp; auto. Qed. Lemma getsrc_map: forall p, getsrc p = map (fun x => fst x) p. Proof. induction p. simpl; auto. destruct a; simpl. rewrite IHp; auto. Qed. Theorem Fpmov_correct2: forall (p : Moves) (e : Env) (m : Move), In m p -> simpleDest p -> no_overlap_list p -> noTmp p -> (let (s, d) := m in get (sexec (StateDone (Pmov (p, nil, nil))) e) d = get e s). Proof. intros p e m Hin Hsd Hno_O HnoTmp; destruct m as [s d]; generalize (Fpmov_correctMoves p e); intros. rewrite <- H; auto. apply pexec_correct with ( m := (s, d) ); auto. apply (In_noTmp_notempo s d p); auto. apply (In_SD_no_o s d p Hin Hsd). Qed. Lemma notindst_nW: forall a p, Loc.notin a (getdst p) -> noWrite p a. Proof. induction p; simpl; auto. destruct a0 as [a1 a2]. simpl. intros H; elim H; intro; split. apply Loc.diff_sym; (try assumption). apply IHp; auto. Qed. Lemma disjoint_tmp__noTmp: forall p, Loc.disjoint (getsrc p) temporaries -> Loc.disjoint (getdst p) temporaries -> noTmp p. Proof. induction p; simpl; auto. destruct a as [a1 a2]; simpl getsrc; simpl getdst; unfold Loc.disjoint; intros; (repeat split). intro; unfold T; case (Loc.type r); apply H; (try (left; trivial; fail)). right; left; trivial. right; right; right; right; left; trivial. intro; unfold T; case (Loc.type r); apply H0; (try (left; trivial; fail)). right; left; trivial. right; right; right; right; left; trivial. apply IHp. apply Loc.disjoint_cons_left with a1; auto. apply Loc.disjoint_cons_left with a2; auto. Qed. Theorem Fpmov_correct_IT3: forall p rs, simpleDest p -> no_overlap_list p -> Loc.disjoint (getsrc p) temporaries -> Loc.disjoint (getdst p) temporaries -> (sexec (StateDone (Pmov (p, nil, nil))) rs) (R IT3) = rs (R IT3). Proof. intros p rs Hsd Hno_O Hdistmpsrc Hdistmpdst. generalize (Fpmov_correctMoves p rs); unfold get, Locmap.get; intros H2. rewrite <- H2; auto. generalize (get_noWrite p (R IT3)); unfold get, Locmap.get; intros. rewrite <- H; auto. apply notindst_nW. apply (Loc.disjoint_notin temporaries). apply Loc.disjoint_sym; auto. right; right; left; trivial. apply disjoint_tmp__noTmp; auto. unfold notemporary, T. intros x; case (Loc.type x); simpl; intro; discriminate. intros x H; right; apply Loc.in_notin_diff with (getdst p); auto. apply Loc.disjoint_notin with temporaries; auto. apply Loc.disjoint_sym; auto. right; right; left; trivial. Qed. Theorem Fpmov_correct_map: forall p rs, simpleDest p -> no_overlap_list p -> Loc.disjoint (getsrc p) temporaries -> Loc.disjoint (getdst p) temporaries -> List.map (sexec (StateDone (Pmov (p, nil, nil))) rs) (getdst p) = List.map rs (getsrc p). Proof. intros; rewrite getsrc_map; rewrite getdst_map; rewrite list_map_compose; rewrite list_map_compose; apply list_map_exten; intros. generalize (Fpmov_correct2 p rs x). destruct x; simpl. unfold get, Locmap.get; intros; auto. rewrite H4; auto. apply disjoint_tmp__noTmp; auto. Qed. Theorem Fpmov_correct_ext: forall p rs, simpleDest p -> no_overlap_list p -> Loc.disjoint (getsrc p) temporaries -> Loc.disjoint (getdst p) temporaries -> forall l, Loc.notin l (getdst p) -> Loc.notin l temporaries -> (sexec (StateDone (Pmov (p, nil, nil))) rs) l = rs l. Proof. intros; generalize (Fpmov_correct1 p rs l); unfold get, Locmap.get; intros. rewrite <- H5; auto. apply disjoint_tmp__noTmp; auto. unfold notemporary; simpl in H4 |-; unfold T; intros x; case (Loc.type x). elim H4; [intros H6 H7; elim H7; [intros H8 H9; (try clear H7 H4); (try exact H8)]]. elim H4; [intros H6 H7; elim H7; [intros H8 H9; elim H9; [intros H10 H11; elim H11; [intros H12 H13; elim H13; [intros H14 H15; (try clear H13 H11 H9 H7 H4); (try exact H14)]]]]]. unfold no_overlap_list, no_overlap in H0 |-; intros. case (Loc.eq l x). intros e; left; (try assumption). intros n; right; (try assumption). apply Loc.in_notin_diff with (getdst p); auto. apply notindst_nW; auto. Qed.