Module KildallComp


Require Import Coqlib.
Require Import Iteration.
Require Import Maps.
Require Import Lattice.
Require Import Kildall.
Require Import Classical.

Section CORRECTNESS.

Lemma add_successors_correct2:
  forall tolist from pred n s,
    ~ (In n pred!!!s) -> (~In s tolist \/ n<>from) ->
    ~ In n (add_successors pred from tolist)!!!s.
Proof.
  induction tolist; simpl; intros.
  - tauto.
  - apply IHtolist.
    * intro.
      unfold successors_list at 1 in H1.
      { case_eq ((PTree.set a (from :: pred !!! a) pred) ! s);
        [ intros l Hl | intros Hl]; rewrite Hl in *.
        - (* normal case *)
          destruct (peq a s); subst.
          rewrite PTree.gss in Hl. inv Hl. inv H1.
          destruct H0. elim H0. intuition. congruence.
                       elim H0. auto.
                       elim H. auto.
          rewrite PTree.gso in Hl ; auto.
          unfold successors_list in H.
          rewrite Hl in *. intuition.
        - (* error case *) inv H1.
      }
    * destruct H0. left.
      intro. elim H0. intuition.
      intuition.
Qed.
          
Context {A: Type}.
Variable code: PTree.t A.
Variable successors: A -> list positive.

Definition make_preds : PTree.t (list positive) :=
  make_predecessors code successors.

Lemma make_predecessors_correct2_aux :
  forall n i s,
    code ! n = Some i ->
    ~In s (successors i) ->
    ~In n make_preds!!!s.
Proof.
  intros until s. intros Hcode.
  set (P := fun (m:PTree.t A) preds =>
              ~In s (successors i) -> ~In n preds!!!s) in *.
  apply PTree_Properties.fold_rec with (P := P).
 extensionality *)  unfold P; intros.
  apply H0; auto.
 base case *)  red ; unfold successors_list. repeat rewrite PTree.gempty. auto.
 inductive case *)  unfold P; intros.
  eapply add_successors_correct2; eauto.
  destruct (peq n k).
  - inv e.
    left ; auto.
    rewrite Hcode in *. congruence.
  - auto.
Qed.

Lemma make_predecessors_correct2 :
  forall n i s,
    code ! n = Some i ->
    In n make_preds!!!s ->
    In s (successors i).
Proof.
  generalize make_predecessors_correct2_aux ; intro.
  intros.
  assert (Hdecpos:forall (p1 p2: positive), {p1 = p2}+{p1 <> p2}) by decide equality.
  assert (Hin := In_dec Hdecpos s (successors i)).
  destruct Hin; auto.
  exploit H ; eauto. intuition.
Qed.

Lemma make_predecessors_some : forall s l,
  make_preds ! s = Some l ->
  forall p, In p l -> exists i, code ! p = Some i.
Proof.
  unfold make_preds, make_predecessors.
  apply PTree_Properties.fold_rec; intros.
  - rewrite <- H. eapply H0; eauto.
  - rewrite PTree.gempty in H. inv H.
  - destruct (peq k p).
    * subst. rewrite PTree.gss. eauto.
    * rewrite PTree.gso; auto.
      destruct (classic (In p a !!! s \/ p = k /\ In s (successors v))).
      {
        destruct H4 as [Hcase1 | Hcase2].
        - unfold successors_list in *.
          case_eq (a ! s) ; intros.
          * rewrite H4 in *. eapply (H1 s); eauto.
          * rewrite H4 in *. inv Hcase1.
        - inv Hcase2. congruence.
      }
      {
        eelim add_successors_correct2 with (tolist := (successors v)); eauto.
        unfold successors_list. rewrite H2.
        auto.
      }
Qed.


Section make_preds_NoDup.

Lemma add_successors_complete : forall tolist from pred n s,
  In n (add_successors pred from tolist) !!! s ->
  In n pred !!! s \/ n = from /\ In s tolist.
Proof.
  intros tolist. induction tolist; intros.
  - simpl in H. left; assumption.
  - simpl in H. apply IHtolist in H.
    destruct H as [H | [H H0]].
    + unfold successors_list at 1 in H. rewrite PTree.gsspec in H.
      destruct (peq s a).
      * subst. destruct H.
        -- right. split; [|left]; congruence.
        -- left; assumption.
      * fold (pred !!! s) in H. left; assumption.
    + right. split; [|right]; congruence.
Qed.

Definition once {A : Type} eq_dec (x : A) l :=
  (count_occ eq_dec l x = 1)%nat.

Lemma add_successors_NoDup : forall preds from tos s,
  NoDup (preds !!! s) ->
  (In s tos -> ~ In from (preds !!! s) /\ once peq s tos) ->
  NoDup ((add_successors preds from tos) !!! s).
Proof.
  intros. revert dependent preds. induction tos; intros.
  - simpl. assumption.
  - simpl. apply IHtos.
    + unfold successors_list at 1. rewrite PTree.gsspec.
      destruct (peq s a).
      * subst. constructor; [|assumption]. apply H0. left; reflexivity.
      * fold (preds !!! s). assumption.
    + intros. destruct H0 as (H01 & H02); [right; assumption|].
      split.
      * unfold successors_list at 1. rewrite PTree.gso.
        -- fold (preds !!! s). assumption.
        -- intros contra. subst. unfold once in H02. simpl in H02.
           rewrite peq_true in H02. apply (count_occ_In peq) in H1. xomega.
      * unfold once in H02. unfold once. simpl in H02.
        destruct (peq a s).
        -- subst. apply (count_occ_In peq) in H1. xomega.
        -- xomega.
