Module NoError


Require Import
  Utf8 Coqlib Util
  AST Globalenvs Maps
  Values Memory Integers Floats
  Cminor
  Csharpminor.

Set Implicit Arguments.

Section EEI.
Context (ge: genv) (e: env) (t: temp_env) (m: Mem.mem).

Lemma eval_expr_Evar_inv id v :
  eval_expr ge e t m (Evar id) v
  t ! id = Some v.
Proof.
inversion 1; auto. Qed.

Lemma eval_expr_Econst_inv c v :
  eval_expr ge e t m (Econst c) v
  eval_constant c = Some v.
Proof.
inversion 1; auto. Qed.

Lemma eval_expr_Eaddrof_inv id v :
  eval_expr ge e t m (Eaddrof id) v
  ∃ b, eval_var_addr ge e id bv = Vptr b Int.zero.
Proof.
inversion 1; vauto. Qed.

Lemma eval_expr_Eunop_inv op a v :
  eval_expr ge e t m (Eunop op a) v
  ∃ v', eval_expr ge e t m a v' ∧
        eval_unop op v' = Some v.
Proof.
  inversion 1. vauto.
Qed.

Lemma eval_expr_Ebinop_inv op a1 a2 v :
  eval_expr ge e t m (Ebinop op a1 a2) v
  ∃ v1 v2,
    eval_expr ge e t m a1 v1
    eval_expr ge e t m a2 v2
    eval_binop op v1 v2 m = Some v.
Proof.
  inversion 1. vauto.
Qed.

Lemma eval_expr_Eload_inv κ a v :
  eval_expr ge e t m (Eload κ a) v
  ∃ v', eval_expr ge e t m a v' ∧ Mem.loadv κ m v' = Some v.
Proof.
inversion 1; vauto. Qed.

End EEI.

Ltac eval_expr_inv :=
  repeat
  match goal with
  | H : eval_expr _ _ _ _ (Evar _) _ |- _ =>
    apply eval_expr_Evar_inv in H
  | H : eval_expr _ _ _ _ (Eaddrof _) _ |- _ =>
    apply eval_expr_Eaddrof_inv in H;
    let b := fresh "b" in
    let EQ := fresh "EQ" in
    destruct H as (b & H & EQ)
  | H : eval_expr _ _ _ _ (Econst _) _ |- _ =>
    apply eval_expr_Econst_inv in H
  | H : eval_expr _ _ _ _ (Eunop _ _) _ |- _ =>
    apply eval_expr_Eunop_inv in H;
    let v1 := fresh "v1" in
    destruct H as (v1 & ? & H)
  | H : eval_expr _ _ _ _ (Ebinop _ _ _) _ |- _ =>
    apply eval_expr_Ebinop_inv in H;
    let v1 := fresh "v1" in
    let v2 := fresh "v2" in
    destruct H as (v1 & v2 & ? & ? & H)
  | H : eval_expr _ _ _ _ (Eload _ _) _ |- _ =>
    apply eval_expr_Eload_inv in H;
    let v1 := fresh "v1" in
    destruct H as (v1 & ? & H)
  end.

Section GE.

Context (ge: genv) (e: env) (t: temp_env) (m: Mem.mem).

Let valid_ptr : blockZbool := Mem.valid_pointer m.
Let weak_valid_ptr := λ b ofs, valid_ptr b ofs || valid_ptr b (ofs - 1).

Section B.
Local Unset Elimination Schemes.
Definition i_unop : unary_operationProp :=
  λ o, match o with
       | Ocast8unsigned
       | Ocast16unsigned
       | Ocast8signed
       | Ocast16signed
       | Onegint
       | Onotint
       | Ofloatofint
       | Ofloatofintu
       | Osingleofint
       | Osingleofintu
       | Olongofint
       | Olongofintu => True
       | _ => False
       end.

Definition f_unop : unary_operationProp :=
  λ o, match o with
       | Onegf
       | Oabsf
       | Osingleoffloat
       | Ointoffloat
       | Ointuoffloat
       | Olongoffloat
       | Olonguoffloat
         => True
       | _ => False
       end.

Definition s_unop : unary_operationProp :=
  λ o, match o with
       | Onegfs
       | Oabsfs
       | Ofloatofsingle
       | Ointofsingle
       | Ointuofsingle
       | Olongofsingle
       | Olonguofsingle
         => True
       | _ => False
       end.

Definition l_unop : unary_operationProp :=
  λ o, match o with
       | Ointoflong
       | Ofloatoflong
       | Ofloatoflongu
       | Osingleoflong
       | Osingleoflongu
       | Onegl
       | Onotl
         => True
       | _ => False
       end.

Inductive error_unop : unary_operationvalProp :=
| error_int o v :
    match v with Vint _ => False | _ => True end
    i_unop o
    error_unop o v
| error_float o v :
    match v with Vfloat _ => False | _ => True end
    f_unop o
    error_unop o v
