Module PointsTo


Require Cells.
Import
  Utf8
  Coqlib
  Maps
  Globalenvs
  AST
  Integers
  Values
  Cminor
  Csharpminorannot
  Util
  ToString
  ShareTree
  AdomLib
  AssocList
  Sets
  PExpr
  Cells.

Set Implicit Arguments.
Unset Elimination Schemes.

Definition PTSet : Type := BlockSet.t +⊤.

Instance ptset_gamma ge stk : gamma_op BlockSet.t block :=
  λ s b,
  ∃ ab, BlockSet.mem ab sblock_of_ablock ge stk ab = Some b.

Instance ptset_leb : leb_op BlockSet.t := BSO.Sleb.

Instance ptset_leb_correct (ge:genv) (stk:list (temp_env * env)) :
  leb_op_correct BlockSet.t block (G:=ptset_gamma ge stk).
Proof.
  intros x y H b X.
  destruct X as (ab & IN & AB). exists ab. intuition.
  eapply BlockSet.le_spec; eauto.
Qed.

Instance ptset_join : join_op BlockSet.t _ := BSO.Sjoin.

Instance ptset_join_correct (ge:genv) (stk:list (temp_env * env)) :
  join_op_correct BlockSet.t BlockSet.t block (GA:=ptset_gamma ge stk) (GB:=ptset_gamma ge stk).
Proof.
  intros x y b H.
  destruct H as [(ab & IN & AB)|(ab & IN & AB)]; exists ab; intuition;
  rewrite BlockSet.mem_union; apply orb_true_intro; rewrite IN; auto.
Qed.

Inductive type : Type :=
| TyFloat | TySingle | TyLong
| TyZero | TyInt
| TyPtr `(PTSet)
| TyZPtr `(PTSet)
| TyIntPtr.

Definition type_of_int (i: int) : type :=
  if Int.eq Int.zero i
  then TyZero
  else TyInt.

Section TO_STRING.
Context {F V} (ge: Genv.t F V).

Local Instance string_of_ablock : ToString ablock :=
  AblockToString ge.

Instance string_of_type : ToString type :=
  λ ty,
  match ty with
  | TyFloat => "float"
  | TySingle => "single"
  | TyLong => "long"
  | TyZero => "null"
  | TyInt => "int"
  | TyPtr bs => "ptr(" ++ to_string bs ++ ")"
  | TyZPtr bs => "null-ptr(" ++ to_string bs ++ ")"
  | TyIntPtr => "int-or-ptr"
  end.

End TO_STRING.

