summaryrefslogtreecommitdiff
path: root/backend/NeedDomain.v
diff options
context:
space:
mode:
Diffstat (limited to 'backend/NeedDomain.v')
-rw-r--r--backend/NeedDomain.v1515
1 files changed, 1515 insertions, 0 deletions
diff --git a/backend/NeedDomain.v b/backend/NeedDomain.v
new file mode 100644
index 0000000..568c80e
--- /dev/null
+++ b/backend/NeedDomain.v
@@ -0,0 +1,1515 @@
+(* *********************************************************************)
+(* *)
+(* The Compcert verified compiler *)
+(* *)
+(* 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 INRIA Non-Commercial License Agreement. *)
+(* *)
+(* *********************************************************************)
+
+(** Abstract domain for neededness analysis *)
+
+Require Import Coqlib.
+Require Import Maps.
+Require Import IntvSets.
+Require Import AST.
+Require Import Integers.
+Require Import Floats.
+Require Import Values.
+Require Import Memory.
+Require Import Globalenvs.
+Require Import Events.
+Require Import Lattice.
+Require Import Registers.
+Require Import ValueDomain.
+Require Import Op.
+Require Import RTL.
+
+(** * Neededness for values *)
+
+Inductive nval : Type :=
+ | Nothing (**r value is entirely unused *)
+ | I (m: int) (**r only need the bits that are 1 in [m] *)
+ | Fsingle (**r only need the value after conversion to single float *)
+ | All. (**r every bit of the value is used *)
+
+Definition eq_nval (x y: nval) : {x=y} + {x<>y}.
+Proof.
+ decide equality. apply Int.eq_dec.
+Defined.
+
+(** ** Agreement between two values relative to a need. *)
+
+Definition iagree (p q mask: int) : Prop :=
+ forall i, 0 <= i < Int.zwordsize -> Int.testbit mask i = true ->
+ Int.testbit p i = Int.testbit q i.
+
+Fixpoint vagree (v w: val) (x: nval) {struct x}: Prop :=
+ match x with
+ | Nothing => True
+ | I m =>
+ match v, w with
+ | Vint p, Vint q => iagree p q m
+ | Vint p, _ => False
+ | _, _ => True
+ end
+ | Fsingle =>
+ match v, w with
+ | Vfloat f, Vfloat g => Float.singleoffloat f = Float.singleoffloat g
+ | Vfloat _, _ => False
+ | _, _ => True
+ end
+ | All => Val.lessdef v w
+ end.
+
+Lemma vagree_same: forall v x, vagree v v x.
+Proof.
+ intros. destruct x; simpl; auto; destruct v; auto. red; auto.
+Qed.
+
+Lemma vagree_lessdef: forall v w x, Val.lessdef v w -> vagree v w x.
+Proof.
+ intros. inv H. apply vagree_same. destruct x; simpl; auto.
+Qed.
+
+Lemma lessdef_vagree: forall v w, vagree v w All -> Val.lessdef v w.
+Proof.
+ intros. simpl in H. auto.
+Qed.
+
+Hint Resolve vagree_same vagree_lessdef lessdef_vagree: na.
+
+Definition vagree_list (vl1 vl2: list val) (nv: nval) : Prop :=
+ list_forall2 (fun v1 v2 => vagree v1 v2 nv) vl1 vl2.
+
+Lemma lessdef_vagree_list:
+ forall vl1 vl2, vagree_list vl1 vl2 All -> Val.lessdef_list vl1 vl2.
+Proof.
+ induction 1; constructor; auto with na.
+Qed.
+
+Lemma vagree_lessdef_list:
+ forall x vl1 vl2, Val.lessdef_list vl1 vl2 -> vagree_list vl1 vl2 x.
+Proof.
+ induction 1; constructor; auto with na.
+Qed.
+
+Hint Resolve lessdef_vagree_list vagree_lessdef_list: na.
+
+(** ** Ordering and least upper bound between value needs *)
+
+Inductive nge: nval -> nval -> Prop :=
+ | nge_nothing: forall x, nge All x
+ | nge_all: forall x, nge x Nothing
+ | nge_int: forall m1 m2,
+ (forall i, 0 <= i < Int.zwordsize -> Int.testbit m2 i = true -> Int.testbit m1 i = true) ->
+ nge (I m1) (I m2)
+ | nge_single:
+ nge Fsingle Fsingle.
+
+Lemma nge_refl: forall x, nge x x.
+Proof.
+ destruct x; constructor; auto.
+Qed.
+
+Hint Constructors nge: na.
+Hint Resolve nge_refl: na.
+
+Lemma nge_trans: forall x y, nge x y -> forall z, nge y z -> nge x z.
+Proof.
+ induction 1; intros w VG; inv VG; eauto with na.
+Qed.
+
+Lemma nge_agree:
+ forall v w x y, nge x y -> vagree v w x -> vagree v w y.
+Proof.
+ induction 1; simpl; auto.
+- destruct v; auto with na.
+- destruct v, w; intuition. red; auto.
+Qed.
+
+Definition nlub (x y: nval) : nval :=
+ match x, y with
+ | Nothing, _ => y
+ | _, Nothing => x
+ | I m1, I m2 => I (Int.or m1 m2)
+ | Fsingle, Fsingle => Fsingle
+ | _, _ => All
+ end.
+
+Lemma nge_lub_l:
+ forall x y, nge (nlub x y) x.
+Proof.
+ unfold nlub; destruct x, y; auto with na.
+ constructor. intros. autorewrite with ints; auto. rewrite H0; auto.
+Qed.
+
+Lemma nge_lub_r:
+ forall x y, nge (nlub x y) y.
+Proof.
+ unfold nlub; destruct x, y; auto with na.
+ constructor. intros. autorewrite with ints; auto. rewrite H0. apply orb_true_r; auto.
+Qed.
+
+(** ** Properties of agreement between integers *)
+
+Lemma iagree_refl:
+ forall p m, iagree p p m.
+Proof.
+ intros; red; auto.
+Qed.
+
+Remark eq_same_bits:
+ forall i x y, x = y -> Int.testbit x i = Int.testbit y i.
+Proof.
+ intros; congruence.
+Qed.
+
+Lemma iagree_and_eq:
+ forall x y mask,
+ iagree x y mask <-> Int.and x mask = Int.and y mask.
+Proof.
+ intros; split; intros.
+- Int.bit_solve. specialize (H i H0).
+ destruct (Int.testbit mask i).
+ rewrite ! andb_true_r; auto.
+ rewrite ! andb_false_r; auto.
+- red; intros. exploit (eq_same_bits i); eauto; autorewrite with ints; auto.
+ rewrite H1. rewrite ! andb_true_r; auto.
+Qed.
+
+Lemma iagree_mone:
+ forall p q, iagree p q Int.mone -> p = q.
+Proof.
+ intros. rewrite iagree_and_eq in H. rewrite ! Int.and_mone in H. auto.
+Qed.
+
+Lemma iagree_zero:
+ forall p q, iagree p q Int.zero.
+Proof.
+ intros. rewrite iagree_and_eq. rewrite ! Int.and_zero; auto.
+Qed.
+
+Lemma iagree_and:
+ forall x y n m,
+ iagree x y (Int.and m n) -> iagree (Int.and x n) (Int.and y n) m.
+Proof.
+ intros. rewrite iagree_and_eq in *. rewrite ! Int.and_assoc.
+ rewrite (Int.and_commut n). auto.
+Qed.
+
+Lemma iagree_not:
+ forall x y m, iagree x y m -> iagree (Int.not x) (Int.not y) m.
+Proof.
+ intros; red; intros; autorewrite with ints; auto. f_equal; auto.
+Qed.
+
+Lemma iagree_not':
+ forall x y m, iagree (Int.not x) (Int.not y) m -> iagree x y m.
+Proof.
+ intros. rewrite <- (Int.not_involutive x). rewrite <- (Int.not_involutive y).
+ apply iagree_not; auto.
+Qed.
+
+Lemma iagree_or:
+ forall x y n m,
+ iagree x y (Int.and m (Int.not n)) -> iagree (Int.or x n) (Int.or y n) m.
+Proof.
+ intros. apply iagree_not'. rewrite ! Int.not_or_and_not. apply iagree_and.
+ apply iagree_not; auto.
+Qed.
+
+Lemma iagree_bitwise_binop:
+ forall sem f,
+ (forall x y i, 0 <= i < Int.zwordsize ->
+ Int.testbit (f x y) i = sem (Int.testbit x i) (Int.testbit y i)) ->
+ forall x1 x2 y1 y2 m,
+ iagree x1 y1 m -> iagree x2 y2 m -> iagree (f x1 x2) (f y1 y2) m.
+Proof.
+ intros; red; intros. rewrite ! H by auto. f_equal; auto.
+Qed.
+
+Lemma iagree_shl:
+ forall x y m n,
+ iagree x y (Int.shru m n) -> iagree (Int.shl x n) (Int.shl y n) m.
+Proof.
+ intros; red; intros. autorewrite with ints; auto.
+ destruct (zlt i (Int.unsigned n)).
+- auto.
+- generalize (Int.unsigned_range n); intros.
+ apply H. omega. rewrite Int.bits_shru by omega.
+ replace (i - Int.unsigned n + Int.unsigned n) with i by omega.
+ rewrite zlt_true by omega. auto.
+Qed.
+
+Lemma iagree_shru:
+ forall x y m n,
+ iagree x y (Int.shl m n) -> iagree (Int.shru x n) (Int.shru y n) m.
+Proof.
+ intros; red; intros. autorewrite with ints; auto.
+ destruct (zlt (i + Int.unsigned n) Int.zwordsize).
+- generalize (Int.unsigned_range n); intros.
+ apply H. omega. rewrite Int.bits_shl by omega.
+ replace (i + Int.unsigned n - Int.unsigned n) with i by omega.
+ rewrite zlt_false by omega. auto.
+- auto.
+Qed.
+
+Lemma iagree_shr_1:
+ forall x y m n,
+ Int.shru (Int.shl m n) n = m ->
+ iagree x y (Int.shl m n) -> iagree (Int.shr x n) (Int.shr y n) m.
+Proof.
+ intros; red; intros. rewrite <- H in H2. rewrite Int.bits_shru in H2 by auto.
+ rewrite ! Int.bits_shr by auto.
+ destruct (zlt (i + Int.unsigned n) Int.zwordsize).
+- apply H0; auto. generalize (Int.unsigned_range n); omega.
+- discriminate.
+Qed.
+
+Lemma iagree_shr:
+ forall x y m n,
+ iagree x y (Int.or (Int.shl m n) (Int.repr Int.min_signed)) ->
+ iagree (Int.shr x n) (Int.shr y n) m.
+Proof.
+ intros; red; intros. rewrite ! Int.bits_shr by auto.
+ generalize (Int.unsigned_range n); intros.
+ set (j := if zlt (i + Int.unsigned n) Int.zwordsize
+ then i + Int.unsigned n
+ else Int.zwordsize - 1).
+ assert (0 <= j < Int.zwordsize).
+ { unfold j; destruct (zlt (i + Int.unsigned n) Int.zwordsize); omega. }
+ apply H; auto. autorewrite with ints; auto. apply orb_true_intro.
+ unfold j; destruct (zlt (i + Int.unsigned n) Int.zwordsize).
+- left. rewrite zlt_false by omega.
+ replace (i + Int.unsigned n - Int.unsigned n) with i by omega.
+ auto.
+- right. reflexivity.
+Qed.
+
+Lemma iagree_rol:
+ forall p q m amount,
+ iagree p q (Int.ror m amount) ->
+ iagree (Int.rol p amount) (Int.rol q amount) m.
+Proof.
+ intros. assert (Int.zwordsize > 0) by (compute; auto).
+ red; intros. rewrite ! Int.bits_rol by auto. apply H.
+ apply Z_mod_lt; auto.
+ rewrite Int.bits_ror.
+ replace (((i - Int.unsigned amount) mod Int.zwordsize + Int.unsigned amount)
+ mod Int.zwordsize) with i. auto.
+ apply Int.eqmod_small_eq with Int.zwordsize; auto.
+ apply Int.eqmod_trans with ((i - Int.unsigned amount) + Int.unsigned amount).
+ apply Int.eqmod_refl2; omega.
+ eapply Int.eqmod_trans. 2: apply Int.eqmod_mod; auto.
+ apply Int.eqmod_add.
+ apply Int.eqmod_mod; auto.
+ apply Int.eqmod_refl.
+ apply Z_mod_lt; auto.
+ apply Z_mod_lt; auto.
+Qed.
+
+Lemma iagree_ror:
+ forall p q m amount,
+ iagree p q (Int.rol m amount) ->
+ iagree (Int.ror p amount) (Int.ror q amount) m.
+Proof.
+ intros. rewrite ! Int.ror_rol_neg by apply int_wordsize_divides_modulus.
+ apply iagree_rol.
+ rewrite Int.ror_rol_neg by apply int_wordsize_divides_modulus.
+ rewrite Int.neg_involutive; auto.
+Qed.
+
+Lemma eqmod_iagree:
+ forall m x y,
+ Int.eqmod (two_p (Int.size m)) x y ->
+ iagree (Int.repr x) (Int.repr y) m.
+Proof.
+ intros. set (p := nat_of_Z (Int.size m)).
+ generalize (Int.size_range m); intros RANGE.
+ assert (EQ: Int.size m = Z_of_nat p). { symmetry; apply nat_of_Z_eq. omega. }
+ rewrite EQ in H; rewrite <- two_power_nat_two_p in H.
+ red; intros. rewrite ! Int.testbit_repr by auto.
+ destruct (zlt i (Int.size m)).
+ eapply Int.same_bits_eqmod; eauto. omega.
+ assert (Int.testbit m i = false) by (eapply Int.bits_size_2; omega).
+ congruence.
+Qed.
+
+Definition complete_mask (m: int) := Int.zero_ext (Int.size m) Int.mone.
+
+Lemma iagree_eqmod:
+ forall x y m,
+ iagree x y (complete_mask m) ->
+ Int.eqmod (two_p (Int.size m)) (Int.unsigned x) (Int.unsigned y).
+Proof.
+ intros. set (p := nat_of_Z (Int.size m)).
+ generalize (Int.size_range m); intros RANGE.
+ assert (EQ: Int.size m = Z_of_nat p). { symmetry; apply nat_of_Z_eq. omega. }
+ rewrite EQ; rewrite <- two_power_nat_two_p.
+ apply Int.eqmod_same_bits. intros. apply H. omega.
+ unfold complete_mask. rewrite Int.bits_zero_ext by omega.
+ rewrite zlt_true by omega. rewrite Int.bits_mone by omega. auto.
+Qed.
+
+Lemma complete_mask_idem:
+ forall m, complete_mask (complete_mask m) = complete_mask m.
+Proof.
+ unfold complete_mask; intros. destruct (Int.eq_dec m Int.zero).
++ subst m; reflexivity.
++ assert (Int.unsigned m <> 0).
+ { red; intros; elim n. rewrite <- (Int.repr_unsigned m). rewrite H; auto. }
+ assert (0 < Int.size m).
+ { apply Int.Zsize_pos'. generalize (Int.unsigned_range m); omega. }
+ generalize (Int.size_range m); intros.
+ f_equal. apply Int.bits_size_4. tauto.
+ rewrite Int.bits_zero_ext by omega. rewrite zlt_true by omega.
+ apply Int.bits_mone; omega.
+ intros. rewrite Int.bits_zero_ext by omega. apply zlt_false; omega.
+Qed.
+
+(** ** Abstract operations over value needs. *)
+
+Ltac InvAgree :=
+ simpl vagree in *;
+ repeat (
+ auto || exact Logic.I ||
+ match goal with
+ | [ H: False |- _ ] => contradiction
+ | [ H: match ?v with Vundef => _ | Vint _ => _ | Vlong _ => _ | Vfloat _ => _ | Vptr _ _ => _ end |- _ ] => destruct v
+ end).
+
+(** And immediate, or immediate *)
+
+Definition andimm (x: nval) (n: int) :=
+ match x with
+ | Nothing | Fsingle => Nothing
+ | I m => I (Int.and m n)
+ | All => I n
+ end.
+
+Lemma andimm_sound:
+ forall v w x n,
+ vagree v w (andimm x n) ->
+ vagree (Val.and v (Vint n)) (Val.and w (Vint n)) x.
+Proof.
+ unfold andimm; intros; destruct x; simpl in *; unfold Val.and.
+- auto.
+- InvAgree. apply iagree_and; auto.
+- destruct v; destruct w; tauto.
+- InvAgree. rewrite iagree_and_eq in H. rewrite H; auto.
+Qed.
+
+Definition orimm (x: nval) (n: int) :=
+ match x with
+ | Nothing | Fsingle => Nothing
+ | I m => I (Int.and m (Int.not n))
+ | _ => I (Int.not n)
+ end.
+
+Lemma orimm_sound:
+ forall v w x n,
+ vagree v w (orimm x n) ->
+ vagree (Val.or v (Vint n)) (Val.or w (Vint n)) x.
+Proof.
+ unfold orimm; intros; destruct x; simpl in *.
+- auto.
+- unfold Val.or; InvAgree. apply iagree_or; auto.
+- destruct v; destruct w; tauto.
+- InvAgree. simpl. apply Val.lessdef_same. f_equal. apply iagree_mone.
+ apply iagree_or. rewrite Int.and_commut. rewrite Int.and_mone. auto.
+Qed.
+
+(** Bitwise operations: and, or, xor, not *)
+
+Definition bitwise (x: nval) :=
+ match x with
+ | Fsingle => Nothing
+ | _ => x
+ end.
+
+Remark bitwise_idem: forall nv, bitwise (bitwise nv) = bitwise nv.
+Proof. destruct nv; auto. Qed.
+
+Lemma vagree_bitwise_binop:
+ forall f,
+ (forall p1 p2 q1 q2 m,
+ iagree p1 q1 m -> iagree p2 q2 m -> iagree (f p1 p2) (f q1 q2) m) ->
+ forall v1 w1 v2 w2 x,
+ vagree v1 w1 (bitwise x) -> vagree v2 w2 (bitwise x) ->
+ vagree (match v1, v2 with Vint i1, Vint i2 => Vint(f i1 i2) | _, _ => Vundef end)
+ (match w1, w2 with Vint i1, Vint i2 => Vint(f i1 i2) | _, _ => Vundef end)
+ x.
+Proof.
+ unfold bitwise; intros. destruct x; simpl in *.
+- auto.
+- InvAgree.
+- destruct v1; auto. destruct v2; auto.
+- inv H0; auto. inv H1; auto. destruct w1; auto.
+Qed.
+
+Lemma and_sound:
+ forall v1 w1 v2 w2 x,
+ vagree v1 w1 (bitwise x) -> vagree v2 w2 (bitwise x) ->
+ vagree (Val.and v1 v2) (Val.and w1 w2) x.
+Proof (vagree_bitwise_binop Int.and (iagree_bitwise_binop andb Int.and Int.bits_and)).
+
+Lemma or_sound:
+ forall v1 w1 v2 w2 x,
+ vagree v1 w1 (bitwise x) -> vagree v2 w2 (bitwise x) ->
+ vagree (Val.or v1 v2) (Val.or w1 w2) x.
+Proof (vagree_bitwise_binop Int.or (iagree_bitwise_binop orb Int.or Int.bits_or)).
+
+Lemma xor_sound:
+ forall v1 w1 v2 w2 x,
+ vagree v1 w1 (bitwise x) -> vagree v2 w2 (bitwise x) ->
+ vagree (Val.xor v1 v2) (Val.xor w1 w2) x.
+Proof (vagree_bitwise_binop Int.xor (iagree_bitwise_binop xorb Int.xor Int.bits_xor)).
+
+Lemma notint_sound:
+ forall v w x,
+ vagree v w (bitwise x) -> vagree (Val.notint v) (Val.notint w) x.
+Proof.
+ intros. rewrite ! Val.not_xor. apply xor_sound; auto with na.
+Qed.
+
+(** Shifts and rotates *)
+
+Definition shlimm (x: nval) (n: int) :=
+ match x with
+ | Nothing | Fsingle => Nothing
+ | I m => I (Int.shru m n)
+ | All => I (Int.shru Int.mone n)
+ end.
+
+Lemma shlimm_sound:
+ forall v w x n,
+ vagree v w (shlimm x n) ->
+ vagree (Val.shl v (Vint n)) (Val.shl w (Vint n)) x.
+Proof.
+ unfold shlimm; intros. unfold Val.shl.
+ destruct (Int.ltu n Int.iwordsize).
+ destruct x; simpl in *.
+- auto.
+- InvAgree. apply iagree_shl; auto.
+- destruct v; destruct w; auto.
+- InvAgree. apply Val.lessdef_same. f_equal. apply iagree_mone. apply iagree_shl; auto.
+- destruct v; auto with na.
+Qed.
+
+Definition shruimm (x: nval) (n: int) :=
+ match x with
+ | Nothing | Fsingle => Nothing
+ | I m => I (Int.shl m n)
+ | All => I (Int.shl Int.mone n)
+ end.
+
+Lemma shruimm_sound:
+ forall v w x n,
+ vagree v w (shruimm x n) ->
+ vagree (Val.shru v (Vint n)) (Val.shru w (Vint n)) x.
+Proof.
+ unfold shruimm; intros. unfold Val.shru.
+ destruct (Int.ltu n Int.iwordsize).
+ destruct x; simpl in *.
+- auto.
+- InvAgree. apply iagree_shru; auto.
+- destruct v; destruct w; auto.
+- InvAgree. apply Val.lessdef_same. f_equal. apply iagree_mone. apply iagree_shru; auto.
+- destruct v; auto with na.
+Qed.
+
+Definition shrimm (x: nval) (n: int) :=
+ match x with
+ | Nothing | Fsingle => Nothing
+ | I m => I (let m' := Int.shl m n in
+ if Int.eq_dec (Int.shru m' n) m
+ then m'
+ else Int.or m' (Int.repr Int.min_signed))
+ | All => I (Int.or (Int.shl Int.mone n) (Int.repr Int.min_signed))
+ end.
+
+Lemma shrimm_sound:
+ forall v w x n,
+ vagree v w (shrimm x n) ->
+ vagree (Val.shr v (Vint n)) (Val.shr w (Vint n)) x.
+Proof.
+ unfold shrimm; intros. unfold Val.shr.
+ destruct (Int.ltu n Int.iwordsize).
+ destruct x; simpl in *.
+- auto.
+- InvAgree.
+ destruct (Int.eq_dec (Int.shru (Int.shl m n) n) m).
+ apply iagree_shr_1; auto.
+ apply iagree_shr; auto.
+- destruct v; destruct w; auto.
+- InvAgree. apply Val.lessdef_same. f_equal. apply iagree_mone. apply iagree_shr. auto.
+- destruct v; auto with na.
+Qed.
+
+Definition rolm (x: nval) (amount mask: int) :=
+ match x with
+ | Nothing | Fsingle => Nothing
+ | I m => I (Int.ror (Int.and m mask) amount)
+ | _ => I (Int.ror mask amount)
+ end.
+
+Lemma rolm_sound:
+ forall v w x amount mask,
+ vagree v w (rolm x amount mask) ->
+ vagree (Val.rolm v amount mask) (Val.rolm w amount mask) x.
+Proof.
+ unfold rolm; intros; destruct x; simpl in *.
+- auto.
+- unfold Val.rolm; InvAgree. unfold Int.rolm.
+ apply iagree_and. apply iagree_rol. auto.
+- unfold Val.rolm; destruct v, w; auto.
+- unfold Val.rolm; InvAgree. apply Val.lessdef_same. f_equal. apply iagree_mone.
+ unfold Int.rolm. apply iagree_and. apply iagree_rol. rewrite Int.and_commut.
+ rewrite Int.and_mone. auto.
+Qed.
+
+Definition ror (x: nval) (amount: int) :=
+ match x with
+ | Nothing | Fsingle => Nothing
+ | I m => I (Int.rol m amount)
+ | All => All
+ end.
+
+Lemma ror_sound:
+ forall v w x n,
+ vagree v w (ror x n) ->
+ vagree (Val.ror v (Vint n)) (Val.ror w (Vint n)) x.
+Proof.
+ unfold ror; intros. unfold Val.ror.
+ destruct (Int.ltu n Int.iwordsize).
+ destruct x; simpl in *.
+- auto.
+- InvAgree. apply iagree_ror; auto.
+- destruct v, w; auto.
+- inv H; auto.
+- destruct v; auto with na.
+Qed.
+
+(** Modular arithmetic operations: add, mul.
+ (But not subtraction because of the pointer - pointer case. *)
+
+Definition modarith (x: nval) :=
+ match x with
+ | Nothing | Fsingle => Nothing
+ | I m => I (complete_mask m)
+ | All => All
+ end.
+
+Lemma add_sound:
+ forall v1 w1 v2 w2 x,
+ vagree v1 w1 (modarith x) -> vagree v2 w2 (modarith x) ->
+ vagree (Val.add v1 v2) (Val.add w1 w2) x.
+Proof.
+ unfold modarith; intros. destruct x; simpl in *.
+- auto.
+- unfold Val.add; InvAgree. apply eqmod_iagree. apply Int.eqmod_add; apply iagree_eqmod; auto.
+- unfold Val.add; destruct v1, w1; auto; destruct v2, w2; auto.
+- inv H; auto. inv H0; auto. destruct w1; auto.
+Qed.
+
+Remark modarith_idem: forall nv, modarith (modarith nv) = modarith nv.
+Proof.
+ destruct nv; simpl; auto. f_equal; apply complete_mask_idem.
+Qed.
+
+Lemma add_sound_2:
+ forall v1 w1 v2 w2 x,
+ vagree v1 w1 (modarith x) -> vagree v2 w2 (modarith x) ->
+ vagree (Val.add v1 v2) (Val.add w1 w2) (modarith x).
+Proof.
+ intros. apply add_sound; rewrite modarith_idem; auto.
+Qed.
+
+Lemma mul_sound:
+ forall v1 w1 v2 w2 x,
+ vagree v1 w1 (modarith x) -> vagree v2 w2 (modarith x) ->
+ vagree (Val.mul v1 v2) (Val.mul w1 w2) x.
+Proof.
+ unfold mul, add; intros. destruct x; simpl in *.
+- auto.
+- unfold Val.mul; InvAgree. apply eqmod_iagree. apply Int.eqmod_mult; apply iagree_eqmod; auto.
+- unfold Val.mul; destruct v1, w1; auto; destruct v2, w2; auto.
+- inv H; auto. inv H0; auto. destruct w1; auto.
+Qed.
+
+Lemma mul_sound_2:
+ forall v1 w1 v2 w2 x,
+ vagree v1 w1 (modarith x) -> vagree v2 w2 (modarith x) ->
+ vagree (Val.mul v1 v2) (Val.mul w1 w2) (modarith x).
+Proof.
+ intros. apply mul_sound; rewrite modarith_idem; auto.
+Qed.
+
+(** Conversions: zero extension, sign extension, single-of-float *)
+
+Definition zero_ext (n: Z) (x: nval) :=
+ match x with
+ | Nothing | Fsingle => Nothing
+ | I m => I (Int.zero_ext n m)
+ | All => I (Int.zero_ext n Int.mone)
+ end.
+
+Lemma zero_ext_sound:
+ forall v w x n,
+ vagree v w (zero_ext n x) ->
+ 0 <= n ->
+ vagree (Val.zero_ext n v) (Val.zero_ext n w) x.
+Proof.
+ unfold zero_ext; intros.
+ destruct x; simpl in *.
+- auto.
+- unfold Val.zero_ext; InvAgree.
+ red; intros. autorewrite with ints; try omega.
+ destruct (zlt i1 n); auto. apply H; auto.
+ autorewrite with ints; try omega. rewrite zlt_true; auto.
+- unfold Val.zero_ext; destruct v; destruct w; auto.
+- unfold Val.zero_ext; InvAgree; auto. apply Val.lessdef_same. f_equal.
+ Int.bit_solve; try omega. destruct (zlt i1 n); auto. apply H; auto.
+ autorewrite with ints; try omega. apply zlt_true; auto.
+Qed.
+
+Definition sign_ext (n: Z) (x: nval) :=
+ match x with
+ | Nothing | Fsingle => Nothing
+ | I m => I (Int.or (Int.zero_ext n m) (Int.shl Int.one (Int.repr (n - 1))))
+ | All => I (Int.zero_ext n Int.mone)
+ end.
+
+Lemma sign_ext_sound:
+ forall v w x n,
+ vagree v w (sign_ext n x) ->
+ 0 < n < Int.zwordsize ->
+ vagree (Val.sign_ext n v) (Val.sign_ext n w) x.
+Proof.
+ unfold sign_ext; intros. destruct x; simpl in *.
+- auto.
+- unfold Val.sign_ext; InvAgree.
+ red; intros. autorewrite with ints; try omega.
+ set (j := if zlt i1 n then i1 else n - 1).
+ assert (0 <= j < Int.zwordsize).
+ { unfold j; destruct (zlt i1 n); omega. }
+ apply H; auto.
+ autorewrite with ints; try omega. apply orb_true_intro.
+ unfold j; destruct (zlt i1 n).
+ left. rewrite zlt_true; auto.
+ right. rewrite Int.unsigned_repr. rewrite zlt_false by omega.
+ replace (n - 1 - (n - 1)) with 0 by omega. reflexivity.
+ generalize Int.wordsize_max_unsigned; omega.
+- unfold Val.sign_ext; destruct v; destruct w; auto.
+- unfold Val.sign_ext; InvAgree; auto. apply Val.lessdef_same. f_equal.
+ Int.bit_solve; try omega.
+ set (j := if zlt i1 n then i1 else n - 1).
+ assert (0 <= j < Int.zwordsize).
+ { unfold j; destruct (zlt i1 n); omega. }
+ apply H; auto. rewrite Int.bits_zero_ext; try omega.
+ rewrite zlt_true. apply Int.bits_mone; auto.
+ unfold j. destruct (zlt i1 n); omega.
+Qed.
+
+Definition singleoffloat (x: nval) :=
+ match x with
+ | Nothing | I _ => Nothing
+ | Fsingle | All => Fsingle
+ end.
+
+Lemma singleoffloat_sound:
+ forall v w x,
+ vagree v w (singleoffloat x) ->
+ vagree (Val.singleoffloat v) (Val.singleoffloat w) x.
+Proof.
+ unfold singleoffloat; intros. destruct x; simpl in *.
+- auto.
+- unfold Val.singleoffloat; destruct v, w; auto.
+- unfold Val.singleoffloat; InvAgree. congruence.
+- unfold Val.singleoffloat; InvAgree; auto. rewrite H; auto.
+Qed.
+
+(** The needs of a memory store concerning the value being stored. *)
+
+Definition store_argument (chunk: memory_chunk) :=
+ match chunk with
+ | Mint8signed | Mint8unsigned => I (Int.repr 255)
+ | Mint16signed | Mint16unsigned => I (Int.repr 65535)
+ | Mfloat32 => Fsingle
+ | _ => All
+ end.
+
+Lemma store_argument_sound:
+ forall chunk v w,
+ vagree v w (store_argument chunk) ->
+ list_forall2 memval_lessdef (encode_val chunk v) (encode_val chunk w).
+Proof.
+ intros.
+ assert (UNDEF: list_forall2 memval_lessdef
+ (list_repeat (size_chunk_nat chunk) Undef)
+ (encode_val chunk w)).
+ {
+ rewrite <- (encode_val_length chunk w).
+ apply repeat_Undef_inject_any.
+ }
+ assert (SAME: forall vl1 vl2,
+ vl1 = vl2 ->
+ list_forall2 memval_lessdef vl1 vl2).
+ {
+ intros. subst vl2. revert vl1. induction vl1; constructor; auto.
+ apply memval_lessdef_refl.
+ }
+
+ intros. unfold store_argument in H; destruct chunk.
+- InvAgree. apply SAME. simpl; f_equal. apply encode_int_8_mod.
+ change 8 with (Int.size (Int.repr 255)). apply iagree_eqmod; auto.
+- InvAgree. apply SAME. simpl; f_equal. apply encode_int_8_mod.
+ change 8 with (Int.size (Int.repr 255)). apply iagree_eqmod; auto.
+- InvAgree. apply SAME. simpl; f_equal. apply encode_int_16_mod.
+ change 16 with (Int.size (Int.repr 65535)). apply iagree_eqmod; auto.
+- InvAgree. apply SAME. simpl; f_equal. apply encode_int_16_mod.
+ change 16 with (Int.size (Int.repr 65535)). apply iagree_eqmod; auto.
+- apply encode_val_inject. rewrite val_inject_id; auto.
+- apply encode_val_inject. rewrite val_inject_id; auto.
+- InvAgree. apply SAME. simpl.
+ rewrite <- (Float.bits_of_singleoffloat f).
+ rewrite <- (Float.bits_of_singleoffloat f0).
+ congruence.
+- apply encode_val_inject. rewrite val_inject_id; auto.
+- apply encode_val_inject. rewrite val_inject_id; auto.
+Qed.
+
+Lemma store_argument_load_result:
+ forall chunk v w,
+ vagree v w (store_argument chunk) ->
+ Val.lessdef (Val.load_result chunk v) (Val.load_result chunk w).
+Proof.
+ unfold store_argument; intros; destruct chunk;
+ auto using Val.load_result_lessdef; InvAgree; simpl.
+- apply sign_ext_sound with (v := Vint i) (w := Vint i0) (x := All) (n := 8).
+ auto. compute; auto.
+- apply zero_ext_sound with (v := Vint i) (w := Vint i0) (x := All) (n := 8).
+ auto. omega.
+- apply sign_ext_sound with (v := Vint i) (w := Vint i0) (x := All) (n := 16).
+ auto. compute; auto.
+- apply zero_ext_sound with (v := Vint i) (w := Vint i0) (x := All) (n := 16).
+ auto. omega.
+- apply singleoffloat_sound with (v := Vfloat f) (w := Vfloat f0) (x := All).
+ auto.
+Qed.
+
+(** The needs of a comparison *)
+
+Definition maskzero (n: int) := I n.
+
+Lemma maskzero_sound:
+ forall v w n b,
+ vagree v w (maskzero n) ->
+ Val.maskzero_bool v n = Some b ->
+ Val.maskzero_bool w n = Some b.
+Proof.
+ unfold maskzero; intros.
+ unfold Val.maskzero_bool; InvAgree; try discriminate.
+ inv H0. rewrite iagree_and_eq in H. rewrite H. auto.
+Qed.
+
+(** The default abstraction: if the result is unused, the arguments are
+ unused; otherwise, the arguments are needed in full. *)
+
+Definition default (x: nval) :=
+ match x with
+ | Nothing => Nothing
+ | _ => All
+ end.
+
+Section DEFAULT.
+
+Variable ge: genv.
+Variable sp: block.
+Variables m1 m2: mem.
+Hypothesis PERM: forall b ofs k p, Mem.perm m1 b ofs k p -> Mem.perm m2 b ofs k p.
+
+Let valid_pointer_inj:
+ forall b1 ofs b2 delta,
+ inject_id b1 = Some(b2, delta) ->
+ Mem.valid_pointer m1 b1 (Int.unsigned ofs) = true ->
+ Mem.valid_pointer m2 b2 (Int.unsigned (Int.add ofs (Int.repr delta))) = true.
+Proof.
+ unfold inject_id; intros. inv H. rewrite Int.add_zero.
+ rewrite Mem.valid_pointer_nonempty_perm in *. eauto.
+Qed.
+
+Let weak_valid_pointer_inj:
+ forall b1 ofs b2 delta,
+ inject_id b1 = Some(b2, delta) ->
+ Mem.weak_valid_pointer m1 b1 (Int.unsigned ofs) = true ->
+ Mem.weak_valid_pointer m2 b2 (Int.unsigned (Int.add ofs (Int.repr delta))) = true.
+Proof.
+ unfold inject_id; intros. inv H. rewrite Int.add_zero.
+ rewrite Mem.weak_valid_pointer_spec in *.
+ rewrite ! Mem.valid_pointer_nonempty_perm in *.
+ destruct H0; [left|right]; eauto.
+Qed.
+
+Let weak_valid_pointer_no_overflow:
+ forall b1 ofs b2 delta,
+ inject_id b1 = Some(b2, delta) ->
+ Mem.weak_valid_pointer m1 b1 (Int.unsigned ofs) = true ->
+ 0 <= Int.unsigned ofs + Int.unsigned (Int.repr delta) <= Int.max_unsigned.
+Proof.
+ unfold inject_id; intros. inv H. rewrite Zplus_0_r. apply Int.unsigned_range_2.
+Qed.
+
+Let valid_different_pointers_inj:
+ forall b1 ofs1 b2 ofs2 b1' delta1 b2' delta2,
+ b1 <> b2 ->
+ Mem.valid_pointer m1 b1 (Int.unsigned ofs1) = true ->
+ Mem.valid_pointer m1 b2 (Int.unsigned ofs2) = true ->
+ inject_id b1 = Some (b1', delta1) ->
+ inject_id b2 = Some (b2', delta2) ->
+ b1' <> b2' \/
+ Int.unsigned (Int.add ofs1 (Int.repr delta1)) <> Int.unsigned (Int.add ofs2 (Int.repr delta2)).
+Proof.
+ unfold inject_id; intros. left; congruence.
+Qed.
+
+Lemma default_needs_of_condition_sound:
+ forall cond args1 b args2,
+ eval_condition cond args1 m1 = Some b ->
+ vagree_list args1 args2 All ->
+ eval_condition cond args2 m2 = Some b.
+Proof.
+ intros. apply eval_condition_inj with (f := inject_id) (m1 := m1) (vl1 := args1); auto.
+ apply val_list_inject_lessdef. apply lessdef_vagree_list. auto.
+Qed.
+
+Lemma default_needs_of_operation_sound:
+ forall op args1 v1 args2 nv,
+ eval_operation ge (Vptr sp Int.zero) op args1 m1 = Some v1 ->
+ vagree_list args1 args2 (default nv) ->
+ nv <> Nothing ->
+ exists v2,
+ eval_operation ge (Vptr sp Int.zero) op args2 m2 = Some v2
+ /\ vagree v1 v2 nv.
+Proof.
+ intros. assert (default nv = All) by (destruct nv; simpl; congruence).
+ rewrite H2 in H0.
+ exploit (@eval_operation_inj _ _ ge inject_id).
+ intros. apply val_inject_lessdef. auto.
+ eassumption. auto. auto. auto.
+ apply val_inject_lessdef. instantiate (1 := Vptr sp Int.zero). instantiate (1 := Vptr sp Int.zero). auto.
+ apply val_list_inject_lessdef. apply lessdef_vagree_list. eauto.
+ eauto.
+ intros (v2 & A & B). exists v2; split; auto.
+ apply vagree_lessdef. apply val_inject_lessdef. auto.
+Qed.
+
+End DEFAULT.
+
+(** ** Detecting operations that are redundant and can be turned into a move *)
+
+Definition andimm_redundant (x: nval) (n: int) :=
+ match x with
+ | Nothing => true
+ | I m => Int.eq_dec (Int.and m (Int.not n)) Int.zero
+ | _ => false
+ end.
+
+Lemma andimm_redundant_sound:
+ forall v w x n,
+ andimm_redundant x n = true ->
+ vagree v w (andimm x n) ->
+ vagree (Val.and v (Vint n)) w x.
+Proof.
+ unfold andimm_redundant; intros. destruct x; try discriminate.
+- simpl; auto.
+- InvBooleans. simpl in *; unfold Val.and; InvAgree.
+ red; intros. exploit (eq_same_bits i1); eauto.
+ autorewrite with ints; auto. rewrite H2; simpl; intros.
+ destruct (Int.testbit n i1) eqn:N; try discriminate.
+ rewrite andb_true_r. apply H0; auto. autorewrite with ints; auto.
+ rewrite H2, N; auto.
+Qed.
+
+Definition orimm_redundant (x: nval) (n: int) :=
+ match x with
+ | Nothing => true
+ | I m => Int.eq_dec (Int.and m n) Int.zero
+ | _ => false
+ end.
+
+Lemma orimm_redundant_sound:
+ forall v w x n,
+ orimm_redundant x n = true ->
+ vagree v w (orimm x n) ->
+ vagree (Val.or v (Vint n)) w x.
+Proof.
+ unfold orimm_redundant; intros. destruct x; try discriminate.
+- auto.
+- InvBooleans. simpl in *; unfold Val.or; InvAgree.
+ apply iagree_not'. rewrite Int.not_or_and_not.
+ apply (andimm_redundant_sound (Vint (Int.not i)) (Vint (Int.not i0)) (I m) (Int.not n)).
+ simpl. rewrite Int.not_involutive. apply proj_sumbool_is_true. auto.
+ simpl. apply iagree_not; auto.
+Qed.
+
+Definition rolm_redundant (x: nval) (amount mask: int) :=
+ Int.eq_dec amount Int.zero && andimm_redundant x mask.
+
+Lemma rolm_redundant_sound:
+ forall v w x amount mask,
+ rolm_redundant x amount mask = true ->
+ vagree v w (rolm x amount mask) ->
+ vagree (Val.rolm v amount mask) w x.
+Proof.
+ unfold rolm_redundant; intros; InvBooleans. subst amount. rewrite Val.rolm_zero.
+ apply andimm_redundant_sound; auto.
+ assert (forall n, Int.ror n Int.zero = n).
+ { intros. rewrite Int.ror_rol_neg by apply int_wordsize_divides_modulus.
+ rewrite Int.neg_zero. apply Int.rol_zero. }
+ unfold rolm, andimm in *. destruct x; auto.
+ rewrite H in H0. auto.
+ rewrite H in H0. auto.
+Qed.
+
+Definition zero_ext_redundant (n: Z) (x: nval) :=
+ match x with
+ | Nothing => true
+ | I m => Int.eq_dec (Int.zero_ext n m) m
+ | _ => false
+ end.
+
+Lemma zero_ext_redundant_sound:
+ forall v w x n,
+ zero_ext_redundant n x = true ->
+ vagree v w (zero_ext n x) ->
+ 0 <= n ->
+ vagree (Val.zero_ext n v) w x.
+Proof.
+ unfold zero_ext_redundant; intros. destruct x; try discriminate.
+- auto.
+- simpl in *; InvAgree. simpl. InvBooleans. rewrite <- H.
+ red; intros; autorewrite with ints; try omega.
+ destruct (zlt i1 n). apply H0; auto.
+ rewrite Int.bits_zero_ext in H3 by omega. rewrite zlt_false in H3 by auto. discriminate.
+Qed.
+
+Definition sign_ext_redundant (n: Z) (x: nval) :=
+ match x with
+ | Nothing => true
+ | I m => Int.eq_dec (Int.zero_ext n m) m
+ | _ => false
+ end.
+
+Lemma sign_ext_redundant_sound:
+ forall v w x n,
+ sign_ext_redundant n x = true ->
+ vagree v w (sign_ext n x) ->
+ 0 < n ->
+ vagree (Val.sign_ext n v) w x.
+Proof.
+ unfold sign_ext_redundant; intros. destruct x; try discriminate.
+- auto.
+- simpl in *; InvAgree. simpl. InvBooleans. rewrite <- H.
+ red; intros; autorewrite with ints; try omega.
+ destruct (zlt i1 n). apply H0; auto.
+ rewrite Int.bits_or; auto. rewrite H3; auto.
+ rewrite Int.bits_zero_ext in H3 by omega. rewrite zlt_false in H3 by auto. discriminate.
+Qed.
+
+Definition singleoffloat_redundant (x: nval) :=
+ match x with
+ | Nothing => true
+ | Fsingle => true
+ | _ => false
+ end.
+
+Lemma singleoffloat_redundant_sound:
+ forall v w x,
+ singleoffloat_redundant x = true ->
+ vagree v w (singleoffloat x) ->
+ vagree (Val.singleoffloat v) w x.
+Proof.
+ unfold singleoffloat; intros. destruct x; try discriminate.
+- auto.
+- simpl in *; InvAgree. simpl. rewrite Float.singleoffloat_idem; auto.
+Qed.
+
+(** * Neededness for register environments *)
+
+Module NVal <: SEMILATTICE.
+
+ Definition t := nval.
+ Definition eq (x y: t) := (x = y).
+ Definition eq_refl: forall x, eq x x := (@refl_equal t).
+ Definition eq_sym: forall x y, eq x y -> eq y x := (@sym_equal t).
+ Definition eq_trans: forall x y z, eq x y -> eq y z -> eq x z := (@trans_equal t).
+ Definition beq (x y: t) : bool := proj_sumbool (eq_nval x y).
+ Lemma beq_correct: forall x y, beq x y = true -> eq x y.
+ Proof. unfold beq; intros. InvBooleans. auto. Qed.
+ Definition ge := nge.
+ Lemma ge_refl: forall x y, eq x y -> ge x y.
+ Proof. unfold eq, ge; intros. subst y. apply nge_refl. Qed.
+ Lemma ge_trans: forall x y z, ge x y -> ge y z -> ge x z.
+ Proof. unfold ge; intros. eapply nge_trans; eauto. Qed.
+ Definition bot : t := Nothing.
+ Lemma ge_bot: forall x, ge x bot.
+ Proof. intros. constructor. Qed.
+ Definition lub := nlub.
+ Lemma ge_lub_left: forall x y, ge (lub x y) x.
+ Proof nge_lub_l.
+ Lemma ge_lub_right: forall x y, ge (lub x y) y.
+ Proof nge_lub_r.
+End NVal.
+
+Module NE := LPMap1(NVal).
+
+Definition nenv := NE.t.
+
+Definition nreg (ne: nenv) (r: reg) := NE.get r ne.
+
+Definition eagree (e1 e2: regset) (ne: nenv) : Prop :=
+ forall r, vagree e1#r e2#r (NE.get r ne).
+
+Lemma nreg_agree:
+ forall rs1 rs2 ne r, eagree rs1 rs2 ne -> vagree rs1#r rs2#r (nreg ne r).
+Proof.
+ intros. apply H.
+Qed.
+
+Hint Resolve nreg_agree: na.
+
+Lemma eagree_ge:
+ forall e1 e2 ne ne',
+ eagree e1 e2 ne -> NE.ge ne ne' -> eagree e1 e2 ne'.
+Proof.
+ intros; red; intros. apply nge_agree with (NE.get r ne); auto. apply H0.
+Qed.
+
+Lemma eagree_bot:
+ forall e1 e2, eagree e1 e2 NE.bot.
+Proof.
+ intros; red; intros. rewrite NE.get_bot. exact Logic.I.
+Qed.
+
+Lemma eagree_same:
+ forall e ne, eagree e e ne.
+Proof.
+ intros; red; intros. apply vagree_same.
+Qed.
+
+Lemma eagree_update_1:
+ forall e1 e2 ne v1 v2 nv r,
+ eagree e1 e2 ne -> vagree v1 v2 nv -> eagree (e1#r <- v1) (e2#r <- v2) (NE.set r nv ne).
+Proof.
+ intros; red; intros. rewrite NE.gsspec. rewrite ! PMap.gsspec.
+ destruct (peq r0 r); auto.
+Qed.
+
+Lemma eagree_update:
+ forall e1 e2 ne v1 v2 r,
+ vagree v1 v2 (nreg ne r) ->
+ eagree e1 e2 (NE.set r Nothing ne) ->
+ eagree (e1#r <- v1) (e2#r <- v2) ne.
+Proof.
+ intros; red; intros. specialize (H0 r0). rewrite NE.gsspec in H0.
+ rewrite ! PMap.gsspec. destruct (peq r0 r).
+ subst r0. auto.
+ auto.
+Qed.
+
+Lemma eagree_update_dead:
+ forall e1 e2 ne v1 r,
+ nreg ne r = Nothing ->
+ eagree e1 e2 ne -> eagree (e1#r <- v1) e2 ne.
+Proof.
+ intros; red; intros. rewrite PMap.gsspec.
+ destruct (peq r0 r); auto. subst. unfold nreg in H. rewrite H. red; auto.
+Qed.
+
+(** * Neededness for memory locations *)
+
+Inductive nmem : Type :=
+ | NMemDead
+ | NMem (stk: ISet.t) (gl: PTree.t ISet.t).
+
+(** Interpretation of [nmem]:
+- [NMemDead]: all memory locations are unused (dead). Acts as bottom.
+- [NMem stk gl]: all memory locations are used, except:
+ - the stack locations whose offset is in the interval [stk]
+ - the global locations whose offset is in the corresponding entry of [gl].
+*)
+
+Section LOCATIONS.
+
+Variable ge: genv.
+Variable sp: block.
+
+Inductive nlive: nmem -> block -> Z -> Prop :=
+ | nlive_intro: forall stk gl b ofs
+ (STK: b = sp -> ~ISet.In ofs stk)
+ (GL: forall id iv,
+ Genv.find_symbol ge id = Some b ->
+ gl!id = Some iv ->
+ ~ISet.In ofs iv),
+ nlive (NMem stk gl) b ofs.
+
+(** All locations are live *)
+
+Definition nmem_all := NMem ISet.empty (PTree.empty _).
+
+Lemma nlive_all: forall b ofs, nlive nmem_all b ofs.
+Proof.
+ intros; constructor; intros.
+ apply ISet.In_empty.
+ rewrite PTree.gempty in H0; discriminate.
+Qed.
+
+(** Add a range of live locations to [nm]. The range starts at
+ the abstract pointer [p] and has length [sz]. *)
+
+Definition nmem_add (nm: nmem) (p: aptr) (sz: Z) : nmem :=
+ match nm with
+ | NMemDead => nmem_all (**r very conservative, should never happen *)
+ | NMem stk gl =>
+ match p with
+ | Gl id ofs =>
+ match gl!id with
+ | Some iv => NMem stk (PTree.set id (ISet.remove (Int.unsigned ofs) (Int.unsigned ofs + sz) iv) gl)
+ | None => nm
+ end
+ | Glo id =>
+ NMem stk (PTree.remove id gl)
+ | Stk ofs =>
+ NMem (ISet.remove (Int.unsigned ofs) (Int.unsigned ofs + sz) stk) gl
+ | Stack =>
+ NMem ISet.empty gl
+ | _ => nmem_all
+ end
+ end.
+
+Lemma nlive_add:
+ forall bc b ofs p nm sz i,
+ genv_match bc ge ->
+ bc sp = BCstack ->
+ pmatch bc b ofs p ->
+ Int.unsigned ofs <= i < Int.unsigned ofs + sz ->
+ nlive (nmem_add nm p sz) b i.
+Proof.
+ intros. unfold nmem_add. destruct nm. apply nlive_all.
+ inv H1; try (apply nlive_all).
+ - (* Gl id ofs *)
+ assert (Genv.find_symbol ge id = Some b) by (eapply H; eauto).
+ destruct gl!id as [iv|] eqn:NG.
+ + constructor; simpl; intros.
+ congruence.
+ assert (id0 = id) by (eapply Genv.genv_vars_inj; eauto). subst id0.
+ rewrite PTree.gss in H5. inv H5. rewrite ISet.In_remove.
+ intros [A B]. elim A; auto.
+ + constructor; simpl; intros.
+ congruence.
+ assert (id0 = id) by (eapply Genv.genv_vars_inj; eauto). subst id0.
+ congruence.
+ - (* Glo id *)
+ assert (Genv.find_symbol ge id = Some b) by (eapply H; eauto).
+ constructor; simpl; intros.
+ congruence.
+ assert (id0 = id) by (eapply Genv.genv_vars_inj; eauto). subst id0.
+ rewrite PTree.grs in H5. congruence.
+ - (* Stk ofs *)
+ constructor; simpl; intros.
+ rewrite ISet.In_remove. intros [A B]. elim A; auto.
+ assert (bc b = BCglob id) by (eapply H; eauto). congruence.
+ - (* Stack *)
+ constructor; simpl; intros.
+ apply ISet.In_empty.
+ assert (bc b = BCglob id) by (eapply H; eauto). congruence.
+Qed.
+
+Lemma incl_nmem_add:
+ forall nm b i p sz,
+ nlive nm b i -> nlive (nmem_add nm p sz) b i.
+Proof.
+ intros. inversion H; subst. unfold nmem_add; destruct p; try (apply nlive_all).
+- (* Gl id ofs *)
+ destruct gl!id as [iv|] eqn:NG.
+ + split; simpl; intros. auto.
+ rewrite PTree.gsspec in H1. destruct (peq id0 id); eauto. inv H1.
+ rewrite ISet.In_remove. intros [P Q]. eelim GL; eauto.
+ + auto.
+- (* Glo id *)
+ split; simpl; intros. auto.
+ rewrite PTree.grspec in H1. destruct (PTree.elt_eq id0 id). congruence. eauto.
+- (* Stk ofs *)
+ split; simpl; intros.
+ rewrite ISet.In_remove. intros [P Q]. eelim STK; eauto.
+ eauto.
+- (* Stack *)
+ split; simpl; intros.
+ apply ISet.In_empty.
+ eauto.
+Qed.
+
+(** Remove a range of locations from [nm], marking these locations as dead.
+ The range starts at the abstract pointer [p] and has length [sz]. *)
+
+Definition nmem_remove (nm: nmem) (p: aptr) (sz: Z) : nmem :=
+ match nm with
+ | NMemDead => NMemDead
+ | NMem stk gl =>
+ match p with
+ | Gl id ofs =>
+ let iv' :=
+ match gl!id with
+ | Some iv => ISet.add (Int.unsigned ofs) (Int.unsigned ofs + sz) iv
+ | None => ISet.interval (Int.unsigned ofs) (Int.unsigned ofs + sz)
+ end in
+ NMem stk (PTree.set id iv' gl)
+ | Stk ofs =>
+ NMem (ISet.add (Int.unsigned ofs) (Int.unsigned ofs + sz) stk) gl
+ | _ => nm
+ end
+ end.
+
+Lemma nlive_remove:
+ forall bc b ofs p nm sz b' i,
+ genv_match bc ge ->
+ bc sp = BCstack ->
+ pmatch bc b ofs p ->
+ nlive nm b' i ->
+ b' <> b \/ i < Int.unsigned ofs \/ Int.unsigned ofs + sz <= i ->
+ nlive (nmem_remove nm p sz) b' i.
+Proof.
+ intros. inversion H2; subst. unfold nmem_remove; inv H1; auto.
+- (* Gl id ofs *)
+ set (iv' := match gl!id with
+ | Some iv =>
+ ISet.add (Int.unsigned ofs) (Int.unsigned ofs + sz) iv
+ | None =>
+ ISet.interval (Int.unsigned ofs)
+ (Int.unsigned ofs + sz)
+ end).
+ assert (Genv.find_symbol ge id = Some b) by (eapply H; eauto).
+ split; simpl; auto; intros.
+ rewrite PTree.gsspec in H6. destruct (peq id0 id).
++ inv H6. destruct H3. congruence. destruct gl!id as [iv0|] eqn:NG.
+ rewrite ISet.In_add. intros [P|P]. omega. eelim GL; eauto.
+ rewrite ISet.In_interval. omega.
++ eauto.
+- (* Stk ofs *)
+ split; simpl; auto; intros. destruct H3.
+ elim H3. subst b'. eapply bc_stack; eauto.
+ rewrite ISet.In_add. intros [P|P]. omega. eapply STK; eauto.
+Qed.
+
+(** Test (conservatively) whether some locations in the range delimited
+ by [p] and [sz] can be live in [nm]. *)
+
+Definition nmem_contains (nm: nmem) (p: aptr) (sz: Z) :=
+ match nm with
+ | NMemDead => false
+ | NMem stk gl =>
+ match p with
+ | Gl id ofs =>
+ match gl!id with
+ | Some iv => negb (ISet.contains (Int.unsigned ofs) (Int.unsigned ofs + sz) iv)
+ | None => true
+ end
+ | Stk ofs =>
+ negb (ISet.contains (Int.unsigned ofs) (Int.unsigned ofs + sz) stk)
+ | _ => true (**r conservative answer *)
+ end
+ end.
+
+Lemma nlive_contains:
+ forall bc b ofs p nm sz i,
+ genv_match bc ge ->
+ bc sp = BCstack ->
+ pmatch bc b ofs p ->
+ nmem_contains nm p sz = false ->
+ Int.unsigned ofs <= i < Int.unsigned ofs + sz ->
+ ~(nlive nm b i).
+Proof.
+ unfold nmem_contains; intros. red; intros L; inv L.
+ inv H1; try discriminate.
+- (* Gl id ofs *)
+ assert (Genv.find_symbol ge id = Some b) by (eapply H; eauto).
+ destruct gl!id as [iv|] eqn:HG; inv H2.
+ destruct (ISet.contains (Int.unsigned ofs) (Int.unsigned ofs + sz) iv) eqn:IC; try discriminate.
+ rewrite ISet.contains_spec in IC. eelim GL; eauto.
+- (* Stk ofs *)
+ destruct (ISet.contains (Int.unsigned ofs) (Int.unsigned ofs + sz) stk) eqn:IC; try discriminate.
+ rewrite ISet.contains_spec in IC. eelim STK; eauto. eapply bc_stack; eauto.
+Qed.
+
+(** Kill all stack locations between 0 and [sz], and mark everything else
+ as live. This reflects the effect of freeing the stack block at
+ a [Ireturn] or [Itailcall] instruction. *)
+
+Definition nmem_dead_stack (sz: Z) :=
+ NMem (ISet.interval 0 sz) (PTree.empty _).
+
+Lemma nlive_dead_stack:
+ forall sz b' i, b' <> sp \/ ~(0 <= i < sz) -> nlive (nmem_dead_stack sz) b' i.
+Proof.
+ intros; constructor; simpl; intros.
+- rewrite ISet.In_interval. intuition.
+- rewrite PTree.gempty in H1; discriminate.
+Qed.
+
+(** Least upper bound *)
+
+Definition nmem_lub (nm1 nm2: nmem) : nmem :=
+ match nm1, nm2 with
+ | NMemDead, _ => nm2
+ | _, NMemDead => nm1
+ | NMem stk1 gl1, NMem stk2 gl2 =>
+ NMem (ISet.inter stk1 stk2)
+ (PTree.combine
+ (fun o1 o2 =>
+ match o1, o2 with
+ | Some iv1, Some iv2 => Some(ISet.inter iv1 iv2)
+ | _, _ => None
+ end)
+ gl1 gl2)
+ end.
+
+Lemma nlive_lub_l:
+ forall nm1 nm2 b i, nlive nm1 b i -> nlive (nmem_lub nm1 nm2) b i.
+Proof.
+ intros. inversion H; subst. destruct nm2; simpl. auto.
+ constructor; simpl; intros.
+- rewrite ISet.In_inter. intros [P Q]. eelim STK; eauto.
+- rewrite PTree.gcombine in H1 by auto.
+ destruct gl!id as [iv1|] eqn:NG1; try discriminate;
+ destruct gl0!id as [iv2|] eqn:NG2; inv H1.
+ rewrite ISet.In_inter. intros [P Q]. eelim GL; eauto.
+Qed.
+
+Lemma nlive_lub_r:
+ forall nm1 nm2 b i, nlive nm2 b i -> nlive (nmem_lub nm1 nm2) b i.
+Proof.
+ intros. inversion H; subst. destruct nm1; simpl. auto.
+ constructor; simpl; intros.
+- rewrite ISet.In_inter. intros [P Q]. eelim STK; eauto.
+- rewrite PTree.gcombine in H1 by auto.
+ destruct gl0!id as [iv1|] eqn:NG1; try discriminate;
+ destruct gl!id as [iv2|] eqn:NG2; inv H1.
+ rewrite ISet.In_inter. intros [P Q]. eelim GL; eauto.
+Qed.
+
+(** Boolean-valued equality test *)
+
+Definition nmem_beq (nm1 nm2: nmem) : bool :=
+ match nm1, nm2 with
+ | NMemDead, NMemDead => true
+ | NMem stk1 gl1, NMem stk2 gl2 => ISet.beq stk1 stk2 && PTree.beq ISet.beq gl1 gl2
+ | _, _ => false
+ end.
+
+Lemma nmem_beq_sound:
+ forall nm1 nm2 b ofs,
+ nmem_beq nm1 nm2 = true ->
+ (nlive nm1 b ofs <-> nlive nm2 b ofs).
+Proof.
+ unfold nmem_beq; intros.
+ destruct nm1 as [ | stk1 gl1]; destruct nm2 as [ | stk2 gl2]; try discriminate.
+- split; intros L; inv L.
+- InvBooleans. rewrite ISet.beq_spec in H0. rewrite PTree.beq_correct in H1.
+ split; intros L; inv L; constructor; intros.
++ rewrite <- H0. eauto.
++ specialize (H1 id). rewrite H2 in H1. destruct gl1!id as [iv1|] eqn: NG; try contradiction.
+ rewrite ISet.beq_spec in H1. rewrite <- H1. eauto.
++ rewrite H0. eauto.
++ specialize (H1 id). rewrite H2 in H1. destruct gl2!id as [iv2|] eqn: NG; try contradiction.
+ rewrite ISet.beq_spec in H1. rewrite H1. eauto.
+Qed.
+
+End LOCATIONS.
+
+
+(** * The lattice for dataflow analysis *)
+
+Module NA <: SEMILATTICE.
+
+ Definition t := (nenv * nmem)%type.
+
+ Definition eq (x y: t) :=
+ NE.eq (fst x) (fst y) /\
+ (forall ge sp b ofs, nlive ge sp (snd x) b ofs <-> nlive ge sp (snd y) b ofs).
+
+ Lemma eq_refl: forall x, eq x x.
+ Proof.
+ unfold eq; destruct x; simpl; split. apply NE.eq_refl. tauto.
+ Qed.
+ Lemma eq_sym: forall x y, eq x y -> eq y x.
+ Proof.
+ unfold eq; destruct x, y; simpl. intros [A B].
+ split. apply NE.eq_sym; auto.
+ intros. rewrite B. tauto.
+ Qed.
+ Lemma eq_trans: forall x y z, eq x y -> eq y z -> eq x z.
+ Proof.
+ unfold eq; destruct x, y, z; simpl. intros [A B] [C D]; split.
+ eapply NE.eq_trans; eauto.
+ intros. rewrite B; auto.
+ Qed.
+
+ Definition beq (x y: t) : bool :=
+ NE.beq (fst x) (fst y) && nmem_beq (snd x) (snd y).
+
+ Lemma beq_correct: forall x y, beq x y = true -> eq x y.
+ Proof.
+ unfold beq, eq; destruct x, y; simpl; intros. InvBooleans. split.
+ apply NE.beq_correct; auto.
+ intros. apply nmem_beq_sound; auto.
+ Qed.
+
+ Definition ge (x y: t) : Prop :=
+ NE.ge (fst x) (fst y) /\
+ (forall ge sp b ofs, nlive ge sp (snd y) b ofs -> nlive ge sp (snd x) b ofs).
+
+ Lemma ge_refl: forall x y, eq x y -> ge x y.
+ Proof.
+ unfold eq, ge; destruct x, y; simpl. intros [A B]; split.
+ apply NE.ge_refl; auto.
+ intros. apply B; auto.
+ Qed.
+ Lemma ge_trans: forall x y z, ge x y -> ge y z -> ge x z.
+ Proof.
+ unfold ge; destruct x, y, z; simpl. intros [A B] [C D]; split.
+ eapply NE.ge_trans; eauto.
+ auto.
+ Qed.
+
+ Definition bot : t := (NE.bot, NMemDead).
+
+ Lemma ge_bot: forall x, ge x bot.
+ Proof.
+ unfold ge, bot; destruct x; simpl. split.
+ apply NE.ge_bot.
+ intros. inv H.
+ Qed.
+
+ Definition lub (x y: t) : t :=
+ (NE.lub (fst x) (fst y), nmem_lub (snd x) (snd y)).
+
+ Lemma ge_lub_left: forall x y, ge (lub x y) x.
+ Proof.
+ unfold ge; destruct x, y; simpl; split.
+ apply NE.ge_lub_left.
+ intros; apply nlive_lub_l; auto.
+ Qed.
+ Lemma ge_lub_right: forall x y, ge (lub x y) y.
+ Proof.
+ unfold ge; destruct x, y; simpl; split.
+ apply NE.ge_lub_right.
+ intros; apply nlive_lub_r; auto.
+ Qed.
+
+End NA.
+