| error_single o v :
    match v with Vsingle _ => False | _ => True end
    s_unop o
    error_unop o v
| error_long o v :
    match v with Vlong _ => False | _ => True end
    l_unop o
    error_unop o v
| error_Ointoffloat f :
    Float.to_int f = None
    error_unop Ointoffloat (Vfloat f)
| error_Ointuoffloat f :
    Float.to_intu f = None
    error_unop Ointuoffloat (Vfloat f)
| error_Olongoffloat f :
    Float.to_long f = None
    error_unop Olongoffloat (Vfloat f)
| error_Olonguoffloat f :
    Float.to_longu f = None
    error_unop Olonguoffloat (Vfloat f)
| error_Ointofsingle f :
    Float32.to_int f = None
    error_unop Ointofsingle (Vsingle f)
| error_Ointuofsingle f :
    Float32.to_intu f = None
    error_unop Ointuofsingle (Vsingle f)
| error_Olongofsingle f :
    Float32.to_long f = None
    error_unop Olongofsingle (Vsingle f)
| error_Olonguofsingle f :
    Float32.to_longu f = None
    error_unop Olonguofsingle (Vsingle f)
.

Inductive error_binop : binary_operationvalvalProp :=
| error_Oadd v w :
    match v, w with
      | Vint _, (Vint _ | Vptr _ _)
      | Vptr _ _, Vint _
        => False
      | _, _ => True
    end
    error_binop Oadd v w
| error_Osub v w :
    match v, w with
      | (Vint _ | Vptr _ _), Vint _ => False
      | Vptr b _, Vptr b' _ => bb'
      | _, _ => True
    end
    error_binop Osub v w
| error_int_int o v w :
    match v, w with
      | Vint _, Vint _ => False
      | _, _ => True
    end
    match o with
    | Omul | Oand | Oor | Oxor | Odiv | Odivu | Omod | Omodu | Oshl | Oshr | Oshru | Ocmp _ => True
    | _ => False
    end
    error_binop o v w
| error_float_float o v w :
    match v, w with
      | Vfloat _, Vfloat _ => False
      | _, _ => True
    end
    match o with Oaddf | Osubf | Omulf | Odivf | Ocmpf _ => True | _ => False end
    error_binop o v w
| error_single_single o v w :
    match v, w with
      | Vsingle _, Vsingle _ => False
      | _, _ => True
    end
    match o with Oaddfs | Osubfs | Omulfs | Odivfs | Ocmpfs _ => True | _ => False end
    error_binop o v w
| error_long_long o v w :
    match v, w with
    | Vlong _, Vlong _ => False
    | _, _ => True
    end
    match o with
    | Oaddl | Osubl | Omull | Oandl | Oorl | Oxorl
    | Odivl | Odivlu | Omodl | Omodlu | Ocmpl _ | Ocmplu _ => True
    | _ => False end
    error_binop o v w
| error_long_int o v w :
    match v, w with
      | Vlong _, Vint _ => False
      | _, _ => True
    end
    match o with Oshll | Oshrl | Oshrlu => True | _ => False end
    error_binop o v w
| error_Odiv_zero o i :
    match o with Odiv | Omod => True | _ => False end
    error_binop o (Vint i) (Vint Int.zero)
| error_Odiv_min_s o :
    match o with Odiv | Omod => True | _ => False end
    error_binop o (Vint (Int.repr Int.min_signed)) (Vint Int.mone)
| error_Odivu_zero o i :
    match o with Odivu | Omodu => True | _ => False end
    error_binop o (Vint i) (Vint Int.zero)
| error_Oshift o i j :
    Int.ltu j Int.iwordsize = false
    match o with Oshl | Oshr | Oshru => True | _ => False end
    error_binop o (Vint i) (Vint j)
| error_Odivl_zero o l :
    match o with Odivl | Omodl => True | _ => False end
    error_binop o (Vlong l) (Vlong Int64.zero)
| error_Odivl_min_s o :
    match o with Odivl | Omodl => True | _ => False end
    error_binop o (Vlong (Int64.repr Int64.min_signed)) (Vlong Int64.mone)
| error_Odivlu_zero o l :
    match o with Odivlu | Omodlu => True | _ => False end
    error_binop o (Vlong l) (Vlong Int64.zero)
| error_Oshiftl o l i :
    Int.ltu i Int64.iwordsize' = false
    match o with Oshll | Oshrl | Oshrlu => True | _ => False end
    error_binop o (Vlong l) (Vint i)
| error_Ocmpu c v w :
    match v, w with
      | Vint _, Vint _
      | Vint _, Vptr _ _
      | Vptr _ _, Vint _
      | Vptr _ _, Vptr _ _
        => False
      | _, _ => True
    end
    error_binop (Ocmpu c) v w
| error_Ocmpu_ip_z c i b j :
    Int.eq i Int.zero = false
    error_binop (Ocmpu c) (Vint i) (Vptr b j)