Instance type_leb : leb_op type :=
  λ x x',
  match x, x' with
  | TyFloat, TyFloat
  | TySingle, TySingle
  | TyLong, TyLong
    => true
  | TyFloat, _ | _, TyFloat
  | TySingle, _ | _, TySingle
  | TyLong, _ | _, TyLong
    => false
  | TyZero, (TyZero | TyInt | TyZPtr _ | TyIntPtr) => true
  | TyZero, TyPtr _ => false
  | TyInt, (TyInt | TyIntPtr) => true
  | TyInt, (TyZero | TyPtr _ | TyZPtr _) => false
  | TyPtr b, (TyPtr b' | TyZPtr b')
  | TyZPtr b, (TyZPtr b') => bb'
  | (TyPtr _ | TyZPtr _), TyIntPtr => true
  | TyPtr _, (TyZero | TyInt) => false
  | TyZPtr _, (TyZero | TyInt | TyPtr _) => false
  | TyIntPtr, TyIntPtr => true
  | TyIntPtr, (TyZero | TyInt | TyPtr _ | TyZPtr _) => false
  end.

Instance type_join : join_op type (type+⊤) :=
  λ x x',
  match x, x' with
  | TyFloat, TyFloat
  | TySingle, TySingle
  | TyLong, TyLong
  | TyZero, TyZero
  | TyInt, TyInt
  | TyIntPtr, TyIntPtr
    => ret x
  | TyFloat, _ | _, TyFloat
  | TySingle, _ | _, TySingle
  | TyLong, _ | _, TyLong
    => ⊤
  | (TyZero | TyInt), TyIntPtr
  | TyZero, TyInt
    => ret x'
  | (TyInt | TyIntPtr), TyZero
  | TyIntPtr, TyInt
    => ret x
  | (TyPtr b | TyZPtr b), TyZero
  | TyZero, (TyPtr b | TyZPtr b) => ret (TyZPtr b)
  | (TyPtr _ | TyZPtr _), (TyInt | TyIntPtr)
  | (TyInt | TyIntPtr), (TyPtr _ | TyZPtr _) => ret TyIntPtr
  | TyPtr b, TyPtr b' => ret (TyPtr (bb'))
  | TyZPtr b, TyPtr b'
  | TyPtr b, TyZPtr b'
  | TyZPtr b, TyZPtr b'
    => ret (TyZPtr (bb'))
  end.

Instance type_gamma (G: gamma_op BlockSet.t block) : gamma_op type val :=
  λ x v,
  match x, v with
  | TyFloat, Vfloat _
  | TySingle, Vsingle _
  | TyLong, Vlong _
  | TyInt, Vint _
  | TyIntPtr, (Vint _ | Vptr _ _)
    => True

  | TyZero, Vint n => Int.eq Int.zero n
  | TyPtr bs, Vptr b _
  | TyZPtr bs, Vptr b _
    => b ∈ γ bs
  | TyZPtr _, Vint n => Int.eq Int.zero n

  | TyFloat, _
  | TySingle, _
  | TyLong, _
  | TyZero, _
  | TyInt, _
  | TyPtr _, _
  | TyZPtr _, _
  | TyIntPtr, _
    => False
  end.

Lemma type_gamma_inv G x v :
  type_gamma G x v
  match x with
  | TyFloat => ∃ f, v = Vfloat f
  | TySingle => ∃ s, v = Vsingle s
  | TyLong => ∃ i, v = Vlong i
  | TyZero => v = Vint Int.zero
  | TyInt => ∃ i, v = Vint i
  | TyPtr bs => ∃ b i, v = Vptr b ib ∈ γ bs
  | TyZPtr bs => (v = Vint Int.zero) ∨ (∃ b i, v = Vptr b ib ∈ γ bs)
  | TyIntPtr => (∃ i, v = Vint i) ∨ (∃ b i, v = Vptr b i)
  end.
Proof.
  destruct x, v; ((intros (); vauto; fail) || (simpl; vauto; fail) || idtac).
  exactK, f_equal Vint (eq_sym (int_eq _ _ K))).
  exactK, or_introl _ (f_equal Vint (eq_sym (int_eq _ _ K)))).
Qed.

Lemma type_gamma_inv' G x v :
  type_gamma G x v
  match v with
  | Vfloat _ => x = TyFloat
  | Vsingle _ => x = TySingle
  | Vlong _ => x = TyLong
  | Vptr b _ => (∃ bs, b ∈ γ bs ∧ (x = TyPtr bsx = TyZPtr bs)) ∨ (x = TyIntPtr)
  | Vint n => (n = Int.zero ∧ (x = TyZero ∨ ∃ bs, x = TyZPtr bs)) ∨ (x = TyInt) ∨ (x = TyIntPtr)
  | Vundef => False
  end.
Proof.
  destruct x, v; try (simpl; easy); vauto.
  intros K; left. split. symmetry; apply (int_eq _ _ K). vauto.
  intros K; left. split. symmetry; apply (int_eq _ _ K). vauto.
Qed.

Lemma toplift_gamma_def G x v :
  toplift_gamma (type_gamma G) x v
  x = All
  match v with Vundef => True | _ => ∃ ty, x = Just tyvtype_gamma G ty end.
Proof.
  destruct x, v; vauto.
Qed.

Instance type_leb_correct (G: gamma_op BlockSet.t block) (BS: leb_op_correct BlockSet.t block) :
  @leb_op_correct _ _ type_leb (type_gamma G).
Proof.
  intros x x'; destruct x, x'; intros LE;
  exactx, id) || exact (false_not_true LE _) || idtac;
  intros v; destruct v;
  exact id || exact_, I) || exact (False_ind _) || idtac;
  repeat match goal with pt: PTSet |- _ => destruct pt as [ | pt ] end;
  exact id || exact_, I) || exact (false_not_true LE _) || idtac;
  apply BS, LE.
