diff options
author | Yann Herklotz <git@yannherklotz.com> | 2022-07-01 18:41:24 +0100 |
---|---|---|
committer | Yann Herklotz <git@yannherklotz.com> | 2022-07-01 18:41:24 +0100 |
commit | 3bf28cdfde1cfcadef07912ec7bde9bc1c5ba8c3 (patch) | |
tree | 32283088dd3a11b157d2bab9130a934b110223ee | |
parent | c90b9ba8d6f37c58519298cfa1ff8960373fcafa (diff) | |
download | vericert-3bf28cdfde1cfcadef07912ec7bde9bc1c5ba8c3.tar.gz vericert-3bf28cdfde1cfcadef07912ec7bde9bc1c5ba8c3.zip |
Add dead code elimination proof mostly
-rw-r--r-- | src/hls/DeadBlocksproof.v | 1052 |
1 files changed, 1052 insertions, 0 deletions
diff --git a/src/hls/DeadBlocksproof.v b/src/hls/DeadBlocksproof.v new file mode 100644 index 0000000..eda9b5e --- /dev/null +++ b/src/hls/DeadBlocksproof.v @@ -0,0 +1,1052 @@ +(** This file contain the proof of the RTLdfs transformation. We show +both that the transformation ensures that generated functions are +satisfying the predicate [wf_dfs_function] and that the transformation +preserves the semantics. *) + +Require Recdef. +Require Import FSets. +Require Import Coqlib. +Require Import Ordered. +Require Import Errors. +Require Import Maps. +Require Import AST. +Require Import Integers. +Require Import Values. +Require Import Globalenvs. +Require Import Op. +Require Import Registers. +Require Import Smallstep. +Require Import DeadBlocks. +Require Import Kildall. +Require Import Conventions. +Require Import Integers. +Require Import Floats. +Require Import Utils. +Require Import Events. +Require Import Gible. +Require Import GibleSeq. +Require Import Relation_Operators. + +Unset Allow StrictProp. + +(** * The [cfg] predicate *) +Variant cfg (code:code) (i j:node) : Prop := + | CFG : forall ins + (HCFG_ins: code!i = Some ins) + (HCFG_in : In j (all_successors ins)), + cfg code i j. + +Inductive cfg_star (code:code) (i:node) : node -> Prop := +| cfg_star0 : cfg_star code i i +| cfg_star1 : forall j k, cfg_star code i j -> cfg code j k -> cfg_star code i k. + +Notation "R **" := (@clos_refl_trans _ R) (at level 30). + +Lemma Rstar_refl : forall A R (i:A), R** i i. +Proof. constructor 2. Qed. + +Lemma Rstar_R : forall A (R:A->A->Prop) (i j:A), R i j -> R** i j. +Proof. constructor 1; auto. Qed. + +Lemma Rstar_trans : forall A (R:A->A->Prop) (i j k:A), + R** i j -> R** j k -> R** i k. +Proof. intros A R i j k; constructor 3 with j; auto. Qed. + +Global Hint Resolve Rstar_trans Rstar_refl Rstar_R: core. + +Lemma star_eq : forall A (R1 R2:A->A->Prop), + (forall i j, R1 i j -> R2 i j) -> + forall i j, R1** i j -> R2** i j. +Proof. + induction 2. + econstructor 1; eauto. + econstructor 2; eauto. + econstructor 3; eauto. +Qed. + +Lemma cfg_star_same_code: forall code1 code2 i, + (forall k, cfg_star code1 i k -> code1!k = code2!k) -> + forall j, cfg_star code1 i j -> cfg_star code2 i j. +Proof. + induction 2. + constructor 1. + constructor 2 with j; auto. + inv H1. + rewrite H in *; auto. + econstructor; eauto. +Qed. + +Lemma cfg_star_same : forall code i j, + cfg_star code i j <-> (cfg code)** i j. +Proof. + split. + induction 1. + constructor 2. + constructor 3 with j; auto. + assert (forall i j, (cfg code0**) i j -> forall k, cfg_star code0 k i -> cfg_star code0 k j). + clear i j; induction 1; auto. + intros. + constructor 2 with x; auto. + intros; apply H with i; auto. + constructor 1. +Qed. + +(** * Utility lemmas *) +Section dfs. +Variable entry:node. +Variable code:code. + +Lemma not_seen_sons_aux0 : forall l0 l1 l2 seen_set seen_set', + fold_left + (fun (ns : prod (list node) (PTree.t unit)) (j : positive) => + let (new, seen) := ns in + match seen ! j with + | Some _ => ns + | None => (j :: new, PTree.set j tt seen) + end) l0 (l1, seen_set) = (l2, seen_set') -> + forall x, In x l1 -> In x l2. +Proof. + induction l0; simpl; intros. + inv H; auto. + destruct (seen_set!a); inv H; eauto with datatypes. +Qed. + +Lemma not_seen_sons_prop1 : forall i j seen_set seen_set' l, + not_seen_sons code i seen_set = (l,seen_set') -> + cfg code i j -> In j l \/ seen_set ! j = Some tt. +Proof. + unfold not_seen_sons; intros. + inv H0. + rewrite HCFG_ins in *. + assert ( + forall l0 l1 l2 seen_set seen_set', + fold_left + (fun (ns : prod (list node) (PTree.t unit)) (j0 : positive) => + let (new, seen) := ns in + match seen ! j0 with + | Some _ => ns + | None => (j0 :: new, PTree.set j0 tt seen) + end) l0 (l1, seen_set) = (l2, seen_set') -> + In j l0 -> In j l2 \/ seen_set ! j = Some tt). + induction l0; simpl; intros. + intuition. + destruct (peq a j). + subst. + case_eq (seen_set0!j); intros. + destruct u; auto. + rewrite H2 in *. + left; eapply not_seen_sons_aux0; eauto with datatypes. + destruct H1. + intuition. + destruct (seen_set0!a); eauto. + elim IHl0 with (1:=H0); auto. + rewrite PTree.gso; auto. + eauto. +Qed. + +Lemma not_seen_sons_prop8 : forall i j seen_set seen_set' l, + not_seen_sons code i seen_set = (l,seen_set') -> + In j l -> cfg code i j. +Proof. + unfold not_seen_sons; intros. + assert ( + forall l0 l1 l2 seen_set seen_set', + fold_left + (fun (ns : prod (list node) (PTree.t unit)) (j0 : positive) => + let (new, seen) := ns in + match seen ! j0 with + | Some _ => ns + | None => (j0 :: new, PTree.set j0 tt seen) + end) l0 (l1, seen_set) = (l2, seen_set') -> + In j l2 -> In j l0 \/ In j l1). + induction l0; simpl; intros. + inv H1; auto. + case_eq (seen_set0!a); intros; rewrite H3 in *. + elim IHl0 with (1:=H1); auto. + elim IHl0 with (1:=H1); auto. + simpl; destruct 1; auto. + case_eq (code!i); intros; rewrite H2 in H. + apply H1 in H; auto; clear H1. + destruct H as [H|H]; try (elim H; fail). + econstructor; eauto. + inv H; elim H0. +Qed. + +Lemma not_seen_sons_prop2 : forall i j seen_set, + In j (fst (not_seen_sons code i seen_set)) -> + seen_set ! j = None. +Proof. + unfold not_seen_sons; intros. + case_eq (code!i); [intros ins Hi|intros Hi]; rewrite Hi in *. + assert (forall l l0 seen_set, + In j + (fst + (fold_left + (fun (ns : prod (list node) (PTree.t unit)) (j : positive) => + let (new, seen) := ns in + match seen ! j with + | Some _ => ns + | None => (j :: new, PTree.set j tt seen) + end) l (l0, seen_set))) -> + In j l0\/ seen_set ! j = None). + induction l; simpl; auto. + intros. + case_eq (seen_set0 ! a); intros; rewrite H1 in *; eauto. + elim IHl with (1:=H0); auto. + simpl; destruct 1; subst; auto. + rewrite PTree.gsspec; destruct peq; auto. + intros; congruence. + elim H0 with (1:=H); auto. + simpl; intuition. + simpl in H; intuition. +Qed. + +Lemma not_seen_sons_prop5 : forall i seen_set, + list_norepet (fst (not_seen_sons code i seen_set)). +Proof. + unfold not_seen_sons; intros. + destruct (code ! i); simpl; try constructor. + assert (forall l l0 seen_set l1 seen_set', + (fold_left + (fun (ns : prod (list node) (PTree.t unit)) (j : positive) => + let (new, seen) := ns in + match seen ! j with + | Some _ => ns + | None => (j :: new, PTree.set j tt seen) + end) l (l0, seen_set)) = (l1,seen_set') -> + (forall x, In x l0 -> seen_set!x = Some tt) -> + list_norepet l0 -> + (forall x, In x l1 -> seen_set'!x = Some tt) /\ list_norepet l1). + induction l; simpl; intros. + inv H ;auto. + case_eq (seen_set0!a); intros; rewrite H2 in *; auto. + elim IHl with (1:=H); auto. + elim IHl with (1:=H); auto. + simpl; destruct 1; auto. + subst; rewrite PTree.gss; auto. + rewrite PTree.gsspec; destruct peq; auto. + constructor; auto. + intro; rewrite (H0 a) in H2; auto; congruence. + generalize (H (all_successors t) nil seen_set). + destruct (fold_left + (fun (ns : prod (list node) (PTree.t unit)) (j : positive) => + let (new, seen) := ns in + match seen ! j with + | Some _ => ns + | None => (j :: new, PTree.set j tt seen) + end) (all_successors t) (nil, seen_set)); intuition. + eelim H0; eauto. + simpl; intuition. + constructor. +Qed. + +Lemma not_seen_sons_prop3_aux : forall l i l0 seen_set l1 seen_set', + seen_set!i = Some tt -> + (fold_left + (fun (ns : prod (list node) (PTree.t unit)) (j : positive) => + let (new, seen) := ns in + match seen ! j with + | Some _ => ns + | None => (j :: new, PTree.set j tt seen) + end) l (l0, seen_set)) = (l1,seen_set') -> + seen_set'!i = Some tt. +Proof. + induction l; simpl; intros. + inv H0; auto. + destruct (seen_set!a). + rewrite (IHl _ _ _ _ _ H H0); auto. + assert ((PTree.set a tt seen_set)! i = Some tt). + rewrite PTree.gsspec; destruct peq; auto. + rewrite (IHl _ _ _ _ _ H1 H0); auto. +Qed. + +Lemma not_seen_sons_prop3 : forall i seen_set seen_set' l, + not_seen_sons code i seen_set = (l,seen_set') -> + forall i, seen_set!i = Some tt -> seen_set'!i = Some tt. +Proof. + unfold not_seen_sons; intros. + destruct (code!i); inv H; auto. + apply not_seen_sons_prop3_aux with (2:=H2); auto. +Qed. + + +Lemma not_seen_sons_prop4 : forall i seen_set seen_set' l, + not_seen_sons code i seen_set = (l,seen_set') -> + forall i, In i l -> seen_set'!i = Some tt. +Proof. + unfold not_seen_sons; intros. + destruct (code!i); inv H; auto. + assert (forall l i l0 seen_set l1 seen_set', + In i l1 -> + (forall i, In i l0 -> seen_set !i = Some tt) -> + (fold_left + (fun (ns : prod (list node) (PTree.t unit)) (j : positive) => + let (new, seen) := ns in + match seen ! j with + | Some _ => ns + | None => (j :: new, PTree.set j tt seen) + end) l (l0, seen_set)) = (l1,seen_set') -> + seen_set'!i = Some tt). + induction l0; simpl; intros. + inv H3; auto. + case_eq (seen_set0 ! a); intros; rewrite H4 in *; inv H3. + apply IHl0 with (3:= H6); auto. + apply IHl0 with (3:= H6); auto. + simpl; destruct 1; subst. + rewrite PTree.gss; auto. + rewrite PTree.gsspec; destruct peq; auto. + apply H with (3:=H2); auto. + simpl; intuition. + elim H0. +Qed. + +Lemma not_seen_sons_prop6 : forall i seen_set seen_set' l, + not_seen_sons code i seen_set = (l,seen_set') -> + forall i, seen_set'!i = Some tt -> seen_set!i = Some tt \/ In i l. +Proof. + unfold not_seen_sons; intros. + destruct (code!i); inv H; auto. + assert (forall l i l0 seen_set l1 seen_set', + (fold_left + (fun (ns : prod (list node) (PTree.t unit)) (j : positive) => + let (new, seen) := ns in + match seen ! j with + | Some _ => ns + | None => (j :: new, PTree.set j tt seen) + end) l (l0, seen_set)) = (l1,seen_set') -> + seen_set'!i = Some tt -> + seen_set !i = Some tt \/ In i l1). + induction l0; simpl; intros. + inv H; auto. + case_eq (seen_set0 ! a); intros; rewrite H3 in *; inv H. + apply IHl0 with (1:= H5); auto. + elim IHl0 with (1:= H5) (i:=i1); auto; intros. + rewrite PTree.gsspec in H; destruct peq; auto. + subst. + right. + eapply not_seen_sons_aux0; eauto with datatypes. + apply H with (1:=H2); auto. +Qed. + +Lemma iter_hh7 : forall seen_list stack + (HH7: forall i j, In i seen_list -> cfg code i j -> In j seen_list \/ In j stack), + forall i j, (cfg code)** i j -> In i seen_list -> In j seen_list \/ + exists k, (cfg code)** i k /\ (cfg code)** k j /\ In k stack. +Proof. + induction 2; intros; auto. + edestruct HH7; eauto. + right; exists y; repeat split; auto. + edestruct IHclos_refl_trans1; eauto. + edestruct IHclos_refl_trans2; eauto. + destruct H3 as [k [T1 [T2 T3]]]. + right; exists k; repeat split; eauto. + destruct H2 as [k [T1 [T2 T3]]]. + right; exists k; repeat split; eauto. +Qed. + +Lemma acc_succ_prop : forall workl seen_set seen_list stack seen code' + (HH1: In entry seen_list) + (HH2: list_norepet stack) + (HH3: forall i, In i stack -> seen_set ! i = Some tt) + (HH4: forall i, In i seen_list -> seen_set ! i = Some tt) + (HH5: forall i, In i seen_list -> In i stack -> False) + (HH6: forall i, seen_set ! i = Some tt -> In i seen_list \/ In i stack) + (HH7: forall i j, In i seen_list -> cfg code i j -> In j seen_list \/ In j stack) + (HH8: forall i, In i seen_list -> (cfg code)** entry i) + (HH11: forall i, In i stack -> (cfg code)** entry i) + (HH9: acc_succ code workl (OK (seen_set,seen_list,stack)) = OK (seen, code')) + (HH10: list_norepet seen_list), + (forall j, (cfg code)** entry j -> In j seen /\ code ! j = code' !j) + /\ (forall j ins, code'!j = Some ins -> In j seen) + /\ list_norepet seen + /\ (forall j, In j seen -> code!j = code'!j) + /\ (forall i j, In i seen -> cfg code i j -> In j seen) + /\ (forall j, In j seen -> (cfg code)** entry j). +Proof. + induction workl; simpl; intros until 11. + destruct stack; inv HH9. + assert (forall j : node, (cfg code **) entry j -> In j seen); intros. + elim (iter_hh7 seen nil HH7 entry j); auto. + destruct 1; intuition. + split; auto. + intros. + rewrite PTree.gcombine; auto. + rewrite HH4; auto. + split; intros. + rewrite PTree.gcombine in H0; auto. + unfold remove_dead in *. + case_eq (seen_set!j); intros; rewrite H1 in *; try congruence. + elim HH6 with j; intros; auto. + destruct u; auto. + split; auto. + split; auto. + intros. + rewrite PTree.gcombine; simpl; auto. + rewrite HH4; auto. + split. + intros; exploit HH7; eauto; destruct 1; simpl; auto. + assumption. + + destruct stack; inv HH9. + assert (forall j : node, (cfg code **) entry j -> In j seen); intros. + elim (iter_hh7 seen nil HH7 entry j); auto. + destruct 1; intuition. + split; auto. + intros. + rewrite PTree.gcombine; auto. + rewrite HH4; auto. + split; intros. + rewrite PTree.gcombine in H0; unfold remove_dead in *. + case_eq (seen_set!j); intros; rewrite H1 in *; try congruence. + elim HH6 with j; intros; auto. + destruct u; auto. + auto. + split; auto. + split; auto. + intros; rewrite PTree.gcombine; auto. + rewrite HH4; auto. + split. + intros; exploit HH7; eauto; destruct 1; auto. + assumption. + + case_eq (not_seen_sons code p (PTree.set p tt seen_set)); intros new seen_set' Hn. + rewrite Hn in *. + + apply IHworkl with (10:=H0); auto with datatypes; clear H0. + + apply list_norepet_append; auto. + generalize (not_seen_sons_prop5 p (PTree.set p tt seen_set)); rewrite Hn; auto. + inv HH2; auto. + unfold list_disjoint; red; intros; subst. + assert (seen_set!y=None). + generalize (not_seen_sons_prop2 p y (PTree.set p tt seen_set)); rewrite Hn; simpl; intros. + apply H1 in H. + rewrite PTree.gsspec in H; destruct peq; try congruence. + rewrite HH3 in H1; auto with datatypes; congruence. + + simpl; intros i Hi. + rewrite in_app in Hi; destruct Hi; auto. + eapply not_seen_sons_prop4; eauto. + eapply not_seen_sons_prop3; eauto. + rewrite PTree.gsspec; destruct peq; auto with datatypes. + +simpl; intros i Hi. + destruct Hi; subst. + eapply not_seen_sons_prop3; eauto. + rewrite PTree.gss; auto. + eapply not_seen_sons_prop3; eauto. + rewrite PTree.gsspec; destruct peq; auto. + +simpl; intros i Hi1 Hi2. + rewrite in_app in Hi2. + destruct Hi2. + generalize (not_seen_sons_prop2 p i (PTree.set p tt seen_set)); rewrite Hn; simpl; intros. + apply H0 in H; clear H0. + rewrite PTree.gsspec in H; destruct peq; try congruence. + destruct Hi1; subst; try congruence. + rewrite HH4 in H; congruence. + destruct Hi1; subst. + inv HH2; intuition. + elim HH5 with i; auto with datatypes. + +intros i Hi. + elim not_seen_sons_prop6 with (1:=Hn) (2:=Hi); intros. + rewrite PTree.gsspec in H; destruct peq; auto. + left; left; auto. + elim HH6 with i; auto with datatypes. + simpl; destruct 1; auto. + right; rewrite in_app; auto. + right; rewrite in_app; auto. + +intros i j Hi1 Hi2. + simpl in Hi1; destruct Hi1; subst. + elim not_seen_sons_prop1 with i j (PTree.set i tt seen_set) seen_set' new; auto; intros. + right; eauto with datatypes. + rewrite PTree.gsspec in H; destruct peq; auto. + left; left; auto. + elim HH6 with j; auto with datatypes. + simpl; destruct 1; auto with datatypes. + elim HH7 with i j; auto with datatypes. + simpl; destruct 1; auto with datatypes. + +simpl; intros i Hi. + destruct Hi; auto with datatypes. + subst; auto with datatypes. + +simpl; intros i Hi. + rewrite in_app in Hi. + destruct Hi; auto with datatypes. + exploit not_seen_sons_prop8; eauto with datatypes. + + constructor; auto. + intro HI; elim HH5 with p; auto with arith datatypes. +Qed. + +End dfs. + +(** * Proof of the well-formedness of generated functions *) +Lemma dfs_prop_aux : forall tf seen code', + dfs tf = OK (seen, code') -> + (forall j, (cfg (fn_code tf))** (fn_entrypoint tf) j -> + In j seen /\ (fn_code tf) ! j = code' ! j) + /\ (forall j ins, code'!j = Some ins -> In j seen) + /\ list_norepet seen + /\ (forall j, In j seen -> (fn_code tf)!j = code'!j) + /\ (forall i j, In i seen -> cfg (fn_code tf) i j -> In j seen) + /\ (forall i, In i seen -> (cfg (fn_code tf))** (fn_entrypoint tf) i). +Proof. + unfold dfs; intros tf seen. + destruct (map (@fst node SeqBB.t) (PTree.elements (fn_code tf))); simpl. + intros; congruence. + case_eq (not_seen_sons (fn_code tf) (fn_entrypoint tf) + (PTree.set (fn_entrypoint tf) tt (PTree.empty unit))); + intros new seen_set TT. + intros code' T; monadInv T. + assert ( + (forall j : node, + (cfg (fn_code tf) **) (fn_entrypoint tf) j -> + In j x /\ (fn_code tf) ! j = code' ! j) /\ + (forall (j : positive) (ins : SeqBB.t), + code' ! j = Some ins -> In j x) /\ list_norepet x /\ + (forall j, In j x -> (fn_code tf)!j = code'!j) /\ + (forall i j, In i x -> cfg (fn_code tf) i j -> In j x) /\ + (forall j : positive, In j x -> (cfg (fn_code tf) **) (fn_entrypoint tf) j) + ). + apply acc_succ_prop with (entry:=(fn_entrypoint tf)) (10:=EQ); auto with datatypes. + + apply list_norepet_append; auto with datatypes. + generalize (not_seen_sons_prop5 (fn_code tf) (fn_entrypoint tf) + (PTree.set (fn_entrypoint tf) tt (PTree.empty unit))); rewrite TT; simpl; auto. + constructor. + intro; simpl; intuition. + + intros. + rewrite in_app in H; destruct H. + generalize (not_seen_sons_prop4 (fn_code tf) (fn_entrypoint tf) + (PTree.set (fn_entrypoint tf) tt (PTree.empty unit))); rewrite TT; simpl; eauto. + elim H. + + simpl; intuition. + subst. + generalize (not_seen_sons_prop3 (fn_code tf) (fn_entrypoint tf) + (PTree.set (fn_entrypoint tf) tt (PTree.empty unit))); rewrite TT; simpl; intros. + eapply H; eauto. + rewrite PTree.gss; auto. + + simpl; intuition; subst. + rewrite in_app in H0; destruct H0. + generalize (not_seen_sons_prop2 (fn_code tf) (fn_entrypoint tf) + (fn_entrypoint tf) + (PTree.set (fn_entrypoint tf) tt (PTree.empty unit))); rewrite TT; simpl. + rewrite PTree.gss; intros. + apply H0 in H; congruence. + elim H. + + intros. + elim not_seen_sons_prop6 with (1:=TT) (i0:=i); auto with datatypes. + rewrite PTree.gsspec; destruct peq; subst; intros; auto with datatypes. + rewrite PTree.gempty in H0; congruence. + + simpl; intuition. + elim not_seen_sons_prop1 with (j:=j) (1:=TT); auto with datatypes. + rewrite PTree.gsspec; destruct peq; subst; intros; auto with datatypes. + rewrite PTree.gempty in H; congruence. + rewrite H1; auto. + + simpl; destruct 1; subst. + constructor 2. + elim H. + + intros i; rewrite in_app; destruct 1. + exploit not_seen_sons_prop8; eauto. + elim H. + + repeat constructor. + intro H; elim H. + + destruct H. + destruct H0. + destruct H1. + destruct H2. + destruct H3 as [H3 H5]. + repeat split; intros. + rewrite <- rev_alt; rewrite <- In_rev; eauto. + elim H with j; auto. + elim H with j; auto. + rewrite <- rev_alt; rewrite <- In_rev; eauto. + rewrite <- rev_alt; auto. + apply list_norepet_rev; auto. + rewrite <- rev_alt in H4; rewrite <- In_rev in H4; eauto. + rewrite <- rev_alt in *; rewrite <- In_rev in *; eauto. + rewrite <- rev_alt in *; rewrite <- In_rev in *; eauto. +Qed. + + (** Lemmas derived from the main lemma.*) +Lemma transf_function_fn_entrypoint : forall f tf, + transf_function f = OK tf -> + fn_entrypoint tf = fn_entrypoint f. +Proof. + intros. + unfold transf_function in H. + destruct (dfs f); simpl in H; try congruence. + destruct p; inv H. + reflexivity. +Qed. + +Lemma transf_function_ppoints1 : forall f tf, + transf_function f = OK tf -> + (forall j, (cfg (fn_code f))** (fn_entrypoint f) j -> + (fn_code f) ! j = (fn_code tf) ! j). +Proof. + intros. + monadInv H. + exploit dfs_prop_aux ; eauto. + intuition. + eelim H1; eauto. +Qed. + +Lemma transf_function_ppoints1' : forall f tf, + transf_function f = OK tf -> + (forall j, (cfg (fn_code f))** (fn_entrypoint f) j -> + (cfg (fn_code tf))** (fn_entrypoint tf) j). +Proof. + intros. + rewrite <- cfg_star_same. + assert (fn_entrypoint tf = fn_entrypoint f) + by (eapply transf_function_fn_entrypoint; eauto). + apply cfg_star_same_code with (fn_code f). + - intros. + rewrite cfg_star_same in *. + clear H0. + rewrite H1 in H2. + exploit transf_function_ppoints1; eauto. + - intuition. + rewrite cfg_star_same; rewrite H1; auto. +Qed. + +(* Lemma transf_function_ppoints2 : forall f tf, *) +(* transf_function f = OK tf -> *) +(* (forall j ins, (fn_code tf)!j = Some ins -> In j (fn_dfs tf)). *) +(* Proof. *) +(* intros. *) +(* monadInv H ; simpl in *. *) +(* exploit dfs_prop_aux ; eauto; intuition eauto. *) +(* Qed. *) + + +(* Lemma transf_function_ppoints3 : forall f tf, *) +(* transf_function f = OK tf -> *) +(* list_norepet (fn_dfs tf). *) +(* Proof. *) +(* intros. *) +(* monadInv H. *) +(* eapply dfs_prop_aux ; eauto. *) +(* Qed. *) + +(* Lemma transf_function_ppoints6 : forall f tf, *) +(* transf_function f = OK tf -> *) +(* (forall i, In i (fn_dfs tf) -> (cfg (RTLdfs.fn_code tf))** (RTLdfs.fn_entrypoint tf) i). *) +(* Proof. *) +(* intros. *) +(* eapply transf_function_ppoints1'; eauto. *) +(* monadInv H. *) +(* eapply dfs_prop_aux ; eauto. *) +(* Qed. *) + +(* Lemma transf_function_wf_dfs : forall f tf, *) +(* transf_function f = OK tf -> *) +(* wf_dfs_function tf. *) +(* Proof. *) +(* constructor. *) +(* eapply transf_function_ppoints2 ; eauto. *) +(* eapply transf_function_ppoints6 ; eauto. *) +(* eapply transf_function_ppoints3 ; eauto. *) +(* Qed. *) + +(** All generated functions satisfy the [wf_dfs] predicate. *) +Require Import Linking. + +Definition match_prog (p: program) (tp: program) := + match_program (fun ctx f tf => transf_fundef f = OK tf) eq p tp. + +Lemma transf_program_match: + forall p tp, transf_program p = OK tp -> match_prog p tp. +Proof. + intros. apply match_transform_partial_program; auto. +Qed. + +(* Lemma match_prog_wf_dfs : forall p tp, *) +(* match_prog p tp -> *) +(* wf_dfs_program tp. *) +(* Proof. *) +(* intros. *) +(* red. intros. *) +(* inv H. intuition. *) +(* revert H1 H0. clear. *) +(* generalize (prog_defs tp). *) +(* induction 1; intros. *) +(* - inv H0. *) +(* - inv H0. *) +(* + clear H1 IHlist_forall2. *) +(* inv H. inv H1. *) +(* destruct f1 ; simpl in * ; try constructor; auto. *) +(* * monadInv H4. *) +(* exploit transf_function_wf_dfs; eauto. *) +(* intros. *) +(* econstructor; eauto. *) +(* * monadInv H4. *) +(* constructor. *) +(* + eapply IHlist_forall2; eauto. *) +(* Qed. *) + +(** * Semantics preservation *) +Section PRESERVATION. + +Variable prog: program. +Variable tprog: program. +Hypothesis TRANSF_PROG: match_prog prog tprog. + +Let ge := Genv.globalenv prog. +Let tge := Genv.globalenv tprog. + +Lemma symbols_preserved: + forall (s: ident), Genv.find_symbol tge s = Genv.find_symbol ge s. +Proof. + intro. + eapply Genv.find_symbol_transf_partial; eauto. +Qed. + +Lemma functions_translated: + forall (v: val) (f: fundef), + Genv.find_funct ge v = Some f -> + exists tf, Genv.find_funct tge v = Some tf /\ transf_fundef f = OK tf. +Proof. + eapply Genv.find_funct_transf_partial; eauto. +Qed. + +Lemma function_ptr_translated: + forall (b: block) (f: fundef), + Genv.find_funct_ptr ge b = Some f -> + exists tf, Genv.find_funct_ptr tge b = Some tf /\ transf_fundef f = OK tf. +Proof. + eapply Genv.find_funct_ptr_transf_partial ; eauto. +Qed. + +Lemma instr_at: + forall f tf pc ins, + transf_function f = OK tf -> + (cfg (fn_code f) **) (fn_entrypoint f) pc -> + (fn_code f)!pc = Some ins -> + (fn_code tf)!pc = Some ins. +Proof. + intros. inv H. + monadInv H3; simpl. + inv EQ. + elim dfs_prop_aux with f x x0; auto; intros. + elim H with pc; auto. + congruence. +Qed. + +Lemma sig_fundef_translated: + forall f tf, + transf_fundef f = OK tf -> + funsig tf = funsig f. +Proof. + intros f tf. destruct f; simpl; intros. + monadInv H; auto. + monadInv EQ; auto. + inv H. simpl; auto. +Qed. + +Lemma find_function_preserved_same : forall r rs f f', + find_function ge (inl ident r) rs = Some f -> + find_function tge (inl ident r) rs = Some f' -> + funsig f = funsig f'. +Proof. + intros. simpl in *. + exploit (functions_translated rs#r) ; eauto. + intros. + destruct H1 as [tf [Htf Oktf]]. + symmetry. + eapply sig_fundef_translated; eauto. + rewrite Htf in H0. inv H0; auto. +Qed. + +Lemma spec_ros_r_find_function: + forall rs f r, + find_function ge (inl _ r) rs = Some f -> + exists tf, + find_function tge (inl _ r) rs = Some tf + /\ transf_fundef f = OK tf. +Proof. + intros. + eapply functions_translated; eauto. +Qed. + +Lemma spec_ros_id_find_function: + forall rs f id, + find_function ge (inr _ id) rs = Some f -> + exists tf, + find_function tge (inr _ id) rs = Some tf + /\ transf_fundef f = OK tf. +Proof. + intros. + simpl in *. + case_eq (Genv.find_symbol ge id) ; intros. + rewrite H0 in H. + rewrite symbols_preserved in * ; eauto ; rewrite H0 in *. + exploit function_ptr_translated; eauto. + rewrite H0 in H ; inv H. +Qed. + +Inductive match_stackframes : list stackframe -> list stackframe -> Prop := +| match_stackframes_nil: match_stackframes nil nil +| match_stackframes_cons: + forall res f sp pc ps rs s tf ts + (STACK : (match_stackframes s ts)) + (SPEC: (transf_function f = OK tf)) + (HCFG: (cfg (fn_code f) **) (fn_entrypoint f) pc), + match_stackframes + ((Stackframe res f sp pc ps rs) :: s) + ((Stackframe res tf sp pc ps rs) :: ts) + . +Hint Constructors match_stackframes: core. + +Variant match_states: state -> state -> Prop := + | match_states_intro: + forall s ts sp pc rs m f tf ps + (SPEC: transf_function f = OK tf) + (HCFG: (cfg (fn_code f) ** ) (fn_entrypoint f) pc) + (STACK: match_stackframes s ts ), + match_states (State s f sp pc rs ps m) (State ts tf sp pc rs ps m) + | match_states_call: + forall s ts f tf args m + (SPEC: transf_fundef f = OK tf) + (STACK: match_stackframes s ts ), + match_states (Callstate s f args m) (Callstate ts tf args m) + | match_states_return: + forall s ts v m + (STACK: match_stackframes s ts ), + match_states (Returnstate s v m) (Returnstate ts v m). +Hint Constructors match_states: core. + +Lemma transf_initial_states: + forall st1, initial_state prog st1 -> + exists st2, initial_state tprog st2 /\ match_states st1 st2. +Proof. + intros. inversion H. + exploit function_ptr_translated ; eauto. intros [tf [Hfind Htrans]]. + assert (MEM: (Genv.init_mem tprog) = Some m0) + by (eapply (Genv.init_mem_transf_partial TRANSF_PROG); eauto). + exists (Callstate nil tf nil m0); split. + - econstructor; eauto. + + replace (prog_main tprog) with (prog_main prog). rewrite symbols_preserved; eauto. + symmetry; eapply match_program_main; eauto. + + rewrite <- H3. apply sig_fundef_translated; auto. + - eapply match_states_call ; eauto. +Qed. + +Lemma transf_final_states: + forall st1 st2 r, + match_states st1 st2 -> final_state st1 r -> final_state st2 r. +Proof. + intros. inv H0. inv H. + inv STACK. + constructor. +Qed. + +Lemma stacksize_preserved: forall f tf, + transf_function f = OK tf -> + fn_stacksize f = fn_stacksize tf. +Proof. + intros. + monadInv H. auto. +Qed. + +Lemma senv_preserved: + Senv.equiv (Genv.to_senv ge) (Genv.to_senv tge). +Proof. + eapply Genv.senv_transf_partial; eauto. +Qed. + +Create HintDb valagree. +Hint Resolve find_function_preserved_same: valagree. +Hint Resolve symbols_preserved : valagree. +Hint Resolve eval_addressing_preserved : valagree. +Hint Resolve eval_operation_preserved : valagree. +Hint Resolve sig_fundef_translated : valagree. +Hint Resolve senv_preserved : valagree. +Hint Resolve stacksize_preserved: valagree. + +Ltac try_succ f pc pc' := + try (eapply Rstar_trans ; eauto) ; constructor ; + (eapply (CFG (fn_code f) pc pc'); eauto; simpl; auto). + +Lemma transl_step_correct: + forall s1 t s2, + step ge s1 t s2 -> + forall s1' (MS: match_states s1 s1'), + exists s2', step tge s1' t s2' /\ match_states s2 s2'. +Proof. + induction 1; intros; inv MS; auto. + + (* inop *) + exploit instr_at; eauto; intros. + destruct state0. + exists (State stack f0 sp0 pc0 rs0 pr0 m0); split ; eauto. + econstructor; auto. eauto. admit. admit. + constructor; auto. admit. + try_succ f pc pc'. + + (* iop *) + exploit instr_at; eauto; intros. + exists (RTLdfs.State ts tf sp pc' (rs#res<- v) m); split ; eauto. + eapply RTLdfs.exec_Iop ; eauto. + rewrite <- H0 ; eauto with valagree. + constructor; auto. + try_succ f pc pc'. + + (* iload *) + exploit instr_at; eauto; intros. + exists (RTLdfs.State ts tf sp pc' (rs#dst <- v) m); split ; eauto. + eapply RTLdfs.exec_Iload ; eauto. + try solve [rewrite <- H0 ; eauto with valagree]. + econstructor ; eauto. + try_succ f pc pc'. + + (* istore *) + exploit instr_at; eauto; intros. + exists (RTLdfs.State ts tf sp pc' rs m'); split ; eauto. + eapply RTLdfs.exec_Istore ; eauto. + try solve [rewrite <- H0 ; eauto with valagree]. + constructor ; eauto. + try_succ f pc pc'. + + (* icall *) + destruct ros. + exploit spec_ros_r_find_function ; eauto. + intros. destruct H1 as [tf' [Hfind OKtf']]. + + exploit instr_at; eauto; intros. + exists (RTLdfs.Callstate (RTLdfs.Stackframe res tf sp pc' rs :: ts) tf' rs ## args m) ; split ; eauto. + eapply RTLdfs.exec_Icall ; eauto. + eauto with valagree. + constructor; auto. + constructor; auto. + try_succ f pc pc'. + + exploit spec_ros_id_find_function ; eauto. + intros. destruct H1 as [tf' [Hfind OKtf']]. + + exploit instr_at; eauto; intros. + exists (RTLdfs.Callstate (RTLdfs.Stackframe res tf sp pc' rs :: ts) tf' rs ## args m) ; split ; eauto. + eapply RTLdfs.exec_Icall ; eauto. + eauto with valagree. + constructor; auto. + constructor ; eauto. + try_succ f pc pc'. + + (* itailcall *) + destruct ros. + exploit spec_ros_r_find_function ; eauto. + intros. destruct H1 as [tf' [Hfind OKtf']]. + + exploit instr_at; eauto; intros. + exploit find_function_preserved_same ; eauto. + intros. + exists (RTLdfs.Callstate ts tf' rs##args m'); split ; eauto. + eapply RTLdfs.exec_Itailcall ; eauto with valagree. + replace (RTLdfs.fn_stacksize tf) with (fn_stacksize f); eauto with valagree. + + exploit spec_ros_id_find_function ; eauto. + intros. destruct H1 as [tf' [Hfind OKtf']]. + + exploit instr_at; eauto; intros. + exists (RTLdfs.Callstate ts tf' rs##args m'); split ; eauto. + eapply RTLdfs.exec_Itailcall ; eauto with valagree. + replace (RTLdfs.fn_stacksize tf) with (fn_stacksize f); eauto with valagree. + + (* ibuiltin *) + exploit instr_at; eauto; intros. + exists (RTLdfs.State ts tf sp pc' (regmap_setres res vres rs) m') ; split ; eauto. + eapply RTLdfs.exec_Ibuiltin with (vargs:= vargs) ; eauto. + eapply eval_builtin_args_preserved with (2:= H0); eauto with valagree. + eapply external_call_symbols_preserved; eauto with valagree. + + constructor; auto. try_succ f pc pc'. + + (* ifso *) + + exploit instr_at; eauto; intros. + destruct b. + exists (RTLdfs.State ts tf sp ifso rs m); split ; eauto. + eapply RTLdfs.exec_Icond ; eauto. + constructor; auto. + try_succ f pc ifso. + + (* ifnot *) + exploit instr_at; eauto; intros. + exists (RTLdfs.State ts tf sp ifnot rs m); split ; eauto. + eapply RTLdfs.exec_Icond ; eauto. + constructor; auto. + try_succ f pc ifnot. + + (* ijump *) + exploit instr_at; eauto; intros. + exists (RTLdfs.State ts tf sp pc' rs m); split ; eauto. + eapply RTLdfs.exec_Ijumptable ; eauto. + constructor; auto. + try_succ f pc pc'. + eapply list_nth_z_in; eauto. + + (* ireturn *) + exploit instr_at; eauto; intros. + exists (RTLdfs.Returnstate ts (regmap_optget or Vundef rs) m'); split ; eauto. + eapply RTLdfs.exec_Ireturn ; eauto. + rewrite <- H0 ; eauto with valagree. + rewrite stacksize_preserved with f tf ; eauto. + + (* internal *) + simpl in SPEC. monadInv SPEC. simpl in STACK. + exists (RTLdfs.State ts x + (Vptr stk Ptrofs.zero) + x.(RTLdfs.fn_entrypoint) + (init_regs args x.(RTLdfs.fn_params)) + m'). + split. + eapply RTLdfs.exec_function_internal; eauto. + rewrite stacksize_preserved with f x in H ; auto. + replace (RTL.fn_entrypoint f) with (RTLdfs.fn_entrypoint x). + replace (RTL.fn_params f) with (RTLdfs.fn_params x). + + econstructor ; eauto. + replace (RTLdfs.fn_entrypoint x) with (fn_entrypoint f). + eapply Rstar_refl ; eauto. + monadInv EQ. auto. + monadInv EQ. auto. + monadInv EQ. auto. + + (* external *) + inv SPEC. + exists (RTLdfs.Returnstate ts res m'). split. + eapply RTLdfs.exec_function_external; eauto. + eapply external_call_symbols_preserved; eauto with valagree. + econstructor ; eauto. + + (* return state *) + inv STACK. + exists (RTLdfs.State ts0 tf sp pc (rs# res <- vres) m); + split; ( try constructor ; eauto). +Qed. + +Theorem transf_program_correct: + forward_simulation (RTL.semantics prog) (RTLdfs.semantics tprog). +Proof. + eapply forward_simulation_step. + eapply senv_preserved. + eexact transf_initial_states. + eexact transf_final_states. + exact transl_step_correct. +Qed. + +End PRESERVATION. |