Qed.

Lemma make_preds_NoDup : forall s,
  (forall n i, code ! n = Some i -> In s (successors i) -> once peq s (successors i)) ->
  NoDup (make_preds !!! s).
Proof.
  intros s.
 we prove this statement that works better with induction *)  assert (
    ((forall n i, code ! n = Some i -> In s (successors i) -> once peq s (successors i)) ->
      NoDup (make_preds !!! s)
    ) /\ Forall (fun p => code ! p <> None) (make_preds !!! s)) as Ha.
  {
    unfold make_preds, make_predecessors.
    apply PTree_Properties.fold_rec.
    - intros. destruct H0 as (H01 & H02).
      split.
      + intros. apply H01. intros. rewrite H in H1.
        eapply H0; eassumption.
      + rewrite Forall_forall in H02 |- *. intros. rewrite <- H. auto.
    - unfold successors_list. rewrite PTree.gempty.
      split; constructor.
    - intros. destruct H1 as (H11 & H12).
      split.
      + intros. apply add_successors_NoDup.
        * apply H11. intros. apply (H1 n). rewrite PTree.gso by congruence.
          assumption. assumption.
        * intros. split.
          -- intros contra. rewrite Forall_forall in H12. apply H12 in contra.
             contradiction.
          -- apply (H1 k). rewrite PTree.gss. reflexivity. assumption.
      + rewrite Forall_forall. intros. apply add_successors_complete in H1.
        destruct H1 as [H1|[H2 H3]].
        * rewrite Forall_forall in H12. apply H12 in H1.
          rewrite PTree.gso by congruence. assumption.
        * subst. rewrite PTree.gss. discriminate.
  }
  apply Ha.
Qed.

End make_preds_NoDup.

End CORRECTNESS.

Section FOLD_EQ.

Section fold_eq.
  Variable A B: Type.
  Variable f: B -> positive -> A -> B.
  Variable b0: B.
  Variable m1 m2: PTree.t A.
  Variable Heq: forall i, m1!i = m2!i.

  Lemma fold_eq: PTree.fold f m1 b0 = PTree.fold f m2 b0.
Proof.
    repeat rewrite PTree.fold_spec.
    rewrite (PTree.elements_extensional _ _ Heq); auto.
  Qed.

End fold_eq.

End FOLD_EQ.

Section Pred_Succs.

Lemma same_successors_same_predecessors_aux0 {A B} :
  forall f1 (f2:B->list positive) (m1:PTree.t A) t a,
 (forall i, m1! i = None) ->
  PTree.xfold
    (fun pred pc instr => add_successors pred pc (f1 instr)) a m1 t = t.
Proof.
  induction m1; simpl; auto.
  intros a t T.
  generalize (T xH); destruct o; simpl; try congruence.
  intros _.
  rewrite IHm1_2.
  - rewrite IHm1_1; auto.
    intros i; generalize (T (xO i)); auto.
  - intros i; generalize (T (xI i)); auto.
Qed.

Lemma same_successors_same_predecessors_aux1 {A B} :
  forall f1 f2 (m1:PTree.t A) (m2:PTree.t B) t a,
 (forall i,
    (PTree.map1 f1 m1) ! i =
    (PTree.map1 f2 m2) ! i) ->
  PTree.xfold
    (fun pred pc instr => add_successors pred pc (f1 instr)) a m1 t =
  PTree.xfold
    (fun pred pc instr => add_successors pred pc (f2 instr)) a m2 t.
Proof.
  induction m1; simpl; auto; intros.
  - erewrite same_successors_same_predecessors_aux0; eauto.
    intros i; generalize (H i); simpl.
    rewrite PTree.gmap1.
    destruct (m2!i); simpl; auto.
    destruct i; simpl; congruence.
  - destruct m2.
    + erewrite same_successors_same_predecessors_aux0; eauto.
      erewrite same_successors_same_predecessors_aux0; eauto.
      erewrite same_successors_same_predecessors_aux0; eauto.
      generalize (H xH); destruct o; simpl; try congruence.
      destruct i; auto.
      intros i; generalize (H (xI i)); simpl.
      rewrite PTree.gmap1.
      destruct (m1_2!i); simpl; congruence.
      intros i; generalize (H (xO i)); simpl.
      rewrite PTree.gmap1.
      destruct (m1_1!i); simpl; congruence.
    + rewrite IHm1_1 with (m2:=m2_1); eauto.
      rewrite IHm1_2 with (m2:=m2_2); eauto.
      generalize (H xH).
      simpl.
      destruct o; destruct o0; simpl; try congruence.
      intros T; inv T.
      rewrite IHm1_2 with (m2:=m2_2); eauto.
      intros i; generalize (H (xI i)); simpl; auto.
      intros i; generalize (H (xI i)); simpl; auto.
      intros i; generalize (H (xO i)); simpl; auto.
Qed.

Lemma same_successors_same_predecessors {A B} : forall f1 f2 (m1:PTree.t A) (m2:PTree.t B),
 (forall i,
    (PTree.map1 f1 m1) ! i =
    (PTree.map1 f2 m2) ! i) ->
  make_predecessors m1 f1 = make_predecessors m2 f2.
Proof.
  unfold make_predecessors; intros.
  apply same_successors_same_predecessors_aux1; auto.
Qed.

End Pred_Succs.