Qed.

Instance type_join_correct (G: gamma_op BlockSet.t block) (BS: join_op_correct BlockSet.t _ block) :
  @join_op_correct _ _ _ type_join (type_gamma G) _.
Proof.
  intros x x' v H; destruct x, x';
  exact I || (elim H; exact id) || idtac;
  destruct v;
  exact I || (elim H; exact id) || idtac;
  try (elim H; clear H;
  (intros (); fail) || exact id);
  repeat match goal with pt: PTSet |- _ => destruct pt as [ | pt ] end;
  try exact I;
  apply BS, H.
Qed.

Module PT ( T : SHARETREE ).

Module ACTreeDom := WPFun T.

Definition points_to : Type := ACTreeDom.t type.

Definition points_to_get (pt: points_to) (c: T.elt) : type+⊤ :=
  ACTreeDom.get c pt.
Coercion points_to_get : points_to >-> Funclass.

Instance points_to_leb : leb_op points_to :=
  ACTreeDom.leb_tree _ _.
Proof.
  abstract (
  intros (); try reflexivity;
  intros (); try reflexivity;
  intros x;
  apply BlockSet.le_spec;
  intros y; exact id
    ).
Defined.

Instance points_to_join : join_op points_to points_to :=
  ACTreeDom.join_tree _ _.
Proof.
  abstract now
  intros (); try reflexivity;
  intros (); try reflexivity;
  intros x; unfold join; simpl;
  unfold join; simpl; repeat apply f_equal;
  apply (f_equal (@Just _));
  unfold join, ptset_join, BSO.Sjoin, BlockSet.union;
  rewrite ABTree.shcombine_eq.
Defined.

Definition points_to_widen : points_topoints_topoints_to := join.

Instance points_to_gamma ge stk : gamma_op points_to (T.eltval) :=
  ACTreeDom.gamma_tree (type_gamma (ptset_gamma ge stk)).

Instance points_to_leb_correct ge stk :
  @leb_op_correct _ _ points_to_leb (points_to_gamma ge stk).
Proof.
  apply ACTreeDom.leb_tree_correct, type_leb_correct, ptset_leb_correct.
Qed.

Instance points_to_join_correct ge stk :
  @join_op_correct _ _ _ points_to_join (points_to_gamma ge stk) (points_to_gamma ge stk).
Proof.
  apply ACTreeDom.join_tree_correct, type_join_correct, ptset_join_correct.
Qed.

Section PT_EVAL.