| error_Ocmpu_ip_invalid c i b j :
    weak_valid_ptr b (Int.unsigned j) = false
    error_binop (Ocmpu c) (Vint i) (Vptr b j)
| error_Ocmpu_ip_cmp c i b j :
    match c with Ceq | Cne => False | _ => True end
    error_binop (Ocmpu c) (Vint i) (Vptr b j)
| error_Ocmpu_pi_z c i b j :
    Int.eq i Int.zero = false
    error_binop (Ocmpu c) (Vptr b j) (Vint i)
| error_Ocmpu_pi_invalid c i b j :
    weak_valid_ptr b (Int.unsigned j) = false
    error_binop (Ocmpu c) (Vptr b j) (Vint i)
| error_Ocmpu_pi_cmp c i b j :
    match c with Ceq | Cne => False | _ => True end
    error_binop (Ocmpu c) (Vptr b j) (Vint i)
| error_Ocmpu_pp_cmp c b i b' i' :
    match c with Ceq | Cne => False | _ => True end
    bb' →
    error_binop (Ocmpu c) (Vptr b i) (Vptr b' i')
| error_Ocmpu_pp_invalid c b i b' i' :
    bb' →
    valid_ptr b (Int.unsigned i) = false
    valid_ptr b' (Int.unsigned i') = false
    error_binop (Ocmpu c) (Vptr b i) (Vptr b' i')
