(* *********************************************************************)
(*                                                                     *)
(*              The Compcert verified compiler                         *)
(*                                                                     *)
(*      Laurence Rideau, INRIA Sophia-Antipolis-M\u00e9diterran\u00e9e           *)
(*      Bernard Paul Serpette, INRIA Sophia-Antipolis-M\u00e9diterran\u00e9e     *)
(*      Xavier Leroy, INRIA Paris-Rocquencourt                         *)
(*                                                                     *)
(*  Copyright Institut National de Recherche en Informatique et en     *)
(*  Automatique.  All rights reserved.  This file is distributed       *)
(*  under the terms of the GNU General Public License as published by  *)
(*  the Free Software Foundation, either version 2 of the License, or  *)
(*  (at your option) any later version.  This file is also distributed *)
(*  under the terms of the INRIA Non-Commercial License Agreement.     *)
(*                                                                     *)
(* *********************************************************************)

(** 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 designed by Laurence Rideau and
  Bernard Serpette.  It is described in the paper
  ``Tilting at windmills with Coq: Formal verification of
  a compilation algorithm for parallel moves'',
  #<A HREF="http://hal.inria.fr/inria-00176007">#
  http://hal.inria.fr/inria-00176007
  #</A>#
*)

Require Import Relations.
Require Import Axioms.
Require Import Coqlib.
Require Import Recdef.
Section PARMOV.
(** * Registers, moves, and their semantics *) (** The development is parameterized by the type of registers, equipped with a decidable equality. *) Variable reg: Type.
Variable reg_eq : forall (r1 r2: reg), {r1=r2} + {r1<>r2}.
(** The [temp] function maps every register [r] to the register that should be used to save the value of [r] temporarily while performing a cyclic assignment involving [r]. In the simplest case, there is only one such temporary register [rtemp] and [temp] is the constant function [fun r => rtemp]. In more realistic cases, different temporary registers can be used to hold different values. In the case of Compcert, we have two temporary registers, one for integer values and the other for floating-point values, and [temp] returns the appropriate temporary depending on the type of its argument. *) Variable temp: reg -> reg.
Definition is_temp (r: reg): Prop := exists s, r = temp s.
(** A set of moves is a list of pairs of registers, of the form (source, destination). *) Definition moves := (list (reg * reg))%type.
(* src -> dst *) Definition srcs (m: moves) := List.map (@fst reg reg) m.
Definition dests (m: moves) := List.map (@snd reg reg) m.
(** ** Semantics of moves *) (** The dynamic semantics of moves is given in terms of environments. An environment is a mapping of registers to their current values. *) Variable val: Type.
Definition env := reg -> val.
Proof.
Admitted.
Proof (@extensionality reg val).
(** The main operation over environments is update: it assigns a value [v] to a register [r] and preserves the values of other registers. *) Definition update (r: reg) (v: val) (e: env) : env := fun r' => if reg_eq r' r then v else e r'.
Proof.
intros.
unfold update.
destruct reg_eq.
eauto.
congruence.
Qed.
Proof.
unfold update.
intros.
destruct (reg_eq r r).
{
auto.
}
{
congruence.
}
Qed.
Proof.
intros.
unfold update.
destruct reg_eq.
try congruence.
eauto.
Qed.
Proof.
unfold update.
intros.
destruct (reg_eq r' r).
{
congruence.
}
{
auto.
}
Qed.
Proof.
unfold update.
intros.
apply env_ext.
intros.
destruct reg_eq.
try congruence.
eauto.
Qed.
Proof.
intros.
apply env_ext.
intro.
unfold update.
destruct (reg_eq r0 r).
{
congruence.
}
{
congruence.
}
Qed.
Proof.
Admitted.
Proof.
intros.
apply env_ext.
intro.
unfold update.
destruct (reg_eq r r1).
{
destruct (reg_eq r r2).
{
auto.
congruence.
}
{
auto.
}
}
{
destruct (reg_eq r r2).
{
auto.
}
{
auto.
}
}
Qed.
Proof.
Admitted.
Proof.
intros.
apply env_ext.
intro.
unfold update.
destruct (reg_eq r0 r).
{
auto.
}
{
auto.
}
Qed.
(** A list of moves [(src1, dst1), ..., (srcN, dstN)] can be given three different semantics, as environment transformers. The first semantics corresponds to a parallel assignment: [dst1, ..., dstN] are set to the initial values of [src1, ..., srcN]. *) Fixpoint exec_par (m: moves) (e: env) {struct m}: env := match m with | nil => e | (s, d) :: m' => update d (e s) (exec_par m' e) end.
(** The second semantics corresponds to a sequence of individual assignments: first, [dst1] is set to the initial value of [src1]; then, [dst2] is set to the current value of [src2] after the first assignment; etc. *) Fixpoint exec_seq (m: moves) (e: env) {struct m}: env := match m with | nil => e | (s, d) :: m' => exec_seq m' (update d (e s) e) end.
(** The third semantics is also sequential, but executes the moves in reverse order, starting with [srcN, dstN] and finishing with [src1, dst1]. *) Fixpoint exec_seq_rev (m: moves) (e: env) {struct m}: env := match m with | nil => e | (s, d) :: m' => let e' := exec_seq_rev m' e in update d (e' s) e' end.
(** * Specification of the non-deterministic algorithm *) (** Rideau and Serpette's parallel move compilation algorithm is first specified as a non-deterministic set of rewriting rules operating over triples [(mu, sigma, tau)] of moves. We define these rules as an inductive predicate [transition] relating triples of moves, and its reflexive transitive closure [transitions]. *) Inductive state: Type := State (mu: moves) (sigma: moves) (tau: moves) : state.
Definition no_read (mu: moves) (d: reg) : Prop := ~In d (srcs mu).
Inductive transition: state -> state -> Prop := | tr_nop: forall mu1 r mu2 sigma tau, transition (State (mu1 ++ (r, r) :: mu2) sigma tau) (State (mu1 ++ mu2) sigma tau) | tr_start: forall mu1 s d mu2 tau, transition (State (mu1 ++ (s, d) :: mu2) nil tau) (State (mu1 ++ mu2) ((s, d) :: nil) tau) | tr_push: forall mu1 d r mu2 s sigma tau, transition (State (mu1 ++ (d, r) :: mu2) ((s, d) :: sigma) tau) (State (mu1 ++ mu2) ((d, r) :: (s, d) :: sigma) tau) | tr_loop: forall mu sigma s d tau, transition (State mu (sigma ++ (s, d) :: nil) tau) (State mu (sigma ++ (temp s, d) :: nil) ((s, temp s) :: tau)) | tr_pop: forall mu s0 d0 s1 d1 sigma tau, no_read mu d1 -> d1 <> s0 -> transition (State mu ((s1, d1) :: sigma ++ (s0, d0) :: nil) tau) (State mu (sigma ++ (s0, d0) :: nil) ((s1, d1) :: tau)) | tr_last: forall mu s d tau, no_read mu d -> transition (State mu ((s, d) :: nil) tau) (State mu nil ((s, d) :: tau)).
Definition transitions: state -> state -> Prop := clos_refl_trans state transition.
(** ** Well-formedness properties of states *) (** A state [mu, sigma, tau] is well-formed if the following properties hold: - [mu] concatenated with [sigma] is a ``mill'', that is, no destination appears twice (predicate [is_mill] below). - No temporary register appears in [mu] (predicate [move_no_temp]). - No temporary register appears in [sigma] except perhaps as the source of the last move in [sigma] (predicate [temp_last]). - [sigma] is a ``path'', that is, the source of a move is the destination of the following move. *) Definition is_mill (m: moves) : Prop := list_norepet (dests m).
Definition is_not_temp (r: reg) : Prop := forall d, r <> temp d.
Definition move_no_temp (m: moves) : Prop := forall s d, In (s, d) m -> is_not_temp s /\ is_not_temp d.
Definition temp_last (m: moves) : Prop := match List.rev m with | nil => True | (s, d) :: m' => is_not_temp d /\ move_no_temp m' end.
Definition is_first_dest (m: moves) (d: reg) : Prop := match m with | nil => True | (s0, d0) :: _ => d = d0 end.
Inductive is_path: moves -> Prop := | is_path_nil: is_path nil | is_path_cons: forall s d m, is_first_dest m s -> is_path m -> is_path ((s, d) :: m).
Inductive state_wf: state -> Prop := | state_wf_intro: forall mu sigma tau, is_mill (mu ++ sigma) -> move_no_temp mu -> temp_last sigma -> is_path sigma -> state_wf (State mu sigma tau).
Proof.
induction m1.
simpl.
intros.
eauto.
simpl.
destruct m2.
simpl.
decEq.
apply IHm1.
simpl.
decEq.
apply IHm1.
Qed.
Proof.
intros.
unfold dests.
apply map_app.
Qed.
Proof.
intros.
apply dests_append.
Qed.
Proof.
intros.
unfold dests.
rewrite map_app.
reflexivity.
Qed.
Proof.
induction m1.
simpl.
intros.
eauto.
simpl.
intros.
unfold fst.
f_equal.
eauto.
Qed.
Proof.
intros.
unfold srcs.
apply map_app.
Qed.
Proof.
intros.
apply srcs_append.
Qed.
Proof.
intros.
unfold srcs.
rewrite map_app.
reflexivity.
Qed.
Proof.
Admitted.
Proof.
induction s.
{
destruct d.
{
simpl.
intros.
tauto.
}
{
simpl.
intros.
discriminate.
}
}
{
destruct d.
{
simpl.
intros.
discriminate.
}
{
simpl.
intros.
elim (IHs d).
{
intros.
split.
{
congruence.
}
{
congruence.
}
}
{
intros.
congruence.
}
}
}
Qed.
(** Some properties of [is_mill] and [dests_disjoint]. *) Definition dests_disjoint (m1 m2: moves) : Prop := list_disjoint (dests m1) (dests m2).
Proof.
intros.
unfold dests_disjoint.
unfold list_disjoint.
unfold In.
split.
eauto.
eauto.
Qed.
Proof.
unfold dests_disjoint.
intros.
split.
{
intros.
apply list_disjoint_sym.
auto.
}
{
intros.
apply list_disjoint_sym.
auto.
}
Qed.
Proof.
Admitted.
Proof.
unfold dests_disjoint.
unfold list_disjoint.
simpl.
intros.
split.
{
intros.
split.
{
auto.
}
{
firstorder.
}
}
{
intros.
destruct H.
elim H0.
{
intro.
red.
intro.
subst.
contradiction.
}
{
intro.
apply H.
{
auto.
}
{
auto.
}
}
}
Qed.
Proof.
intros.
rewrite dests_disjoint_sym.
rewrite dests_disjoint_cons_left.
intuition.
apply dests_disjoint_sym.
eauto.
apply dests_disjoint_sym.
eauto.
Qed.
Proof.
intros.
rewrite dests_disjoint_sym.
rewrite dests_disjoint_cons_left.
rewrite dests_disjoint_sym.
tauto.
Qed.
Proof.
Admitted.
Proof.
unfold dests_disjoint.
unfold list_disjoint.
intros.
split.
{
intros.
split.
{
intros.
apply H.
{
eauto.
rewrite dests_append.
apply in_or_app.
auto.
}
{
eauto.
}
}
{
intros.
apply H.
{
eauto.
rewrite dests_append.
apply in_or_app.
auto.
}
{
eauto.
}
}
}
{
intros.
destruct H.
rewrite dests_append in H0.
elim (in_app_or _ _ _ H0).
{
auto.
}
{
auto.
}
}
Qed.
Proof.
Admitted.
Proof.
intros.
rewrite dests_disjoint_sym.
rewrite dests_disjoint_append_left.
intuition.
{
rewrite dests_disjoint_sym.
assumption.
}
{
rewrite dests_disjoint_sym.
assumption.
}
{
rewrite dests_disjoint_sym.
assumption.
}
{
rewrite dests_disjoint_sym.
assumption.
}
Qed.
Proof.
intros.
red.
intuition.
inv H.
eauto.
inv H.
eauto.
econstructor.
eauto.
eauto.
Qed.
Proof.
unfold is_mill.
unfold dests_disjoint.
intros.
simpl.
split.
{
intros.
inversion H.
tauto.
}
{
intros.
constructor.
{
tauto.
}
{
tauto.
}
}
Qed.
Proof.
Admitted.
Proof.
unfold is_mill.
unfold dests_disjoint.
intros.
rewrite dests_append.
apply list_norepet_app.
Qed.
Proof.
unfold move_no_temp.
induction m1.
simpl.
intros.
eauto.
simpl.
intros.
inv H1.
eauto.
eauto.
Qed.
Proof.
intros.
red.
intros.
elim (in_app_or _ _ _ H1).
{
intro.
apply H.
auto.
}
{
intro.
apply H0.
auto.
}
Qed.
Proof.
Admitted.
Proof.
intros.
red.
intros.
apply H.
rewrite <- List.In_rev.
auto.
Qed.
Proof.
Admitted.
Proof.
intros until sigma.
unfold temp_last.
repeat rewrite rev_unit.
auto.
Qed.
Proof.
Admitted.
Proof.
unfold temp_last.
intros.
simpl.
simpl in H.
destruct (rev sigma).
{
simpl in *.
intuition.
red.
simpl.
intros.
elim H.
{
intros.
inversion H4.
subst.
tauto.
}
{
intros.
tauto.
}
}
{
simpl in *.
destruct p as [sN dN].
intuition.
red.
intros.
elim (in_app_or _ _ _ H).
{
intros.
apply H3.
auto.
}
{
intros.
elim H4.
{
intros.
inversion H5.
subst.
tauto.
}
{
intros.
elim H5.
}
}
}
Qed.
Proof.
Admitted.
Proof.
intros until d2.
change ((s1, d1) :: sigma ++ (s2, d2) :: nil) with ((((s1, d1) :: nil) ++ sigma) ++ ((s2, d2) :: nil)).
unfold temp_last.
repeat rewrite rev_unit.
intuition.
simpl in H1.
red.
intros.
apply H1.
apply in_or_app.
auto.
Qed.
Proof.
intros.
inv H.
eauto.
Qed.
Proof.
intros.
inversion H.
subst.
auto.
Qed.
Proof.
Admitted.
Proof.
induction sigma.
{
simpl.
intros.
constructor.
{
red.
auto.
}
{
constructor.
}
}
{
simpl.
intros.
inversion H.
subst.
clear H.
constructor.
{
destruct sigma as [ | [s1 d1] sigma'].
{
simpl.
simpl in H2.
auto.
}
{
simpl.
simpl in H2.
auto.
}
}
{
auto.
}
}
Qed.
Proof.
Admitted.
Proof.
induction sigma.
{
simpl.
intros.
red.
simpl.
tauto.
}
{
simpl.
intros.
inversion H.
subst.
clear H.
simpl.
assert (In s (dests (sigma ++ (s0, d0) :: nil))).
{
destruct sigma as [ | [s1 d1] sigma'].
{
simpl.
simpl in H2.
intuition.
}
{
simpl.
simpl in H2.
intuition.
}
}
{
apply incl_cons.
{
simpl.
tauto.
}
{
apply incl_tran with (s0 :: dests (sigma ++ (s0, d0) :: nil)).
{
eapply IHsigma.
eauto.
}
{
red.
simpl.
tauto.
}
}
}
}
Qed.
Proof.
Admitted.
Proof.
intros.
generalize (path_sources_dests _ _ _ H0).
intro.
intro.
elim H1.
elim (H2 _ H3).
{
intro.
congruence.
}
{
intro.
auto.
}
Qed.
Proof.
intros.
split.
simpl.
intros.
split.
eauto.
eauto.
intros.
red.
simpl.
intuition.
Qed.
Proof.
intros.
simpl.
intuition auto.
Qed.
Proof.
Admitted.
Proof.
intros.
rewrite dests_append.
rewrite in_app.
tauto.
Qed.
Hint Rewrite is_mill_cons is_mill_append dests_disjoint_cons_left dests_disjoint_cons_right dests_disjoint_append_left dests_disjoint_append_right notin_dests_cons notin_dests_append: pmov.
Proof.
Admitted.
Proof.
induction 1.
{
intro WF.
inversion WF as [mu0 sigma0 tau0 A B C D].
subst.
autorewrite with pmov in A.
constructor.
{
autorewrite with pmov.
(* Nop *) tauto.
}
{
autorewrite with pmov.
red.
intros.
apply B.
apply list_in_insert.
auto.
}
{
autorewrite with pmov.
auto.
}
{
autorewrite with pmov.
auto.
}
}
{
intro WF.
inversion WF as [mu0 sigma0 tau0 A B C D].
subst.
autorewrite with pmov in A.
constructor.
{
autorewrite with pmov.
(* Start *) tauto.
}
{
autorewrite with pmov.
red.
intros.
apply B.
apply list_in_insert.
auto.
}
{
autorewrite with pmov.
red.
simpl.
split.
{
elim (B s d).
{
auto.
}
{
apply in_or_app.
right.
apply in_eq.
}
}
{
red.
simpl.
tauto.
}
}
{
autorewrite with pmov.
constructor.
{
exact I.
}
{
constructor.
}
}
}
{
intro WF.
inversion WF as [mu0 sigma0 tau0 A B C D].
subst.
autorewrite with pmov in A.
constructor.
{
autorewrite with pmov.
(* Push *) intuition.
}
{
autorewrite with pmov.
red.
intros.
apply B.
apply list_in_insert.
auto.
}
{
autorewrite with pmov.
elim (B d r).
{
apply temp_last_push.
auto.
}
{
apply in_or_app.
right.
apply in_eq.
}
}
{
autorewrite with pmov.
constructor.
{
simpl.
auto.
}
{
auto.
}
}
}
{
intro WF.
inversion WF as [mu0 sigma0 tau0 A B C D].
subst.
autorewrite with pmov in A.
constructor.
{
autorewrite with pmov.
(* Loop *) tauto.
}
{
autorewrite with pmov.
auto.
}
{
autorewrite with pmov.
eapply temp_last_change_last_source.
eauto.
}
{
autorewrite with pmov.
eapply is_path_change_last_source.
eauto.
}
}
{
intro WF.
inversion WF as [mu0 sigma0 tau0 A B C D].
subst.
autorewrite with pmov in A.
constructor.
{
autorewrite with pmov.
(* Pop *) intuition.
}
{
autorewrite with pmov.
auto.
}
{
autorewrite with pmov.
eapply temp_last_pop.
eauto.
}
{
autorewrite with pmov.
eapply is_path_pop.
eauto.
}
}
{
intro WF.
inversion WF as [mu0 sigma0 tau0 A B C D].
subst.
autorewrite with pmov in A.
constructor.
{
autorewrite with pmov.
(* Last *) intuition.
}
{
autorewrite with pmov.
auto.
}
{
autorewrite with pmov.
unfold temp_last.
simpl.
auto.
}
{
autorewrite with pmov.
constructor.
}
}
Qed.
Proof.
Admitted.
Proof.
induction 1.
{
intros.
eauto.
eapply transition_preserves_wf.
{
eauto.
}
{
eauto.
}
}
{
intros.
eauto.
}
{
intros.
eauto.
}
Qed.
(** ** Transitions preserve semantics *) (** We define the semantics of states as follows. For a triple [mu, sigma, tau], we perform the moves [tau] in reverse sequential order, then the moves [mu ++ sigma] in parallel. *) Definition statemove (st: state) (e: env) := match st with | State mu sigma tau => exec_par (mu ++ sigma) (exec_seq_rev tau e) end.
Proof.
Admitted.
Proof.
induction m.
{
simpl.
intros.
auto.
}
{
simpl.
intros.
destruct a as [s d].
rewrite update_o.
{
apply IHm.
tauto.
}
{
simpl in H.
intuition.
}
}
Qed.
Proof.
Admitted.
Proof.
induction m1.
{
simpl.
intros.
auto.
}
{
simpl.
intros.
destruct a as [s0 d0].
simpl in H.
rewrite IHm1.
{
simpl.
apply update_commut.
tauto.
}
{
tauto.
}
}
Qed.
Proof.
Admitted.
Proof.
intros.
autorewrite with pmov in H.
rewrite exec_par_lift.
{
simpl.
replace (e r) with (exec_par (m1 ++ m2) e r).
{
apply update_ident.
}
{
apply exec_par_outside.
autorewrite with pmov.
tauto.
}
}
{
tauto.
}
Qed.
Proof.
unfold exec_seq.
induction m1.
simpl.
intros.
eauto.
intros m2.
simpl.
intuition.
Qed.
Proof.
induction m1.
{
simpl.
intros.
auto.
}
{
simpl.
intros.
destruct a as [s d].
rewrite IHm1.
auto.
}
Qed.
Proof.
Admitted.
Proof.
induction m1.
{
simpl.
intros.
auto.
}
{
simpl.
intros.
destruct a as [s d].
rewrite IHm1.
auto.
}
Qed.
Proof.
Admitted.
Proof.
induction m.
{
simpl.
intros.
auto.
}
{
simpl.
intros.
destruct a as [s d].
rewrite exec_seq_app.
simpl.
rewrite IHm.
auto.
}
Qed.
Proof.
Admitted.
Proof.
intros.
generalize (exec_seq_exec_seq_rev (List.rev m) e).
rewrite List.rev_involutive.
auto.
Qed.
Proof.
Admitted.
Proof.
unfold no_read.
induction m.
{
simpl.
intros.
auto.
}
{
simpl.
intros.
destruct a as [s0 d0].
simpl in *.
rewrite IHm.
{
rewrite update_commut.
{
f_equal.
f_equal.
apply update_o.
tauto.
}
{
tauto.
}
}
{
tauto.
}
{
tauto.
}
}
Qed.
Proof.
Admitted.
Proof.
induction m1.
{
simpl.
intros.
auto.
}
{
simpl.
intros.
destruct a as [s d].
f_equal.
{
eauto.
}
{
eauto.
}
}
Qed.
Proof.
Admitted.
Proof.
induction sl.
{
destruct dl.
{
simpl.
intros.
try discriminate.
split.
{
auto.
}
{
auto.
}
}
{
simpl.
intros.
try discriminate.
}
}
{
destruct dl.
{
simpl.
intros.
try discriminate.
}
{
simpl.
intros.
try discriminate.
inversion H0.
subst.
clear H0.
injection H.
intro.
clear H.
destruct (IHsl dl H0 H4) as [A B].
set (e' := exec_par (combine sl dl) e) in *.
split.
{
decEq.
{
apply update_s.
}
{
rewrite <- A.
apply list_map_exten.
intros.
rewrite update_o.
{
auto.
}
{
congruence.
}
}
}
{
intros.
rewrite update_o.
{
apply B.
tauto.
}
{
intuition.
}
}
}
}
Qed.
(** [env_equiv] is an equivalence relation between environments capturing the fact that two environments assign the same values to non-temporary registers, but can disagree on the values of temporary registers. *) Definition env_equiv (e1 e2: env) : Prop := forall r, is_not_temp r -> e1 r = e2 r.
Proof.
intros.
red.
intros.
eauto.
Qed.
Proof.
unfold env_equiv.
auto.
Qed.
Proof.
intros.
red.
intros.
subst.
eauto.
Qed.
Proof.
unfold env_equiv.
intros.
rewrite H.
auto.
Qed.
Proof.
intros.
red.
intros.
rewrite H.
eauto.
eauto.
Qed.
Proof.
unfold env_equiv.
intros.
symmetry.
auto.
Qed.
Proof.
intros.
red.
intros.
rewrite H.
eauto.
eauto.
Qed.
Proof.
unfold env_equiv.
intros.
transitivity (e2 r).
{
auto.
}
{
auto.
}
Qed.
Proof.
Admitted.
Proof.
unfold move_no_temp.
induction m.
{
simpl.
intros.
auto.
}
{
simpl.
intros.
destruct a as [s d].
red.
intros.
unfold update.
destruct (reg_eq r d).
{
apply H0.
elim (H s d).
{
tauto.
}
{
tauto.
}
}
{
apply IHm.
{
auto.
}
{
auto.
}
{
auto.
}
}
}
Qed.
Proof.
Admitted.
Proof.
induction 1.
{
intro WF.
inversion WF as [mu0 sigma0 tau0 A B C D].
subst.
simpl.
(* nop *) apply env_equiv_refl'.
unfold statemove.
repeat rewrite app_ass.
simpl.
symmetry.
apply exec_par_ident.
rewrite app_ass in A.
exact A.
}
{
intro WF.
inversion WF as [mu0 sigma0 tau0 A B C D].
subst.
simpl.
(* start *) apply env_equiv_refl'.
unfold statemove.
autorewrite with pmov in A.
rewrite exec_par_lift.
{
repeat rewrite app_ass.
simpl.
rewrite exec_par_lift.
{
reflexivity.
}
{
tauto.
}
}
{
autorewrite with pmov.
tauto.
}
}
{
intro WF.
inversion WF as [mu0 sigma0 tau0 A B C D].
subst.
simpl.
(* push *) apply env_equiv_refl'.
unfold statemove.
autorewrite with pmov in A.
rewrite exec_par_lift.
{
rewrite exec_par_lift.
{
simpl.
rewrite exec_par_lift.
{
repeat rewrite app_ass.
simpl.
rewrite exec_par_lift.
{
simpl.
apply update_commut.
intuition.
}
{
tauto.
}
}
{
autorewrite with pmov.
tauto.
}
}
{
autorewrite with pmov.
intuition.
}
}
{
autorewrite with pmov.
intuition.
}
}
{
intro WF.
inversion WF as [mu0 sigma0 tau0 A B C D].
subst.
simpl.
(* loop *) unfold statemove.
simpl exec_seq_rev.
set (e1 := exec_seq_rev tau e).
autorewrite with pmov in A.
repeat rewrite <- app_ass.
assert (~In d (dests (mu ++ sigma))).
{
autorewrite with pmov.
tauto.
}
{
repeat rewrite exec_par_lift.
{
auto.
simpl.
repeat rewrite <- app_nil_end.
assert (move_no_temp (mu ++ sigma)).
{
red in C.
rewrite rev_unit in C.
destruct C.
apply move_no_temp_append.
{
auto.
}
{
auto.
apply move_no_temp_rev.
auto.
}
}
{
set (e2 := update (temp s) (e1 s) e1).
set (e3 := exec_par (mu ++ sigma) e1).
set (e4 := exec_par (mu ++ sigma) e2).
assert (env_equiv e2 e1).
{
unfold e2.
red.
intros.
apply update_o.
apply H1.
}
{
assert (env_equiv e4 e3).
{
unfold e4.
unfold e3.
apply exec_par_env_equiv.
{
auto.
}
{
auto.
}
}
{
red.
intros.
unfold update.
destruct (reg_eq r d).
{
unfold e2.
apply update_s.
}
{
apply H2.
auto.
}
}
}
}
}
{
auto.
}
{
auto.
}
}
}
{
intro WF.
inversion WF as [mu0 sigma0 tau0 A B C D].
subst.
simpl.
(* pop *) apply env_equiv_refl'.
unfold statemove.
simpl exec_seq_rev.
set (e1 := exec_seq_rev tau e).
autorewrite with pmov in A.
apply exec_par_append_eq.
{
simpl.
apply exec_par_update_no_read.
{
apply no_read_path.
{
auto.
}
{
auto.
eapply is_path_pop.
eauto.
}
{
auto.
autorewrite with pmov.
tauto.
}
}
{
autorewrite with pmov.
tauto.
}
}
{
intros.
apply update_o.
red.
intro.
subst r.
elim (H H1).
}
}
{
intro WF.
inversion WF as [mu0 sigma0 tau0 A B C D].
subst.
simpl.
(* last *) apply env_equiv_refl'.
unfold statemove.
simpl exec_seq_rev.
set (e1 := exec_seq_rev tau e).
apply exec_par_append_eq.
{
simpl.
auto.
}
{
intros.
apply update_o.
red.
intro.
subst r.
elim (H H0).
}
}
Qed.
Proof.
Admitted.
Proof.
induction 1.
{
intros.
eapply transition_preserves_semantics.
{
eauto.
}
{
eauto.
}
}
{
intros.
apply env_equiv_refl.
}
{
intros.
apply env_equiv_trans with (statemove y e).
{
auto.
apply IHclos_refl_trans2.
eapply transitions_preserve_wf.
{
eauto.
}
{
eauto.
}
}
{
auto.
}
}
Qed.
Proof.
Admitted.
Proof.
intros.
constructor.
{
rewrite <- app_nil_end.
auto.
}
{
auto.
}
{
red.
simpl.
auto.
}
{
constructor.
}
Qed.
Proof.
Admitted.
Proof.
intros.
generalize (transitions_preserve_semantics _ _ e H1 (state_wf_start _ H H0)).
unfold statemove.
simpl.
rewrite <- app_nil_end.
rewrite exec_seq_exec_seq_rev.
auto.
Qed.
(** * Determinisation of the transition relation *) (** We now define a deterministic variant [dtransition] of the transition relation [transition]. [dtransition] is deterministic in the sense that at most one transition applies to a given state. *) Inductive dtransition: state -> state -> Prop := | dtr_nop: forall r mu tau, dtransition (State ((r, r) :: mu) nil tau) (State mu nil tau) | dtr_start: forall s d mu tau, s <> d -> dtransition (State ((s, d) :: mu) nil tau) (State mu ((s, d) :: nil) tau) | dtr_push: forall mu1 d r mu2 s sigma tau, no_read mu1 d -> dtransition (State (mu1 ++ (d, r) :: mu2) ((s, d) :: sigma) tau) (State (mu1 ++ mu2) ((d, r) :: (s, d) :: sigma) tau) | dtr_loop_pop: forall mu s r0 d sigma tau, no_read mu r0 -> dtransition (State mu ((s, r0) :: sigma ++ (r0, d) :: nil) tau) (State mu (sigma ++ (temp r0, d) :: nil) ((s, r0) :: (r0, temp r0) :: tau)) | dtr_pop: forall mu s0 d0 s1 d1 sigma tau, no_read mu d1 -> d1 <> s0 -> dtransition (State mu ((s1, d1) :: sigma ++ (s0, d0) :: nil) tau) (State mu (sigma ++ (s0, d0) :: nil) ((s1, d1) :: tau)) | dtr_last: forall mu s d tau, no_read mu d -> dtransition (State mu ((s, d) :: nil) tau) (State mu nil ((s, d) :: tau)).
Definition dtransitions: state -> state -> Prop := clos_refl_trans state dtransition.
Proof.
Admitted.
Proof.
induction 1.
{
intro.
unfold transitions.
apply rt_step.
exact (tr_nop nil r mu nil tau).
}
{
intro.
unfold transitions.
apply rt_step.
exact (tr_start nil s d mu tau).
}
{
intro.
unfold transitions.
apply rt_step.
apply tr_push.
}
{
intro.
unfold transitions.
eapply rt_trans.
{
apply rt_step.
change ((s, r0) :: sigma ++ (r0, d) :: nil) with (((s, r0) :: sigma) ++ (r0, d) :: nil).
apply tr_loop.
}
{
apply rt_step.
simpl.
apply tr_pop.
{
auto.
}
{
inv H0.
generalize H6.
change ((s, r0) :: sigma ++ (r0, d) :: nil) with (((s, r0) :: sigma) ++ (r0, d) :: nil).
unfold temp_last.
rewrite List.rev_unit.
intros [E F].
elim (F s r0).
{
unfold is_not_temp.
auto.
}
{
rewrite <- List.In_rev.
apply in_eq.
}
}
}
}
{
intro.
unfold transitions.
apply rt_step.
apply tr_pop.
{
auto.
}
{
auto.
}
}
{
intro.
unfold transitions.
apply rt_step.
apply tr_last.
auto.
}
Qed.
Proof.
Admitted.
Proof.
unfold transitions.
induction 1.
{
intros.
eapply transition_determ.
{
eauto.
}
{
eauto.
}
}
{
intros.
apply rt_refl.
}
{
intros.
apply rt_trans with y.
{
auto.
}
{
apply IHclos_refl_trans2.
apply transitions_preserve_wf with x.
{
auto.
red.
auto.
}
{
auto.
}
}
}
Qed.
Proof.
Admitted.
Proof.
intros.
eapply transitions_correctness.
{
eauto.
}
{
eauto.
}
{
eauto.
apply transitions_determ.
{
auto.
}
{
apply state_wf_start.
{
auto.
}
{
auto.
}
}
}
Qed.
(** * The compilation function *) (** We now define a function that takes a well-formed parallel move [mu] and returns a sequence of elementary moves [tau] that is semantically equivalent. We start by defining a number of auxiliary functions. *) Fixpoint split_move (m: moves) (r: reg) {struct m} : option (moves * reg * moves) := match m with | nil => None | (s, d) :: tl => if reg_eq s r then Some (nil, d, tl) else match split_move tl r with | None => None | Some (before, d', after) => Some ((s, d) :: before, d', after) end end.
Fixpoint is_last_source (r: reg) (m: moves) {struct m} : bool := match m with | nil => false | (s, d) :: nil => if reg_eq s r then true else false | (s, d) :: tl => is_last_source r tl end.
Fixpoint replace_last_source (r: reg) (m: moves) {struct m} : moves := match m with | nil => nil | (s, d) :: nil => (r, d) :: nil | s_d :: tl => s_d :: replace_last_source r tl end.
Definition final_state (st: state) : bool := match st with | State nil nil _ => true | _ => false end.
Definition parmove_step (st: state) : state := match st with | State nil nil _ => st | State ((s, d) :: tl) nil l => if reg_eq s d then State tl nil l else State tl ((s, d) :: nil) l | State t ((s, d) :: b) l => match split_move t d with | Some (t1, r, t2) => State (t1 ++ t2) ((d, r) :: (s, d) :: b) l | None => match b with | nil => State t nil ((s, d) :: l) | _ => if is_last_source d b then State t (replace_last_source (temp d) b) ((s, d) :: (d, temp d) :: l) else State t b ((s, d) :: l) end end end.
Proof.
Admitted.
Proof.
unfold no_read.
induction m.
{
simpl.
intros.
tauto.
}
{
simpl.
intros.
destruct a as [s d].
destruct (reg_eq s r).
{
subst s.
auto.
}
{
specialize (IHm r).
destruct (split_move m r) as [[[before d'] after] | ].
{
destruct IHm.
subst m.
simpl.
intuition.
}
{
simpl.
intuition.
}
}
}
Qed.
Proof.
Admitted.
Proof.
induction m.
{
simpl.
destruct (reg_eq s r).
{
congruence.
}
{
congruence.
}
}
{
simpl.
destruct a as [s0 d0].
case_eq (m ++ (s, d) :: nil).
{
intros.
generalize (app_cons_not_nil m nil (s, d)).
congruence.
}
{
intros.
rewrite <- H.
auto.
}
}
Qed.
Proof.
Admitted.
Proof.
induction m.
{
simpl.
auto.
}
{
simpl.
destruct a as [s0 d0].
case_eq (m ++ (s, d) :: nil).
{
intros.
generalize (app_cons_not_nil m nil (s, d)).
congruence.
}
{
intros.
rewrite <- H.
congruence.
}
}
Qed.
Proof.
Admitted.
Proof.
intros st NOTFINAL.
destruct st as [mu sigma tau].
unfold parmove_step.
case_eq mu.
{
intros MEQ.
case_eq sigma.
{
intros SEQ.
subst mu sigma.
simpl in NOTFINAL.
discriminate.
}
{
intros [ss sd] stl SEQ.
simpl.
case_eq stl.
{
intros STLEQ.
apply dtr_last.
red.
simpl.
auto.
}
{
intros xx1 xx2 STLEQ.
elim (@exists_last _ stl).
{
intros sigma1 [[ss1 sd1] SEQ2].
rewrite <- STLEQ.
clear STLEQ xx1 xx2.
generalize (is_last_source_charact sd ss1 sd1 sigma1).
rewrite SEQ2.
destruct (is_last_source sd (sigma1 ++ (ss1, sd1) :: nil)).
{
intro.
subst ss1.
rewrite replace_last_source_charact.
apply dtr_loop_pop.
red.
simpl.
auto.
}
{
intro.
apply dtr_pop.
{
red.
simpl.
auto.
}
{
auto.
}
}
}
{
congruence.
}
}
}
}
{
intros [ms md] mtl MEQ.
case_eq sigma.
{
intros SEQ.
destruct (reg_eq ms md).
{
subst.
apply dtr_nop.
}
{
apply dtr_start.
auto.
}
}
{
intros [ss sd] stl SEQ.
generalize (split_move_charact ((ms, md) :: mtl) sd).
case (split_move ((ms, md) :: mtl) sd).
{
intros [[before r] after].
intros [MEQ2 NOREAD].
rewrite MEQ2.
apply dtr_push.
auto.
}
{
idtac.
intro NOREAD.
case_eq stl.
{
intros STLEQ.
apply dtr_last.
auto.
}
{
intros xx1 xx2 STLEQ.
elim (@exists_last _ stl).
{
intros sigma1 [[ss1 sd1] SEQ2].
rewrite <- STLEQ.
clear STLEQ xx1 xx2.
generalize (is_last_source_charact sd ss1 sd1 sigma1).
rewrite SEQ2.
destruct (is_last_source sd (sigma1 ++ (ss1, sd1) :: nil)).
{
intro.
subst ss1.
rewrite replace_last_source_charact.
apply dtr_loop_pop.
auto.
}
{
intro.
apply dtr_pop.
{
auto.
}
{
auto.
}
}
}
{
congruence.
}
}
}
}
}
Qed.
(** The compilation function is obtained by iterating the [parmov_step] function. To show that this iteration always terminates, we introduce the following measure over states. *) Open Scope nat_scope.
Definition measure (st: state) : nat := match st with | State mu sigma tau => 2 * List.length mu + List.length sigma end.
Proof.
Admitted.
Proof.
induction 1.
{
repeat (simpl; rewrite List.app_length).
simpl.
omega.
}
{
repeat (simpl; rewrite List.app_length).
simpl.
omega.
}
{
repeat (simpl; rewrite List.app_length).
simpl.
omega.
}
{
repeat (simpl; rewrite List.app_length).
simpl.
omega.
}
{
repeat (simpl; rewrite List.app_length).
simpl.
omega.
}
{
repeat (simpl; rewrite List.app_length).
simpl.
omega.
}
Qed.
Proof.
Admitted.
Proof.
intros.
apply measure_decreasing_1.
apply parmove_step_compatible.
auto.
Qed.
Proof.
Admitted.
Proof.
intros.
apply measure_decreasing_2.
auto.
Qed.
Proof.
Admitted.
Proof.
unfold dtransitions.
intro st.
functional induction (parmove_aux st).
{
destruct _x; destruct _x0; simpl in e; discriminate || apply rt_refl.
}
{
eapply rt_trans.
{
apply rt_step.
apply parmove_step_compatible.
eauto.
}
{
auto.
}
}
Qed.
Definition parmove (mu: moves) : moves := List.rev (parmove_aux (State mu nil nil)).
Proof.
Admitted.
Proof.
intros.
unfold parmove.
apply dtransitions_correctness.
{
auto.
}
{
auto.
}
{
auto.
apply parmove_aux_transitions.
}
Qed.
(** Here is an alternate formulation of [parmove], where the parallel move problem is given as two separate lists of sources and destinations. *) Definition parmove2 (sl dl: list reg) : moves := parmove (List.combine sl dl).
Proof.
Admitted.
Proof.
intros.
destruct (srcs_dests_combine sl dl H) as [A B].
assert (env_equiv e' (exec_par (List.combine sl dl) e)).
{
unfold e'.
unfold parmove2.
apply parmove_correctness.
{
red.
intros.
split.
{
apply H1.
eapply List.in_combine_l.
eauto.
}
{
apply H2.
eapply List.in_combine_r.
eauto.
}
}
{
red.
rewrite B.
auto.
}
}
{
destruct (exec_par_combine e sl dl H H0) as [C D].
set (e1 := exec_par (combine sl dl) e) in *.
split.
{
rewrite <- C.
apply list_map_exten.
intros.
symmetry.
apply H3.
auto.
}
{
intros.
transitivity (e1 r).
{
auto.
}
{
auto.
}
}
}
Qed.
(** * Additional syntactic properties *) (** We now show an additional property of the sequence of moves generated by [parmove mu]: any such move [s -> d] is either already present in [mu], or of the form [temp s -> d] or [s -> temp s] for some [s -> d] in [mu]. This syntactic property is useful to show that [parmove] preserves register classes, for instance. *) Section PROPERTIES.
Variable initial_move: moves.
Inductive wf_move: reg -> reg -> Prop := | wf_move_same: forall s d, In (s, d) initial_move -> wf_move s d | wf_move_temp_left: forall s d, wf_move s d -> wf_move (temp s) d | wf_move_temp_right: forall s d, wf_move s d -> wf_move s (temp s).
Definition wf_moves (m: moves) : Prop := forall s d, In (s, d) m -> wf_move s d.
Proof.
Admitted.
Proof.
unfold wf_moves.
intros.
simpl.
firstorder.
inversion H0.
subst s0 d0.
auto.
Qed.
Proof.
Admitted.
Proof.
unfold wf_moves.
intros.
split.
{
intros.
split.
{
intros.
apply H.
apply in_or_app.
auto.
}
{
intros.
apply H.
apply in_or_app.
auto.
}
}
{
intros.
destruct H.
elim (in_app_or _ _ _ H0).
{
intro.
auto.
}
{
intro.
auto.
}
}
Qed.
Hint Rewrite wf_moves_cons wf_moves_append: pmov.
Inductive wf_state: state -> Prop := | wf_state_intro: forall mu sigma tau, wf_moves mu -> wf_moves sigma -> wf_moves tau -> wf_state (State mu sigma tau).
Proof.
Admitted.
Proof.
induction 1.
{
intro WF.
inv WF.
constructor.
{
autorewrite with pmov in *.
intuition.
}
{
autorewrite with pmov in *.
intuition.
}
{
autorewrite with pmov in *.
intuition.
}
}
{
intro WF.
inv WF.
constructor.
{
autorewrite with pmov in *.
intuition.
}
{
autorewrite with pmov in *.
intuition.
}
{
autorewrite with pmov in *.
intuition.
}
}
{
intro WF.
inv WF.
constructor.
{
autorewrite with pmov in *.
intuition.
}
{
autorewrite with pmov in *.
intuition.
}
{
autorewrite with pmov in *.
intuition.
}
}
{
intro WF.
inv WF.
constructor.
{
autorewrite with pmov in *.
intuition.
}
{
autorewrite with pmov in *.
intuition.
apply wf_move_temp_left.
auto.
}
{
autorewrite with pmov in *.
intuition.
eapply wf_move_temp_right.
eauto.
}
}
{
intro WF.
inv WF.
constructor.
{
autorewrite with pmov in *.
intuition.
}
{
autorewrite with pmov in *.
intuition.
}
{
autorewrite with pmov in *.
intuition.
}
}
{
intro WF.
inv WF.
constructor.
{
autorewrite with pmov in *.
intuition.
}
{
autorewrite with pmov in *.
intuition.
}
{
autorewrite with pmov in *.
intuition.
}
}
Qed.
Proof.
Admitted.
Proof.
induction 1.
{
intros.
eauto.
eapply dtransition_preserves_wf_state.
{
eauto.
}
{
eauto.
}
}
{
intros.
eauto.
}
{
intros.
eauto.
}
Qed.
End PROPERTIES.
Proof.
Admitted.
Proof.
intros.
assert (wf_state mu (State mu nil nil)).
{
constructor.
{
red.
intros.
apply wf_move_same.
auto.
}
{
red.
simpl.
tauto.
}
{
red.
simpl.
tauto.
}
}
{
generalize (dtransitions_preserve_wf_state mu _ _ (parmove_aux_transitions (State mu nil nil)) H).
intro WFS.
inv WFS.
unfold parmove.
red.
intros.
apply H5.
rewrite List.In_rev.
auto.
}
Qed.
Proof.
intros.
apply parmove_wf_moves.
Qed.
Proof.
intros.
unfold parmove2.
apply parmove_wf_moves.
Qed.
Proof.
Admitted.
Proof.
induction 1.
{
split.
{
left.
change s with (fst (s, d)).
unfold srcs.
apply List.in_map.
auto.
}
{
left.
change d with (snd (s, d)).
unfold dests.
apply List.in_map.
auto.
}
}
{
split.
{
right.
exists s.
auto.
}
{
tauto.
}
}
{
split.
{
tauto.
}
{
right.
exists s.
auto.
}
}
Qed.
Proof.
Admitted.
Proof.
intros.
apply wf_move_initial_reg_or_temp.
apply parmove_wf_moves.
auto.
Qed.
Proof.
Admitted.
Proof.
intros.
destruct (list_in_map_inv (@fst reg reg) _ _ H) as [[s' d'] [A B]].
simpl in A.
exists d'.
congruence.
Qed.
Proof.
Admitted.
Proof.
intros.
destruct (list_in_map_inv (@snd reg reg) _ _ H) as [[s' d'] [A B]].
simpl in A.
exists s'.
congruence.
Qed.
Proof.
Admitted.
Proof.
intros.
destruct (in_srcs _ _ H) as [d A].
destruct (parmove_initial_reg_or_temp _ _ _ A).
auto.
Qed.
Proof.
Admitted.
Proof.
intros.
destruct (in_dests _ _ H) as [s A].
destruct (parmove_initial_reg_or_temp _ _ _ A).
auto.
Qed.
(** As a second corollary, we show that [parmov] preserves register classes, in the sense made precise below. *) Section REGISTER_CLASSES.
Variable class: Type.
Variable regclass: reg -> class.
Hypothesis temp_preserves_class: forall r, regclass (temp r) = regclass r.
Definition is_class_compatible (mu: moves) : Prop := forall s d, In (s, d) mu -> regclass s = regclass d.
Proof.
Admitted.
Proof.
intros.
assert (forall s d, wf_move mu s d -> regclass s = regclass d).
{
induction 1.
{
apply H.
auto.
}
{
rewrite temp_preserves_class.
auto.
}
{
symmetry.
apply temp_preserves_class.
}
}
{
red.
intros.
apply H0.
apply parmove_wf_moves.
auto.
}
Qed.
End REGISTER_CLASSES.
(** * Extension to partially overlapping registers *) (** We now extend the previous results to the case where distinct registers can partially overlap, so that assigning to one register changes the value of the other. We asuume given a disjointness relation [disjoint] between registers. *) Variable disjoint: reg -> reg -> Prop.
Hypothesis disjoint_sym: forall r1 r2, disjoint r1 r2 -> disjoint r2 r1.
Hypothesis disjoint_not_equal: forall r1 r2, disjoint r1 r2 -> r1 <> r2.
(** Two registers partially overlap if they are different and not disjoint. For the Coq development, it is easier to define the complement: two registers do not partially overlap if they are identical or disjoint. *) Definition no_overlap (r1 r2: reg) : Prop := r1 = r2 \/ disjoint r1 r2.
Proof.
intros.
red.
inv H.
eauto.
eauto.
Qed.
Proof.
intros.
destruct H.
{
left.
auto.
}
{
right.
auto.
}
Qed.
(** We axiomatize the effect of assigning a value to a register over an execution environment. The target register is set to the given value (property [weak_update_s]), and registers disjoint from the target keep their previous values (property [weak_update_d]). The values of other registers are undefined after the assignment. *) Variable weak_update: reg -> val -> env -> env.
Hypothesis weak_update_s: forall r v e, weak_update r v e r = v.
Hypothesis weak_update_d: forall r1 v e r2, disjoint r1 r2 -> weak_update r1 v e r2 = e r2.
Fixpoint weak_exec_seq (m: moves) (e: env) {struct m}: env := match m with | nil => e | (s, d) :: m' => weak_exec_seq m' (weak_update d (e s) e) end.
Definition disjoint_list (r: reg) (l: list reg) : Prop := forall r', In r' l -> disjoint r r'.
Inductive pairwise_disjoint: list reg -> Prop := | pairwise_disjoint_nil: pairwise_disjoint nil | pairwise_disjoint_cons: forall r l, disjoint_list r l -> pairwise_disjoint l -> pairwise_disjoint (r :: l).
Definition disjoint_temps (r: reg) : Prop := forall t, is_temp t -> disjoint r t.
Section OVERLAP.
(** We consider a parallel move problem [mu] that satisfies the following conditions, which are stronger, overlap-aware variants of the [move_no_temp mu] and [is_mill mu] conditions used previously. *) Variable mu: moves.
(** Sources and destinations are disjoint from all temporary registers. *) Hypothesis mu_no_temporaries_src: forall s, In s (srcs mu) -> disjoint_temps s.
Hypothesis mu_no_temporaries_dst: forall d, In d (dests mu) -> disjoint_temps d.
(** Destinations are pairwise disjoint. *) Hypothesis mu_dest_pairwise_disjoint: pairwise_disjoint (dests mu).
(** Sources and destinations do not partially overlap. *) Hypothesis mu_src_dst_no_overlap: forall s d, In s (srcs mu) -> In d (dests mu) -> no_overlap s d.
(** Distinct temporaries do not partially overlap. *) Hypothesis temps_no_overlap: forall t1 t2, is_temp t1 -> is_temp t2 -> no_overlap t1 t2.
Proof.
Admitted.
Proof.
intros.
red.
intro.
assert (r <> r).
{
apply disjoint_not_equal.
apply H.
auto.
}
{
congruence.
}
Qed.
Proof.
induction l.
intros.
econstructor.
intuition.
inv H.
econstructor.
eauto.
eauto.
Qed.
Proof.
induction 1.
{
constructor.
}
{
constructor.
{
apply disjoint_list_notin.
auto.
}
{
auto.
}
}
Qed.
Proof.
unfold disjoint_temps.
unfold is_temp.
intros.
red.
intros.
eauto.
Qed.
Proof.
intros.
red.
intros.
apply disjoint_not_equal.
apply H.
exists d.
auto.
Qed.
Proof.
unfold is_mill.
inv mu_dest_pairwise_disjoint.
econstructor.
econstructor.
apply disjoint_list_notin.
eauto.
apply pairwise_disjoint_norepet.
eauto.
Qed.
Proof.
red.
apply pairwise_disjoint_norepet.
auto.
Qed.
Proof.
Admitted.
Proof.
red.
intros.
split.
{
apply disjoint_temps_not_temp.
apply mu_no_temporaries_src.
auto.
unfold srcs.
change s with (fst (s,d)).
apply List.in_map.
auto.
}
{
apply disjoint_temps_not_temp.
apply mu_no_temporaries_dst.
auto.
unfold dests.
change d with (snd (s,d)).
apply List.in_map.
auto.
}
Qed.
(** We define the ``adherence'' of the problem [mu] as the set of registers that partially overlap with one of the registers possibly assigned by the parallel move: destinations and temporaries. Again, we define the complement of the ``adherence'' set, which is more convenient for Coq reasoning. *) Definition no_adherence (r: reg) : Prop := forall x, In x (dests mu) \/ is_temp x -> no_overlap x r.
Proof.
induction m.
simpl.
intros.
red.
left.
easy.
simpl.
intuition.
red.
inv H.
eauto.
red.
inv H.
eauto.
red.
inv H.
eauto.
red.
inv H.
intuition.
Qed.
Proof.
induction 1.
{
intros.
elim H.
}
{
intros.
simpl in *.
destruct H1.
{
destruct H2.
{
left.
congruence.
}
{
subst.
right.
apply H.
auto.
}
}
{
destruct H2.
{
subst.
right.
apply disjoint_sym.
apply H.
auto.
}
{
auto.
}
}
}
Qed.
Proof.
Admitted.
Proof.
intros.
red.
intros.
destruct H0.
{
apply no_overlap_pairwise with (dests mu).
{
auto.
}
{
auto.
}
{
auto.
}
}
{
right.
apply disjoint_sym.
apply mu_no_temporaries_dst.
{
auto.
}
{
auto.
}
}
Qed.
Proof.
Admitted.
Proof.
intros.
red.
intros.
destruct H0.
{
apply no_overlap_sym.
apply mu_src_dst_no_overlap.
{
auto.
}
{
auto.
}
}
{
right.
apply disjoint_sym.
apply mu_no_temporaries_src.
{
auto.
}
{
auto.
}
}
Qed.
Proof.
Admitted.
Proof.
intros.
red.
intros.
destruct H0.
{
right.
apply mu_no_temporaries_dst.
{
auto.
}
{
auto.
}
}
{
apply temps_no_overlap.
{
auto.
}
{
auto.
}
}
Qed.
(** The relation [env_match] holds between two environments [e1] and [e2] if they assign the same values to all registers not in the adherence set. *) Definition env_match (e1 e2: env) : Prop := forall r, no_adherence r -> e1 r = e2 r.
Proof.
Admitted.
Proof.
intros.
red.
intros.
assert (no_overlap d r).
{
apply H2.
auto.
}
{
destruct H3.
{
subst.
rewrite update_s.
rewrite weak_update_s.
apply H1.
destruct H.
{
apply no_adherence_src.
auto.
}
{
apply no_adherence_tmp.
auto.
}
}
{
rewrite update_o.
{
rewrite weak_update_d.
{
apply H1.
auto.
}
{
auto.
}
}
{
apply not_eq_sym.
apply disjoint_not_equal.
auto.
}
}
}
Qed.
Proof.
induction m.
simpl.
intros.
eauto.
simpl.
intuition.
apply IHm.
intros.
eauto.
intros.
eauto.
apply weak_update_match.
eauto.
eauto.
eauto.
Qed.
Proof.
induction m.
{
intros.
simpl.
auto.
}
{
intros.
simpl.
destruct a as [s d].
simpl in H.
simpl in H0.
apply IHm.
{
auto.
}
{
auto.
}
{
auto.
apply weak_update_match.
{
auto.
}
{
auto.
}
{
auto.
}
}
}
Qed.
End OVERLAP.
Proof.
Admitted.
Proof.
intros.
assert (list_norepet dl).
{
apply pairwise_disjoint_norepet.
auto.
}
{
assert (forall r : reg, In r sl -> is_not_temp r).
{
intros.
apply disjoint_temps_not_temp.
auto.
}
{
assert (forall r : reg, In r dl -> is_not_temp r).
{
intros.
apply disjoint_temps_not_temp.
auto.
}
{
generalize (parmove2_correctness sl dl H H5 H6 H7 e).
set (e1 := exec_seq (parmove2 sl dl) e).
intros [A B].
destruct (srcs_dests_combine sl dl H) as [C D].
assert (env_match (combine sl dl) e1 e').
{
unfold parmove2.
unfold e1.
unfold e'.
apply weak_exec_seq_match.
{
try (rewrite C).
try (rewrite D).
auto.
}
{
try (rewrite C).
try (rewrite D).
auto.
}
{
try (rewrite C).
try (rewrite D).
auto.
}
{
try (rewrite C).
try (rewrite D).
auto.
}
{
try (rewrite C).
try (rewrite D).
auto.
intros.
rewrite <- C.
apply parmove_srcs_initial_reg_or_temp.
auto.
}
{
try (rewrite C).
try (rewrite D).
auto.
intros.
rewrite <- D.
apply parmove_dests_initial_reg_or_temp.
auto.
}
{
try (rewrite C).
try (rewrite D).
auto.
red.
auto.
}
}
{
split.
{
rewrite <- A.
apply list_map_exten.
intros.
apply H8.
apply no_adherence_dst.
{
rewrite D.
auto.
}
{
rewrite D.
auto.
}
{
rewrite D.
auto.
}
}
{
intros.
transitivity (e1 r).
{
symmetry.
apply H8.
red.
rewrite D.
intros.
destruct H11.
{
right.
apply disjoint_sym.
apply H9.
auto.
}
{
right.
apply disjoint_sym.
apply H10.
auto.
}
}
{
apply B.
{
apply disjoint_list_notin.
auto.
}
{
apply disjoint_temps_not_temp.
auto.
}
}
}
}
}
}
}
Qed.
End PARMOV.