Context (ge: genv) (μ: fname) (pt: points_to).
Fixpoint pt_eval_pexpr (pe: pexpr T.elt) : type+⊤ :=
  match pe with
  | PEvar x _ => ACTreeDom.get x pt
  | PElocal s => Just (TyPtr (Just (BSO.singleton (ABlocal μ s))))
  | PEconst (Ointconst i) _ _ => Just (type_of_int i)
  | PEconst (Ofloatconst _) _ _ => Just TyFloat
  | PEconst (Osingleconst _) _ _ => Just TySingle
  | PEconst (Olongconst _) _ _ => Just TyLong
  | PEconst (Oaddrsymbol s _) _ _ =>
    Just (TyPtr
    match Genv.find_symbol ge s with
    | Some b => Just (BSO.singleton (ABglobal b))
    | None => All
    end)

  | PEunop op pe' _ _ =>
    Just
    match op with
    | Ocast8unsigned
    | Ocast8signed
    | Ocast16unsigned
    | Ocast16signed
      =>
      match pt_eval_pexpr pe' with
      | Just TyZero => TyZero
      | _ => TyInt
      end
    | Onegint | Onotint | Ointoffloat | Ointuoffloat | Ointofsingle | Ointuofsingle | Ointoflong => TyInt
    | Onegf | Oabsf | Ofloatofsingle | Ofloatofint | Ofloatofintu | Ofloatoflong | Ofloatoflongu => TyFloat
    | Onegfs | Oabsfs | Osingleoffloat | Osingleofint | Osingleofintu | Osingleoflong | Osingleoflongu => TySingle
    | Onegl | Onotl | Olongofint | Olongofintu | Olongoffloat | Olonguoffloat | Olongofsingle | Olonguofsingle => TyLong
    end

  | PEbinop op x y _ _ =>
    match op with
    | Oadd =>
      do p <- pt_eval_pexpr x;
      do q <- pt_eval_pexpr y;
      Just
      match p, q with
      | TyFloat, _ | _, TyFloat
      | TySingle, _ | _, TySingle
      | TyLong, _ | _, TyLong
        => TyZero
      | TyZero, k | k, TyZero => k
      | TyInt, TyZPtr _ | TyZPtr _, TyInt => TyIntPtr
      | TyInt, k | k, TyInt => k
      | TyPtr _, TyPtr _ => TyZero
      | TyPtr _ as k, (TyZPtr _ | TyIntPtr) | (TyZPtr _ | TyIntPtr), TyPtr _ as k => k
      | TyZPtr bs, TyZPtr bs' => TyZPtr (bsbs')
      | TyIntPtr, TyIntPtr
      | TyIntPtr, TyZPtr _
      | TyZPtr _, TyIntPtr => TyIntPtr
      end

    | Osub =>
      do p <- pt_eval_pexpr x;
      do q <- pt_eval_pexpr y;
      Just
      match p, q with
      | TyFloat, _ | _, TyFloat
      | TySingle, _ | _, TySingle
      | TyLong, _ | _, TyLong
        => TyZero
      | TyZero, k | k, TyZero => k
      | TyInt, _
      | TyPtr _, TyPtr _
      | TyZPtr _, TyPtr _ => TyInt
      | (TyPtr _ | TyIntPtr), TyInt => p
      | TyPtr _, (TyZPtr _ | TyIntPtr)
      | TyZPtr _, (TyInt | TyZPtr _ | TyIntPtr)
      | TyIntPtr, _
        => TyIntPtr
      end

    | Omul
    | Odiv | Odivu | Omod | Omodu
    | Oand | Oor | Oxor | Oshl | Oshr | Oshru
    | Ocmp _
    | Ocmpu _
      => Just TyInt
    | Oaddf | Osubf | Omulf | Odivf => Just TyFloat
    | Oaddfs | Osubfs | Omulfs | Odivfs => Just TySingle
    | Oaddl | Osubl | Omull | Odivl | Odivlu | Omodl | Omodlu
    | Oandl | Oorl | Oxorl | Oshll | Oshrl | Oshrlu => Just TyLong
    | Ocmpf _ | Ocmpfs _ | Ocmpl _ | Ocmplu _ => Just TyInt
    end
  end.

Definition env_as_fun : envidentoption block :=
  λ e i, match e ! i with Some (b, _) => Some b | _ => None end.
Coercion env_as_fun : env >-> Funclass.

Lemma int_eq_intro (P: boolProp) :
  ∀ x y,
    (x = yP true) →
    (xyP false) →
    P (Int.eq x y).
Proof.
  intros x y EQ NE.
  generalize (Int.eq_spec x y).
  now case Int.eq.
Qed.

Context (m: Memory.mem) (stk: list (temp_env * env)) (ρ: T.eltval) (ε: env) (tmp: temp_env).
Local Instance __ptset_gamma : gamma_op BlockSet.t block := ptset_gamma ge ((tmp, ε) :: stk).
Local Instance __ptset_join_correct : join_op_correct BlockSet.t BlockSet.t block := @ptset_join_correct ge ((tmp, ε) :: stk).

Lemma pt_eval_pexpr_correct
      (Hstk: μ = plength stk)
      (PT: ρ ∈ points_to_gamma ge ((tmp, ε) :: stk) pt) :
  ∀ pe v,
    veval_pexpr ge m ρ ε pe
    match v with Vundef => False | _ => True end
    vtoplift_gamma (type_gamma __ptset_gamma) (pt_eval_pexpr pe).