| error_Ocmpu_pp_winvalid c b i i' :
    weak_valid_ptr b (Int.unsigned i) = false
    weak_valid_ptr b (Int.unsigned i') = false
    error_binop (Ocmpu c) (Vptr b i) (Vptr b i')
.

Inductive error_load (κ: memory_chunk) : valProp :=
| error_load_not_ptr v :
    match v with Vptr _ _ => False | _ => True end
    error_load κ v
| error_load_None b i :
    Mem.load κ m b (Int.unsigned i) = None
    error_load κ (Vptr b i)
| error_load_undef b i :
    Mem.load κ m b (Int.unsigned i) = Some Vundef
    error_load κ (Vptr b i)
.

End B.

Inductive error_expr : exprProp :=
| error_Evar_None i :
    t ! i = None
    error_expr (Evar i)
| error_Evar_Vundef i :
    t ! i = Some Vundef
    error_expr (Evar i)
| error_Eaddrof i :
    e ! i = None
    Genv.find_symbol ge i = None
    error_expr (Eaddrof i)
| error_Eunop u q v :
    eval_expr ge e t m q v
    error_unop u v
    error_expr (Eunop u q)
| error_Eunop_rec u q :
    error_expr q
    error_expr (Eunop u q)
| error_Ebinop b q r v w :
    eval_expr ge e t m q v
    eval_expr ge e t m r w
    error_binop b v w
    error_expr (Ebinop b q r)
| error_Ebinop_rec_l b q r :
    error_expr q
    error_expr (Ebinop b q r)
| error_Ebinop_rec_r b q r v :
    eval_expr ge e t m q v
    error_expr r
    error_expr (Ebinop b q r)
| error_Eload κ q v :
    eval_expr ge e t m q v
    error_load κ v
    error_expr (Eload κ q)
| error_Eload_rec κ q :
    error_expr q
    error_expr (Eload κ q)
.

Lemma error_expr_Unop_inv u q :
  error_expr (Eunop u q) →
  (∃ v, eval_expr ge e t m q verror_unop u v)
∨ (error_expr q).
Proof.
inversion 1; vauto. Qed.

Lemma error_expr_Binop_inv b q r :
  error_expr (Ebinop b q r) →
  (∃ v w, eval_expr ge e t m q veval_expr ge e t m r werror_binop b v w)
∨ (error_expr q)
∨ (∃ v, eval_expr ge e t m q verror_expr r).
Proof.
inversion 1; vauto. Qed.

Lemma error_expr_Load_inv κ q :
  error_expr (Eload κ q) →
  (∃ v, eval_expr ge e t m q verror_load κ v)
∨ (error_expr q).
Proof.
inversion 1; vauto. Qed.

Lemma val_cmp_ii_def c i j :
  Val.cmp c (Vint i) (Vint j) = VundefFalse.
Proof.
unfold Val.cmp. simpl. destruct Int.cmp; discriminate. Qed.
Lemma val_cmpf_ff_def c f g :
  Val.cmpf c (Vfloat f) (Vfloat g) = VundefFalse.
Proof.
unfold Val.cmpf. simpl. destruct Float.cmp; discriminate. Qed.
Lemma val_cmpfs_ss_def c f g :
  Val.cmpfs c (Vsingle f) (Vsingle g) = VundefFalse.
Proof.
unfold Val.cmpfs. simpl. destruct Float32.cmp; discriminate. Qed.
Lemma val_of_bool_def b :
  Val.of_bool b = VundefFalse.
Proof.
destruct b; discriminate. Qed.
Hint Resolve val_cmp_ii_def val_cmpf_ff_def val_cmpfs_ss_def val_of_bool_def.

Lemma noerror_def (q: expr) :
  ¬ error_expr q
  ∀ v, eval_expr ge e t m q vvVundef.
Proof.
  induction q; intros NB; intros v EVAL ->;
  eval_expr_inv; try (elim NB; vauto; discriminate).
+ destruct c; simpl in *; eq_some_inv; discriminate.
+ asserterror_expr q) as NB'.
  { intros K; elim NB; vauto. }
  repeat match goal with
  | H : _ , K : __ |- _ => specialize (K H)
  end.
  destruct u; simpl in *; eq_some_inv;
  destruct v1; simpl in *; auto;
  try (elim NB; vauto2);
  try discriminate;
  try (match goal with
  | H : context[ Ointoffloat ] |- _ => destruct (Float.to_int f) eqn: EQ
  | H : context[ Ointuoffloat ] |- _ => destruct (Float.to_intu f) eqn: EQ
  | H : context[ Olongoffloat ] |- _ => destruct (Float.to_long f) eqn: EQ
  | H : context[ Olonguoffloat ] |- _ => destruct (Float.to_longu f) eqn: EQ
  | H : context[ Ointofsingle ] |- _ => destruct (Float32.to_int f) eqn: EQ
  | H : context[ Ointuofsingle ] |- _ => destruct (Float32.to_intu f) eqn: EQ
  | H : context[ Olongofsingle ] |- _ => destruct (Float32.to_long f) eqn: EQ
  | H : context[ Olonguofsingle ] |- _ => destruct (Float32.to_longu f) eqn: EQ
   end;[simpl in *; eq_some_inv; discriminate|elim NB; vauto; fail]).

+ asserterror_expr q1) as NB1. { intros K; elim NB; vauto. }
  asserterror_expr q2) as NB2. { intros K; elim NB; vauto. }
  repeat match goal with
  | H : _ , K : __ |- _ => specialize (K H)
  end.
  destruct b; simpl in *; eq_some_inv;
  destruct v1; try (exact (IHq1 eq_refl));
  try (elim NB; vauto; fail);
  destruct v2; try (exact (IHq2 eq_refl));
  try (elim NB; vauto; fail);
  eauto;
  try discriminate;
  simpl in *;
  try (* shifts *)
  (destruct (Int.ltu i0 Int.iwordsize) eqn:?;
  [discriminate| elim NB; vauto; fail]);
  try (* shifts long *)
  (destruct (Int.ltu i0 Int64.iwordsize') eqn:?;
  [discriminate| elim NB; vauto; fail]).
- (* sub *)
  destruct (eq_block b b0) as [ ? | NE ]. discriminate.
  elim NB. vauto.
- (* div *)
  destruct (Int.eq i0 Int.zero); simpl in *. eq_some_inv.
  destruct (Int.eq i (Int.repr Int.min_signed)).
  destruct (Int.eq i0 Int.mone);
  simpl in *; eq_some_inv.
  discriminate.
  simpl in *; eq_some_inv; discriminate.
- (* divu *)
  destruct (Int.eq i0 Int.zero); simpl in *; eq_some_inv.
  discriminate.
- (* mod *) (* same script as div *)
  destruct (Int.eq i0 Int.zero); simpl in *. eq_some_inv.
  destruct (Int.eq i (Int.repr Int.min_signed)).
  destruct (Int.eq i0 Int.mone);
  simpl in *; eq_some_inv.
  discriminate.
  simpl in *; eq_some_inv; discriminate.
- (* modu *) (* same as divu *)
  destruct (Int.eq i0 Int.zero); simpl in *; eq_some_inv.
  discriminate.
- (* divl *)
  destruct (Int64.eq i0 Int64.zero); simpl in *. eq_some_inv.
  destruct (Int64.eq i (Int64.repr Int64.min_signed)).
  destruct (Int64.eq i0 Int64.mone);
  simpl in *; eq_some_inv.
  discriminate.
  simpl in *; eq_some_inv; discriminate.
- (* divlu *)
  destruct (Int64.eq i0 Int64.zero); simpl in *; eq_some_inv.
  discriminate.
- (* modl *) (* same as divl *)
  destruct (Int64.eq i0 Int64.zero); simpl in *. eq_some_inv.
  destruct (Int64.eq i (Int64.repr Int64.min_signed)).
  destruct (Int64.eq i0 Int64.mone);
  simpl in *; eq_some_inv.
  discriminate.
  simpl in *; eq_some_inv; discriminate.
- (* modlu *) (* same as divlu *)
  destruct (Int64.eq i0 Int64.zero); simpl in *; eq_some_inv.
  discriminate.
- (* cmpu i i *)
  simpl in EVAL.
  unfold Val.cmpu in *. simpl in *. destruct Int.cmpu; discriminate.
- (* cmpu i p *)
  unfold Val.cmpu in *. simpl in *.
  destruct (Int.eq i Int.zero &&
             (Mem.valid_pointer m b (Int.unsigned i0)
           || Mem.valid_pointer m b (Int.unsigned i0 - 1))) eqn: Z.
  destruct c; try discriminate;
  elim NB; vauto.
  elim NB. rewrite Bool.andb_false_iff in Z. destruct Z; vauto.
- (* cmpu p i *)
  unfold Val.cmpu in *. simpl in *.
  destruct (Int.eq i0 Int.zero &&
             (Mem.valid_pointer m b (Int.unsigned i)
           || Mem.valid_pointer m b (Int.unsigned i - 1))) eqn: Z.
  destruct c; try discriminate;
  elim NB; vauto.
  elim NB. rewrite Bool.andb_false_iff in Z. destruct Z; vauto.
- (* cmpu p p *)
  assert (∀ b : bool, (if b then Vtrue else Vfalse) ≠ Vundef) as K.
  { intros (); discriminate. }
  unfold Val.cmpu in *. simpl in *.
  destruct (eq_block b b0). subst b0.
  destruct (Mem.valid_pointer _ _ (Int.unsigned i)) eqn:Hi;
  simpl in *.
  destruct (Mem.valid_pointer _ _ (Int.unsigned i0)) eqn:Hi0;
  simpl in *. eauto.
  destruct (Mem.valid_pointer _ _ (Int.unsigned i0 - 1)) eqn:Hi0';
  simpl in *. eauto.
  apply NB. eapply error_Ebinop; eauto.
  apply error_Ocmpu_pp_winvalid; unfold weak_valid_ptr, valid_ptr.
  right; rewrite Hi0, Hi0'; reflexivity.
  destruct (Mem.valid_pointer _ _ (Int.unsigned i - 1)) eqn:Hi';
  simpl in *.
  destruct (Mem.valid_pointer _ _ (Int.unsigned i0)) eqn:Hi0;
  simpl in *. eauto.
  destruct (Mem.valid_pointer _ _ (Int.unsigned i0 - 1)) eqn:Hi0';
  simpl in *. eauto.
  apply NB. eapply error_Ebinop; eauto.
  apply error_Ocmpu_pp_winvalid; unfold weak_valid_ptr, valid_ptr.
  right; rewrite Hi0, Hi0'; reflexivity.
  apply NB. eapply error_Ebinop; eauto.
  apply error_Ocmpu_pp_winvalid; unfold weak_valid_ptr, valid_ptr.
  left; rewrite Hi, Hi'; reflexivity.
  destruct (Mem.valid_pointer _ _ (Int.unsigned i)) eqn:Hi;
  simpl in *.
  destruct (Mem.valid_pointer _ _ (Int.unsigned i0)) eqn:Hi0;
  simpl in *.
  destruct c; try discriminate; apply NB; vauto; fail.
  apply NB; vauto.
  apply NB; vauto.
- (* cmpl *)
  unfold Val.cmpl in *.
  destruct c; simpl in *; eq_some_inv; eauto.
- (* cmplu *)
  unfold Val.cmplu in *.
  destruct c; simpl in *; eq_some_inv; eauto.

+ (* load *)
  asserterror_expr q) as NB'.
  { intros K; elim NB; vauto. }
  repeat match goal with
  | H : _ , K : __ |- _ => specialize (K H)
  end.
  destruct v1; try (elim NB; vauto; fail).
Qed.

Lemma noerror_eval_expr (q: expr) :
  ¬ error_expr q
  ∃ v, eval_expr ge e t m q v.
Proof.
  induction q; intros NB.
+ destruct (t ! i) as [v|] eqn:?. vauto.
  elim NB; vauto.
+ destruct (e ! i) as [(b,o)|] eqn:?. vauto2.
  destruct (Genv.find_symbol ge i) as [b|] eqn: ?. vauto2.
  elim NB. vauto.
+ destruct c; vauto2.

+ asserterror_expr q) as NB'.
  { intros K; elim NB; vauto. }
  specialize (IHq NB'); clear NB'.
  destruct IHq as (v & EV).
  destruct u; try vauto2;
  destruct v; try (elim NB; vauto2);
  try
  (match goal with
   | H : context[ Ointoffloat ] |- _ => destruct (Float.to_int f) eqn: EQ
   | H : context[ Ointuoffloat ] |- _ => destruct (Float.to_intu f) eqn: EQ
   | H : context[ Olongoffloat ] |- _ => destruct (Float.to_long f) eqn: EQ
   | H : context[ Olonguoffloat ] |- _ => destruct (Float.to_longu f) eqn: EQ
   | H : context[ Ointofsingle ] |- _ => destruct (Float32.to_int f) eqn: EQ
   | H : context[ Ointuofsingle ] |- _ => destruct (Float32.to_intu f) eqn: EQ
   | H : context[ Olongofsingle ] |- _ => destruct (Float32.to_long f) eqn: EQ
   | H : context[ Olonguofsingle ] |- _ => destruct (Float32.to_longu f) eqn: EQ
   end;[|elim NB; vauto; fail]);
   try (eexists; econstructor; eauto; simpl; try rewrite EQ; reflexivity).

+ asserterror_expr q1) as NB1. { intros K; elim NB; vauto. }
  specialize (IHq1 NB1); clear NB1.
  destruct IHq1 as (v1 & V1).
  asserterror_expr q2) as NB2. { intros K; elim NB; vauto. }
  specialize (IHq2 NB2); clear NB2.
  destruct IHq2 as (v2 & V2).

  destruct b; try vauto2;
  destruct v1; try (elim NB; vauto; fail);
  destruct v2; try (elim NB; vauto; fail).

  - (* div *)
    generalize (Int.eq_spec i0 Int.zero).
    destruct (Int.eq i0 Int.zero) eqn: Z.
    intros ->. elim NB. vauto.
    intros _.
    generalize (Int.eq_spec i (Int.repr Int.min_signed)).
    destruct (Int.eq i (Int.repr Int.min_signed)) eqn: MS.
    intros ->.
    generalize (Int.eq_spec i0 Int.mone).
    destruct (Int.eq i0 Int.mone) eqn: M1.
    intros ->. elim NB. vauto.
    intros _.
    eexists. econstructor; try eassumption.
    simpl; rewrite Z, MS, M1; reflexivity.
    intros _.
    eexists. econstructor; try eassumption.
    simpl; rewrite Z, MS; reflexivity.
  - (* divu *)
    generalize (Int.eq_spec i0 Int.zero).
    destruct (Int.eq i0 Int.zero) eqn: Z.
    intros ->. elim NB. vauto.
    intros _.
    eexists. econstructor; try eassumption.
    simpl; rewrite Z; reflexivity.
  - (* mod *) (* same as div *)
    generalize (Int.eq_spec i0 Int.zero).
    destruct (Int.eq i0 Int.zero) eqn: Z.
    intros ->. elim NB. vauto.
    intros _.
    generalize (Int.eq_spec i (Int.repr Int.min_signed)).
    destruct (Int.eq i (Int.repr Int.min_signed)) eqn: MS.
    intros ->.
    generalize (Int.eq_spec i0 Int.mone).
    destruct (Int.eq i0 Int.mone) eqn: M1.
    intros ->. elim NB. vauto.
    intros _.
    eexists. econstructor; try eassumption.
    simpl; rewrite Z, MS, M1; reflexivity.
    intros _.
    eexists. econstructor; try eassumption.
    simpl; rewrite Z, MS; reflexivity.
  - (* modu *) (* same as divu *)
    generalize (Int.eq_spec i0 Int.zero).
    destruct (Int.eq i0 Int.zero) eqn: Z.
    intros ->. elim NB. vauto.
    intros _.
    eexists. econstructor; try eassumption.
    simpl; rewrite Z; reflexivity.
  - (* divl *)
    generalize (Int64.eq_spec i0 Int64.zero).
    destruct (Int64.eq i0 Int64.zero) eqn: Z.
    intros ->. elim NB. vauto.
    intros _.
    generalize (Int64.eq_spec i (Int64.repr Int64.min_signed)).
    destruct (Int64.eq i (Int64.repr Int64.min_signed)) eqn: MS.
    intros ->.
    generalize (Int64.eq_spec i0 Int64.mone).
    destruct (Int64.eq i0 Int64.mone) eqn: M1.
    intros ->. elim NB. vauto.
    intros _.
    eexists. econstructor; try eassumption.
    simpl; rewrite Z, MS, M1; reflexivity.
    intros _.
    eexists. econstructor; try eassumption.
    simpl; rewrite Z, MS; reflexivity.
  - (* divlu *)
    generalize (Int64.eq_spec i0 Int64.zero).
    destruct (Int64.eq i0 Int64.zero) eqn: Z.
    intros ->. elim NB. vauto.
    intros _.
    eexists. econstructor; try eassumption.
    simpl; rewrite Z; reflexivity.
  - (* modl *) (* same as divl *)
    generalize (Int64.eq_spec i0 Int64.zero).
    destruct (Int64.eq i0 Int64.zero) eqn: Z.
    intros ->. elim NB. vauto.
    intros _.
    generalize (Int64.eq_spec i (Int64.repr Int64.min_signed)).
    destruct (Int64.eq i (Int64.repr Int64.min_signed)) eqn: MS.
    intros ->.
    generalize (Int64.eq_spec i0 Int64.mone).
    destruct (Int64.eq i0 Int64.mone) eqn: M1.
    intros ->. elim NB. vauto.
    intros _.
    eexists. econstructor; try eassumption.
    simpl; rewrite Z, MS, M1; reflexivity.
    intros _.
    eexists. econstructor; try eassumption.
    simpl; rewrite Z, MS; reflexivity.
  - (* modlu *) (* same as divlu *)
    generalize (Int64.eq_spec i0 Int64.zero).
    destruct (Int64.eq i0 Int64.zero) eqn: Z.
    intros ->. elim NB. vauto.
    intros _.
    eexists. econstructor; try eassumption.
    simpl; rewrite Z; reflexivity.
  - (* cmpl *)
    econstructor. econstructor; eauto. reflexivity.
  - (* cmplu *)
    econstructor. econstructor; eauto. reflexivity.