Proof.
  intros pe; elim pe; clear pe.
  - intros x t v EV DEF. eval_pexpr_inv. hsplit.
    generalize (PT x). rewrite EV. exact id.
  - intros i v EV DEF. eval_pexpr_inv. subst v.
    eexists. split. apply BSO.mem_singleton. reflexivity. simpl.
    rewrite Hstk, get_stk_length. exact EV.
  - intros (); simpl; intros; eval_pexpr_inv; hsplit; subst;
    try exact I.
    unfold type_of_int. apply int_eq_intro. intros <-. reflexivity.
    intros _. exact I.
    simpl in *. destruct (Genv.find_symbol ge _) as [ b | ] eqn: Hb. 2: assumption.
    eexists. split. apply BSO.mem_singleton. reflexivity.
    now simpl; rewrite (Genv.find_invert_symbol ge _ Hb).
  - intros op pe IH ty Hty v EV DEF.
    apply eval_pexpr_unop_inv in EV. destruct EV as (v' & Hv' & Hv & K).
    destruct K as [ K | TY ]. subst v; elim DEF.
    now
    destruct op; simpl in Hty; subst ty;
    apply gamma_typ_inv in TY;
    hsplit; subst v;
    try exact I;
    simpl in *; eq_some_inv;
    destruct v'; try discriminate;
    simpl in *; inversion Hv; clear Hv; subst i;
    specialize (IH _ Hv' I);
    (apply toplift_gamma_def in IH; destruct IH as [ -> | (ty & Hty & TY) ];
     [ exact I | ]);
    apply type_gamma_inv' in TY;
    repeat match goal with X : __ |- _ => destruct X as [ X | X ]; hsplit | H : ?a = ?b |- _ => subst b || subst a end;
    rewrite Hty.

  - intros op pe1 IH1 pe2 IH2 ty Hty v EV DEF.
    apply eval_pexpr_binop_inv in EV.
    destruct EV as (v1 & v2 & Hv1 & Hv2 & EV & [ K | TY ]).
    rewrite K in DEF. elim DEF.
    destruct op;
      try exact I;
      try (
      simpl in *; subst ty;
      apply gamma_typ_inv in TY;
      hsplit; subst v;
      try exact I;
      idtac);
    simpl in *; eq_some_inv; subst v;
    specialize (IH1 _ Hv1); specialize (IH2 _ Hv2);
    destruct v1; try (elim DEF; fail); specialize (IH1 I);
    destruct v2; try (elim DEF; fail); specialize (IH2 I);
    clear DEF;
    (destruct (pt_eval_pexpr pe1) as [ | ty1 ]; [ exact I | ]);
    apply type_gamma_inv in IH1;
    destruct ty1;
    hsplit; try discriminate;
    repeat match goal with H : __ |- _ => destruct H as [ H | H ]; hsplit | H : Vint _ = _ |- _ => inversion H; clear H | H : ?a = ?b |- _ => subst b || subst a end;
    (destruct (pt_eval_pexpr pe2) as [ | ty2 ]; [ exact I | ]);
    apply type_gamma_inv in IH2;
    destruct ty2;
    hsplit; try discriminate;
    repeat match goal with H : __ |- _ => destruct H as [ H | H ]; hsplit | H : Vint _ = _ |- _ => inversion H; clear H | H : Vptr _ _ = _ |- _ => inversion H; clear H | H : ?a = ?b |- _ => subst b || subst a end;
    exact I || exact eq_refl || assumption || simpl.
    eapply join_correct; right; assumption.
    eapply join_correct; left; assumption.
    simpl in *. destruct eq_block; auto. exact (gamma_typ_inv' _ _ TY).
    simpl in *. destruct eq_block; auto. exact (gamma_typ_inv' _ _ TY).
    simpl in *. destruct eq_block; auto. exact (gamma_typ_inv' _ _ TY).
    simpl in *. destruct eq_block; auto. exact (gamma_typ_inv' _ _ TY).
    simpl in *. destruct eq_block; auto. exact (gamma_typ_inv' _ _ TY).
    simpl in *. destruct eq_block; auto. exact (gamma_typ_inv' _ _ TY).
    simpl in *. destruct eq_block; auto. exact (gamma_typ_inv' _ _ TY).
    simpl in *. destruct eq_block; auto. exact (gamma_typ_inv' _ _ TY).
    simpl in *. destruct eq_block; auto. exact (gamma_typ_inv' _ _ TY).
Qed.

End PT_EVAL.

End PT.