+ (* load *)
  asserterror_expr q) as NB'.
  { intros K; elim NB; vauto. }
  specialize (IHq NB'); clear NB'.
  destruct IHq as (v & EV).
  destruct v; try (elim NB; vauto; fail).
  destruct (Mem.load m0 m b (Int.unsigned i)) as [v|] eqn:?.
  vauto.
  elim NB; vauto.
Qed.

Corollary noerror_eval_expr_def (q: expr) :
  ¬ error_expr q
  ∃ v, vVundefeval_expr ge e t m q v.
Proof.
  intros NB.
  destruct (noerror_eval_expr NB) as (v & EV).
  exists v. eauto using noerror_def.
Qed.

Section PE.

  Require Import PExpr.

  Context (var: Type) (ρ: varval) (ε: identoption block).

  Let eval_pexpr := eval_pexpr ge m ρ ε.

  Definition error_pbinop b v w :=
    match b, v, w with
    | Ocmpu _, Vptr _ _, Vint _
    | Ocmpu _, Vint _, Vptr _ _ => True
    | Ocmpu _, Vptr p i, Vptr q j =>
      pqMem.weak_valid_pointer m p (Int.unsigned i) || Mem.weak_valid_pointer m q (Int.unsigned j) = false
    | _, _, _ => error_binop b v w
    end.

  Fixpoint error_pexpr (pe: pexpr var) : Prop :=
    match pe with
    | PEvar i _ => ρ(i) = Vundef
    | PElocal i => ε(i) = None
    | PEconst (Some (Oaddrsymbol s _)) _ =>
      Genv.find_symbol ge s = None
    | PEunop u q _ =>
      error_pexpr q ∨ ∃ v, eval_pexpr q verror_unop u v
    | PEbinop b q r _ =>
      error_pexpr q
      ∃ v, eval_pexpr q v
      (error_pexpr r
       ∃ w, eval_pexpr r w
            error_binop b v w)
    | _ => False
    end.

  Lemma error_pexpr_def (pe: pexpr var) :
    ¬ error_pexpr pe
    ∀ v, eval_pexpr pe vvVundef.
Proof.
    unfold eval_pexpr.
    induction pe; intros NB ? EV;
    repeat match goal with H : option constant |- _ => destruct H as [()|] end;
    eval_pexpr_inv; subst; intros K; subst; hsplit; try discriminate.
  - apply NB; eauto.
  - simpl in *. apply NB.
    destruct Genv.find_symbol. discriminate. reflexivity.
  - auto.

  - assert ( ¬ error_pexpr pe ) as NB' by (intros ?; elim NB; vauto).
    specialize (IHpe NB'); clear NB'.
    subst. fold (eval_pexpr pe) in *.
    match goal with
    | EV: eval_pexpr _ ?i |- _ =>
      specialize (IHpe i EV)
    end.
    destruct u; simpl in *; eq_some_inv;
    destruct v'; simpl in *; auto;
    try (apply NB; right; eexists; split; [ exact EV | vauto2 ]);
    try discriminate;
    (match goal with
    | H : context[ Ointoffloat ] |- _ => destruct (Float.to_int f) eqn: EQ
    | H : context[ Ointuoffloat ] |- _ => destruct (Float.to_intu f) eqn: EQ
    | H : context[ Olongoffloat ] |- _ => destruct (Float.to_long f) eqn: EQ
    | H : context[ Olonguoffloat ] |- _ => destruct (Float.to_longu f) eqn: EQ
    | H : context[ Ointofsingle ] |- _ => destruct (Float32.to_int f) eqn: EQ
    | H : context[ Ointuofsingle ] |- _ => destruct (Float32.to_intu f) eqn: EQ
    | H : context[ Olongofsingle ] |- _ => destruct (Float32.to_long f) eqn: EQ
    | H : context[ Olonguofsingle ] |- _ => destruct (Float32.to_longu f) eqn: EQ
    end;[simpl in *; eq_some_inv; discriminate|apply NB; right; eexists; split; [ exact EV | vauto2 ]]).

-
  asserterror_pexpr pe1) as NB1. { intros K; elim NB; vauto. }
  asserterror_pexpr pe2) as NB2. { intros K; elim NB; vauto. }
  repeat match goal with
  | H : _, K : __ |- _ => specialize (K H)
  end.
  destruct b; simpl in *; eq_some_inv;
  destruct v₁; try (exact (IHq1 eq_refl));
  try (apply NB; right; eexists; split; [ exact EV | right; eexists; vauto2 ]);
  destruct v₂; try (exact (IHq2 eq_refl));
  try (apply NB; right; eexists; split; [ exact EV | right; eexists; vauto2 ]);
  eauto;
  try discriminate;
  simpl in *;
  try (* shifts *)
  (destruct (Int.ltu i0 Int.iwordsize) eqn:?;
  [discriminate| apply NB; right; eexists; split; [ exact EV | right; eexists; vauto2 ]]);
  try (* shifts long *)
  (destruct (Int.ltu i0 Int64.iwordsize') eqn:?;
  [discriminate| apply NB; right; eexists; split; [ exact EV | right; eexists; vauto2 ]]).
+ (* sub *)
  destruct (eq_block b b0) as [ ? | NE ]. discriminate.
  apply NB; right; eexists; split; [ eauto | right; eexists; split; [ eauto | vauto ] ].
+ (* div *)
  destruct (Int.eq i0 Int.zero); simpl in *. eq_some_inv.
  destruct (Int.eq i (Int.repr Int.min_signed)).
  destruct (Int.eq i0 Int.mone);
  simpl in *; eq_some_inv.
  discriminate.
  simpl in *; eq_some_inv; discriminate.
+ (* divu *)
  destruct (Int.eq i0 Int.zero); simpl in *; eq_some_inv.
  discriminate.
+ (* mod *) (* same script as div *)
  destruct (Int.eq i0 Int.zero); simpl in *. eq_some_inv.
  destruct (Int.eq i (Int.repr Int.min_signed)).
  destruct (Int.eq i0 Int.mone);
  simpl in *; eq_some_inv.
  discriminate.
  simpl in *; eq_some_inv; discriminate.
+ (* modu *) (* same as divu *)
  destruct (Int.eq i0 Int.zero); simpl in *; eq_some_inv.
  discriminate.
+ (* divl *)
  destruct (Int64.eq i0 Int64.zero); simpl in *. eq_some_inv.
  destruct (Int64.eq i (Int64.repr Int64.min_signed)).
  destruct (Int64.eq i0 Int64.mone);
  simpl in *; eq_some_inv.
  discriminate.
  simpl in *; eq_some_inv; discriminate.
+ (* divlu *)
  destruct (Int64.eq i0 Int64.zero); simpl in *; eq_some_inv.
  discriminate.
+ (* modl *) (* same as divl *)
  destruct (Int64.eq i0 Int64.zero); simpl in *. eq_some_inv.
  destruct (Int64.eq i (Int64.repr Int64.min_signed)).
  destruct (Int64.eq i0 Int64.mone);
  simpl in *; eq_some_inv.
  discriminate.
  simpl in *; eq_some_inv; discriminate.
+ (* modlu *) (* same as divlu *)
  destruct (Int64.eq i0 Int64.zero); simpl in *; eq_some_inv.
  discriminate.
+ (* cmpu i i *)
  unfold Val.cmpu in *. simpl in *. destruct Int.cmpu; discriminate.
+ (* cmpu i p *)
  unfold Val.cmpu in *. simpl in *.
  destruct (Int.eq i Int.zero &&
             (Mem.valid_pointer m b (Int.unsigned i0)
           || Mem.valid_pointer m b (Int.unsigned i0 - 1))) eqn: Z.
  destruct c; try discriminate;
  elim NB; right; eexists; split; eauto; right; eexists; split; eauto; vauto.
  elim NB; right; eexists; split; eauto; right; eexists; split; eauto.
  rewrite Bool.andb_false_iff in Z. destruct Z; vauto.
+ (* cmpu p i *)
  unfold Val.cmpu in *. simpl in *.
  destruct (Int.eq i0 Int.zero &&
             (Mem.valid_pointer m b (Int.unsigned i)
           || Mem.valid_pointer m b (Int.unsigned i - 1))) eqn: Z.
  destruct c; try discriminate;
  elim NB; right; eexists; split; eauto; right; eexists; split; eauto; vauto.
  elim NB; right; eexists; split; eauto; right; eexists; split; eauto.
  rewrite Bool.andb_false_iff in Z. destruct Z; vauto.
+ (* cmpu p p *)
  apply NB. right. eexists; split; eauto. right. eexists; split; eauto.
  unfold Val.cmpu in *. simpl in *.
  revert H0.
  bif; bif'.
  destruct (Int.cmpu _ _ _); discriminate. intros _.
  subst. apply error_Ocmpu_pp_winvalid.
  rewrite andb_false_iff in *. assumption.
  destruct c; try discriminate; vauto.
  intros _.
  apply error_Ocmpu_pp_invalid; auto.
  rewrite andb_false_iff in *. assumption.
+ (* cmpl *)
  unfold Val.cmpl in *.
  destruct c; simpl in *; eq_some_inv; eauto.
+ (* cmplu *)
  unfold Val.cmplu in *.
  destruct c; simpl in *; eq_some_inv; eauto.
  Qed.

End PE.

End GE.