Require Import Coqlib.
Require Import AST.
Require Import Integers.
Require Import Floats.
Require Import Values.
Require Import Ctypes.
Require Import Cop.
Require Import Footprint Memory MemOpFP ValFP.
Local Notation locset := 
Locs.t.
Local Notation empls := 
Locs.emp.
Local Notation footprint := 
FP.t.
Local Notation empfp := 
FP.emp.
Local Notation FP := 
FP.Build_t.
Instrument C operations with footprints 
 Semantic with memory read/writes 
Definition sem_cast_fp (
v:
val) (
t1 t2: 
type) (
m: 
mem): 
option footprint :=
  
match classify_cast t1 t2 with
  | 
cast_case_pointer =>
    
match v with
    | 
Vint _ => 
if Archi.ptr64 then None else Some empfp
    | 
Vlong _ => 
if Archi.ptr64 then Some empfp else None
    | 
Vptr _ _ => 
Some empfp
    | 
_ => 
None
    end
  | 
cast_case_i2i _ _ =>
    
match v with
    | 
Vint _ => 
Some empfp
    | 
_ => 
None
    end
  | 
cast_case_f2f =>
    
match v with
    | 
Vfloat _ => 
Some empfp
    | 
_ => 
None
    end
  | 
cast_case_s2s =>
    
match v with
    | 
Vsingle _ => 
Some empfp
    | 
_ => 
None
    end
  | 
cast_case_f2s =>
    
match v with
    | 
Vfloat _ => 
Some empfp
    | 
_ => 
None
    end
  | 
cast_case_s2f =>
    
match v with
    | 
Vsingle _ => 
Some empfp
    | 
_ => 
None
    end
  | 
cast_case_i2f _ =>
    
match v with
    | 
Vint _ => 
Some empfp
    | 
_ => 
None
    end
  | 
cast_case_i2s _ =>
    
match v with
    | 
Vint _ => 
Some empfp
    | 
_ => 
None
    end
  | 
cast_case_f2i sz2 si2 =>
    
match v with
    | 
Vfloat f =>
      
match cast_float_int si2 f with
      | 
Some _ => 
Some empfp
      | 
None => 
None
      end
    | 
_ => 
None
    end
  | 
cast_case_s2i sz2 si2 =>
    
match v with
    | 
Vsingle f =>
      
match cast_single_int si2 f with
      | 
Some _ => 
Some empfp
      | 
None => 
None
      end
    | 
_ => 
None
    end
  | 
cast_case_l2l =>
    
match v with
    | 
Vlong _ => 
Some empfp
    | 
_ => 
None
    end
  | 
cast_case_i2l _ =>
    
match v with
    | 
Vint _ => 
Some empfp
    | 
_ => 
None
    end
  | 
cast_case_l2i _ _ =>
    
match v with
    | 
Vlong _ => 
Some empfp
    | 
_ => 
None
    end
  | 
cast_case_l2f _ =>
    
match v with
    | 
Vlong _ => 
Some empfp
    | 
_ => 
None
    end
  | 
cast_case_l2s _ =>
    
match v with
    | 
Vlong _ => 
Some empfp
    | 
_ => 
None
    end
  | 
cast_case_f2l si2 =>
    
match v with
    | 
Vfloat f =>
      
match cast_float_long si2 f with
      | 
Some _ => 
Some empfp
      | 
None => 
None
      end
    | 
_ => 
None
    end
  | 
cast_case_s2l si2 =>
    
match v with
    | 
Vsingle f =>
      
match cast_single_long si2 f with
      | 
Some i => 
Some empfp
      | 
None => 
None
      end
    | 
_ => 
None
    end
  | 
cast_case_i2bool =>
    
match v with
    | 
Vptr b ofs =>
      
if Archi.ptr64 then None
      else Some (
weak_valid_pointer_fp m b (
Ptrofs.unsigned ofs))
    | 
Vint n => 
Some empfp
    | 
_ => 
None
    end
  | 
cast_case_l2bool =>
    
match v with
    | 
Vptr b ofs =>
      
if negb Archi.ptr64 then None
      else Some (
weak_valid_pointer_fp m b (
Ptrofs.unsigned ofs))
    | 
Vlong _ => 
Some empfp
    | 
_ => 
None
    end
  | 
cast_case_f2bool =>
    
match v with
    | 
Vfloat _ => 
Some empfp
    | 
_ => 
None
    end
  | 
cast_case_s2bool =>
    
match v with
    | 
Vsingle _ => 
Some empfp
    | 
_ => 
None
    end
  | 
cast_case_struct id1 id2 =>
    
match v with
    | 
Vptr _ _ => 
if ident_eq id1 id2 then Some empfp else None
    | 
_ => 
None
    end
  | 
cast_case_union id1 id2 =>
    
match v with
    | 
Vptr _ _ => 
if ident_eq id1 id2 then Some empfp else None
    | 
_ => 
None
    end
  | 
cast_case_void => 
Some empfp
  | 
case_case_default => 
None
  end.
Definition sem_cast_fp_total (
v:
val) (
t1 t2: 
type) (
m: 
mem): 
footprint :=
  
match classify_cast t1 t2 with
  | 
cast_case_i2bool =>
    
match v with
    | 
Vptr b ofs =>
      
if Archi.ptr64 then empfp
      else (
weak_valid_pointer_fp m b (
Ptrofs.unsigned ofs))
    | 
_ => 
empfp
    end
  | 
cast_case_l2bool =>
    
match v with
    | 
Vptr b ofs =>
      
if negb Archi.ptr64 then empfp
      else (
weak_valid_pointer_fp m b (
Ptrofs.unsigned ofs))
    | 
_ => 
empfp
    end
  | 
_ => 
empfp
  end.
Lemma sem_cast_fp_sem_cast_fp_total:
  
forall v t1 t2 m fp,
    
sem_cast_fp v t1 t2 m = 
Some fp ->
    
sem_cast_fp_total v t1 t2 m = 
fp.
Proof.
Lemma sem_cast_sem_cast_fp:
  
forall v1 ty1 ty2 m v2,
    
sem_cast v1 ty1 ty2 m = 
Some v2 ->
    
exists fp, 
sem_cast_fp v1 ty1 ty2 m = 
Some fp.
Proof.
  unfold sem_cast, 
sem_cast_fp.
  
intros.
  
destruct (
classify_cast ty1 ty2) 
eqn:? ; 
eauto;
    
destruct v1 eqn:? ; 
try congruence; 
eauto;
      
match goal with
      | |- 
context[
match ?
x with _ => 
_ end] => 
destruct x; 
try congruence; 
eauto
      end.
Qed.
 
Lemma sem_cast_sem_cast_fp_total:
  
forall v1 ty1 ty2 m v2,
    
sem_cast v1 ty1 ty2 m = 
Some v2 ->
    
exists fp, 
sem_cast_fp_total v1 ty1 ty2 m = 
fp.
Proof.
Lemma sem_cast_fp_sem_cast:
  
forall v1 ty1 ty2 m fp,
    
sem_cast_fp v1 ty1 ty2 m = 
Some fp ->
    (
exists v2, 
sem_cast v1 ty1 ty2 m = 
Some v2)
    \/ (
exists b ofs, 
v1 = 
Vptr b ofs /\ 
Mem.weak_valid_pointer m b (
Ptrofs.unsigned ofs) = 
false).
Proof.
  unfold sem_cast_fp, 
sem_cast. 
intros.
  
destruct (
classify_cast ty1 ty2) 
eqn:? ; 
eauto;
    
destruct v1 eqn:? ; 
try congruence; 
eauto;
      
match goal with
      | |- 
context[
match ?
x with _ => 
_ end] => 
destruct x eqn:? ; 
try congruence; 
eauto
      end;
      
match goal with
      | |- 
context[
match ?
x with _ => 
_ end] => 
destruct x eqn:? ; 
eauto
      end.
Qed.
 
Lemma sem_cast_casted_fp:
  
forall v ty m,
    
val_casted v ty ->
    
sem_cast v ty ty m = 
Some v ->
    
sem_cast_fp v ty ty m = 
Some empfp.
Proof.
  intros v ty m CASTED CAST.
  
destruct v; 
inversion CASTED; 
subst; 
try (
cbv; 
auto; 
fail);
    
unfold sem_cast_fp, 
sem_cast in *.
  
destruct classify_cast; 
eauto; 
inv CAST.
  
simpl in *. 
rewrite H0. 
auto.
  
simpl in *. 
rewrite H2. 
auto.
  
simpl in *. 
destruct ident_eq; 
auto; 
discriminate.
  
simpl in *. 
destruct ident_eq; 
auto; 
discriminate.
Qed.
 
Interpretation of values as truth values. 
Definition bool_val_fp (
v: 
val) (
t: 
type) (
m: 
mem): 
option footprint :=
  
match classify_bool t with
  | 
bool_case_i =>
    
match v with
    | 
Vptr b ofs =>
      
if Archi.ptr64 then None
      else Some (
weak_valid_pointer_fp m b (
Ptrofs.unsigned ofs))
    | 
Vint n => 
Some empfp
    | 
_ => 
None
    end
  | 
bool_case_l =>
    
match v with
    | 
Vptr b ofs =>
      
if negb Archi.ptr64 then None
      else Some (
weak_valid_pointer_fp m b (
Ptrofs.unsigned ofs))
    | 
Vlong _ => 
Some empfp
    | 
_ => 
None
    end
  | 
bool_case_f =>
    
match v with
    | 
Vfloat _ => 
Some empfp
    | 
_ => 
None
    end
  | 
bool_case_s =>
    
match v with
    | 
Vsingle _ => 
Some empfp
    | 
_ => 
None
    end
  | 
bool_defalt => 
None
  end.
Definition bool_val_fp_total (
v: 
val) (
t: 
type) (
m: 
mem): 
footprint :=
  
match classify_bool t with
  | 
bool_case_i =>
    
match v with
    | 
Vptr b ofs =>
      
if Archi.ptr64 then empfp
      else (
weak_valid_pointer_fp m b (
Ptrofs.unsigned ofs))
    | 
_ => 
empfp
    end
  | 
bool_case_l =>
    
match v with
    | 
Vptr b ofs =>
      
if negb Archi.ptr64 then empfp
      else (
weak_valid_pointer_fp m b (
Ptrofs.unsigned ofs))
    | 
_ => 
empfp
    end
  | 
_ => 
empfp
  end.
Lemma bool_val_fp_bool_val_fp_total:
  
forall v t m fp,
    
bool_val_fp v t m = 
Some fp ->
    
bool_val_fp_total v t m = 
fp.
Proof.
Lemma bool_val_bool_val_fp:
  
forall v t m b,
    
bool_val v t m = 
Some b ->
    
exists fp, 
bool_val_fp v t m = 
Some fp.
Proof.
Lemma bool_val_bool_val_fp_total:
  
forall v t m b,
    
bool_val v t m = 
Some b ->
    
exists fp, 
bool_val_fp_total v t m = 
fp.
Proof.
Lemma bool_val_fp_bool_val:
  
forall v t m fp,
    
bool_val_fp v t m = 
Some fp ->
    (
exists b, 
bool_val v t m = 
Some b) 
    \/ (
exists b ofs, 
v = 
Vptr b ofs /\ 
Mem.weak_valid_pointer m b (
Ptrofs.unsigned ofs) = 
false).
Proof.
  unfold bool_val, 
bool_val_fp; 
intros.
  
destruct Archi.ptr64 eqn:? ;
    
destruct (
classify_bool t); 
destruct v; 
simpl in *;
      
try congruence; 
eauto;
        
match goal with
        | |- 
context[
if ?
x then _ else _] => 
destruct x eqn:? ; 
eauto
        end.
Qed.
 
  
 Unary operators 
 Boolean negation 
Definition sem_notbool_fp (
v: 
val) (
ty: 
type) (
m: 
mem) : 
option footprint :=
  
bool_val_fp v ty m.
Lemma sem_notbool_sem_notbool_fp:
  
forall v ty m b,
    
sem_notbool v ty m = 
Some b ->
    
exists fp, 
sem_notbool_fp v ty m = 
Some fp.
Proof.
Lemma sem_notbool_fp_sem_notbool:
  
forall v ty m fp,
    
sem_notbool_fp v ty m = 
Some fp ->
    (
exists b, 
sem_notbool v ty m = 
Some b)
    \/ (
exists b ofs, 
v = 
Vptr b ofs /\ 
Mem.weak_valid_pointer m b (
Ptrofs.unsigned ofs) = 
false).
Proof.
 Binary operators 
Definition sem_binarith_fp
           (
sem_int: 
signedness -> 
int -> 
int -> 
option val)
           (
sem_long: 
signedness -> 
int64 -> 
int64 -> 
option val)
           (
sem_float: 
float -> 
float -> 
option val)
           (
sem_single: 
float32 -> 
float32 -> 
option val)
           (
v1: 
val) (
t1: 
type) (
v2: 
val) (
t2: 
type) (
m: 
mem): 
option footprint:=
  
let c := 
classify_binarith t1 t2 in
  let t := 
binarith_type c in
  match sem_cast v1 t1 t m , 
sem_cast_fp v1 t1 t m with
  | 
Some v1', 
Some fp1 =>
    
match sem_cast v2 t2 t m , 
sem_cast_fp v2 t2 t m with
    | 
Some v2', 
Some fp2 =>
      
match c with
      | 
bin_case_i sg =>
        
match v1', 
v2' 
with
        | 
Vint n1, 
Vint n2 =>
          
if sem_int sg n1 n2 then Some (
FP.union fp1 fp2) 
else None
        | 
_,  
_ => 
None
        end
      | 
bin_case_f =>
        
match v1', 
v2' 
with
        | 
Vfloat n1, 
Vfloat n2 =>
          
if sem_float n1 n2 then Some (
FP.union fp1 fp2) 
else None
        | 
_,  
_ => 
None
        end
      | 
bin_case_s =>
        
match v1', 
v2' 
with
        | 
Vsingle n1, 
Vsingle n2 =>
          
if sem_single n1 n2 then Some (
FP.union fp1 fp2) 
else None
        | 
_,  
_ => 
None
        end
      | 
bin_case_l sg =>
        
match v1', 
v2' 
with
        | 
Vlong n1, 
Vlong n2 =>
          
if sem_long sg n1 n2 then Some (
FP.union fp1 fp2) 
else None            
        | 
_,  
_ => 
None
        end
      | 
bin_default => 
None
      end
    | 
_, 
_ => 
None
    end
  | 
_, 
_ => 
None
  end.
Lemma sem_binarith_sem_binarith_fp:
  
forall sem1 sem2 sem3 sem4 v1 t1 v2 t2 m v,
    
sem_binarith sem1 sem2 sem3 sem4 v1 t1 v2 t2 m = 
Some v ->
    
exists fp, 
sem_binarith_fp sem1 sem2 sem3 sem4 v1 t1 v2 t2 m = 
Some fp.
Proof.
  
Lemma sem_binarith_fp_sem_binarith:
  
forall sem1 sem2 sem3 sem4 v1 t1 v2 t2 m fp,
    
sem_binarith_fp sem1 sem2 sem3 sem4 v1 t1 v2 t2 m = 
Some fp ->
    (
exists v, 
sem_binarith sem1 sem2 sem3 sem4 v1 t1 v2 t2 m = 
Some v)
    \/ (
exists b ofs, 
v1 = 
Vptr b ofs /\ 
Mem.weak_valid_pointer m b (
Ptrofs.unsigned ofs) = 
false)
    \/ (
exists b ofs, 
v2 = 
Vptr b ofs /\ 
Mem.weak_valid_pointer m b (
Ptrofs.unsigned ofs) = 
false).
Proof.
  unfold sem_binarith_fp, 
sem_binarith.
  
intros.
  
destruct (
sem_cast_fp v2 t2) 
eqn: 
Hv2, (
sem_cast_fp v1 t1) 
eqn: 
Hv1; 
simpl;
    
try (
apply sem_cast_fp_sem_cast with (
m:=
m) 
in Hv2);
    
try (
destruct Hv2 as [ [
v2' 
Hv2] | [
b [
ofs [
Hv2 INVALID2]]]];
         [ 
rewrite Hv2 in * | ]);
    
try (
apply sem_cast_fp_sem_cast with (
m:=
m) 
in Hv1);
    
try (
destruct Hv1 as [ [
v1' 
Hv1] | [
b [
ofs [
Hv1 INVALID1]]]];
         [ 
rewrite Hv1 in * | ]);
    
destruct classify_binarith;
    
try destruct v1' 
eqn:?; 
try destruct v2' 
eqn:?; 
try (
inv H; 
fail);
      
try match goal with
          | 
H: (
if ?
x then _ else _) = 
Some _ |- 
_ => 
destruct x; 
inv H; 
eauto
          end; 
eauto;
        
try (
right; 
left; 
eauto; 
fail);
        
try (
right; 
right; 
eauto; 
fail).
Qed.
 
 Addition 
Definition sem_add_fp
           (
cenv: 
composite_env) (
v1:
val) (
t1:
type) (
v2: 
val) (
t2:
type)
           (
m: 
mem) : 
option footprint :=
  
match classify_add t1 t2 with
  | 
add_case_pi ty si =>
    
if sem_add_ptr_int cenv ty si v1 v2
    then Some empfp else None
  | 
add_case_pl ty =>
    
if sem_add_ptr_long cenv ty v1 v2
    then Some empfp else None
  | 
add_case_ip si ty =>
    
if sem_add_ptr_int cenv ty si v2 v1
    then Some empfp else None
  | 
add_case_lp ty =>
    
if sem_add_ptr_long cenv ty v2 v1
    then Some empfp else None
  | 
add_default =>
    
sem_binarith_fp
      (
fun sg n1 n2 => 
Some(
Vint(
Int.add n1 n2)))
      (
fun sg n1 n2 => 
Some(
Vlong(
Int64.add n1 n2)))
      (
fun n1 n2 => 
Some(
Vfloat(
Float.add n1 n2)))
      (
fun n1 n2 => 
Some(
Vsingle(
Float32.add n1 n2)))
      
v1 t1 v2 t2 m
  end.
Lemma sem_add_sem_add_fp:
  
forall cenv v1 t1 v2 t2 m v,
    
sem_add cenv v1 t1 v2 t2 m = 
Some v ->
    
exists fp, 
sem_add_fp cenv v1 t1 v2 t2 m = 
Some fp.
Proof.
Lemma sem_add_fp_sem_add:
  
forall cenv v1 t1 v2 t2 m fp,
    
sem_add_fp cenv v1 t1 v2 t2 m = 
Some fp ->
    (
exists v : 
val, 
sem_add cenv v1 t1 v2 t2 m = 
Some v) \/
    (
exists (
b : 
block) (
ofs : 
ptrofs),
        
v1 = 
Vptr b ofs /\ 
Mem.weak_valid_pointer m b (
Ptrofs.unsigned ofs) = 
false) \/
    (
exists (
b : 
block) (
ofs : 
ptrofs),
        
v2 = 
Vptr b ofs /\ 
Mem.weak_valid_pointer m b (
Ptrofs.unsigned ofs) = 
false).
Proof.
 Subtraction 
Definition sem_sub_fp cenv v1 t1 v2 t2 m : 
option footprint :=
  
match classify_sub t1 t2 with
  | 
sub_case_pi ty si =>
    
match v1, 
v2 with
    | 
Vptr b1 ofs1, 
Vint n2 => 
Some empfp
    | 
Vint n1, 
Vint n2 =>
      
if Archi.ptr64 then None else Some empfp
    | 
Vlong n1, 
Vint n2 =>
      
if Archi.ptr64 then Some empfp else None
    | 
_,  
_ => 
None
      end
  | 
sub_case_pl ty =>            
(* pointer minus long  *)
    match v1, 
v2 with
    | 
Vptr b1 ofs1, 
Vlong n2 => 
Some empfp
    | 
Vint n1, 
Vlong n2 =>
      
if Archi.ptr64 then None else Some empfp
    | 
Vlong n1, 
Vlong n2 =>
      
if Archi.ptr64 then Some empfp else None
    | 
_,  
_ => 
None
    end
  | 
sub_case_pp ty =>          
(* pointer minus pointer  *)
    match v1,
v2 with
    | 
Vptr b1 ofs1, 
Vptr b2 ofs2 =>
      
if eq_block b1 b2 then
        let sz := 
sizeof cenv ty in
        if zlt 0 
sz && 
zle sz Ptrofs.max_signed
        then Some empfp
        else None
      else None
    | 
_, 
_ => 
None
    end
  | 
sub_default =>
      
sem_binarith_fp
        (
fun sg n1 n2 => 
Some(
Vint(
Int.sub n1 n2)))
        (
fun sg n1 n2 => 
Some(
Vlong(
Int64.sub n1 n2)))
        (
fun n1 n2 => 
Some(
Vfloat(
Float.sub n1 n2)))
        (
fun n1 n2 => 
Some(
Vsingle(
Float32.sub n1 n2)))
        
v1 t1 v2 t2 m
  end.
Lemma sem_sub_sem_sub_fp:
  
forall cenv v1 t1 v2 t2 m v,
    
sem_sub cenv v1 t1 v2 t2 m = 
Some v ->
    
exists fp, 
sem_sub_fp cenv v1 t1 v2 t2 m = 
Some fp.
Proof.
Lemma sem_sub_fp_sem_sub:
  
forall cenv v1 t1 v2 t2 m fp,
    
sem_sub_fp cenv v1 t1 v2 t2 m = 
Some fp ->
    (
exists v : 
val, 
sem_sub cenv v1 t1 v2 t2 m = 
Some v) \/
    (
exists (
b : 
block) (
ofs : 
ptrofs),
        
v1 = 
Vptr b ofs /\ 
Mem.weak_valid_pointer m b (
Ptrofs.unsigned ofs) = 
false) \/
    (
exists (
b : 
block) (
ofs : 
ptrofs),
        
v2 = 
Vptr b ofs /\ 
Mem.weak_valid_pointer m b (
Ptrofs.unsigned ofs) = 
false).
Proof.
  unfold sem_sub, 
sem_sub_fp. 
intros.
  
destruct (
classify_sub t1 t2);
    
repeat match goal with
           | 
H : (
if ?
x then _ else _) = 
Some _ |- 
_ => 
destruct x eqn:?
           | 
H : 
context[
match ?
x with _ => 
_ end] |- 
_ => 
destruct x eqn:?
           | |- 
context[
if ?
x then _ else _] => 
destruct x eqn:?
           
end;
    
try discriminate; 
eauto.
  
eapply sem_binarith_fp_sem_binarith; 
eauto.
Qed.
 
 Multiplication, division, modulus 
Definition sem_mul_fp (
v1:
val) (
t1:
type) (
v2: 
val) (
t2:
type) (
m: 
mem): 
option footprint :=
  
sem_binarith_fp
    (
fun sg n1 n2 => 
Some(
Vint(
Int.mul n1 n2)))
    (
fun sg n1 n2 => 
Some(
Vlong(
Int64.mul n1 n2)))
    (
fun n1 n2 => 
Some(
Vfloat(
Float.mul n1 n2)))
    (
fun n1 n2 => 
Some(
Vsingle(
Float32.mul n1 n2)))
    
v1 t1 v2 t2 m.
Definition sem_div_fp (
v1:
val) (
t1:
type) (
v2: 
val) (
t2:
type) (
m: 
mem) : 
option footprint :=
  
sem_binarith_fp
    (
fun sg n1 n2 =>
       
match sg with
       | 
Signed =>
         
if Int.eq n2 Int.zero
            || 
Int.eq n1 (
Int.repr Int.min_signed) && 
Int.eq n2 Int.mone
         then None else Some(
Vint(
Int.divs n1 n2))
       | 
Unsigned =>
         
if Int.eq n2 Int.zero
         then None else Some(
Vint(
Int.divu n1 n2))
       
end)
    (
fun sg n1 n2 =>
       
match sg with
       | 
Signed =>
         
if Int64.eq n2 Int64.zero
            || 
Int64.eq n1 (
Int64.repr Int64.min_signed) && 
Int64.eq n2 Int64.mone
         then None else Some(
Vlong(
Int64.divs n1 n2))
       | 
Unsigned =>
         
if Int64.eq n2 Int64.zero
         then None else Some(
Vlong(
Int64.divu n1 n2))
       
end)
    (
fun n1 n2 => 
Some(
Vfloat(
Float.div n1 n2)))
    (
fun n1 n2 => 
Some(
Vsingle(
Float32.div n1 n2)))
    
v1 t1 v2 t2 m.
Definition sem_mod_fp (
v1:
val) (
t1:
type) (
v2: 
val) (
t2:
type) (
m: 
mem) : 
option footprint:=
  
sem_binarith_fp
    (
fun sg n1 n2 =>
      
match sg with
      | 
Signed =>
          
if Int.eq n2 Int.zero
          || 
Int.eq n1 (
Int.repr Int.min_signed) && 
Int.eq n2 Int.mone
          then None else Some(
Vint(
Int.mods n1 n2))
      | 
Unsigned =>
          
if Int.eq n2 Int.zero
          then None else Some(
Vint(
Int.modu n1 n2))
      
end)
    (
fun sg n1 n2 =>
      
match sg with
      | 
Signed =>
          
if Int64.eq n2 Int64.zero
          || 
Int64.eq n1 (
Int64.repr Int64.min_signed) && 
Int64.eq n2 Int64.mone
          then None else Some(
Vlong(
Int64.mods n1 n2))
      | 
Unsigned =>
          
if Int64.eq n2 Int64.zero
          then None else Some(
Vlong(
Int64.modu n1 n2))
      
end)
    (
fun n1 n2 => 
None)
    (
fun n1 n2 => 
None)
    
v1 t1 v2 t2 m.
Definition sem_and_fp (
v1:
val) (
t1:
type) (
v2: 
val) (
t2:
type) (
m: 
mem) : 
option footprint:=
   
sem_binarith_fp
    (
fun sg n1 n2 => 
Some(
Vint(
Int.and n1 n2)))
    (
fun sg n1 n2 => 
Some(
Vlong(
Int64.and n1 n2)))
    (
fun n1 n2 => 
None)
    (
fun n1 n2 => 
None)
    
v1 t1 v2 t2 m.
Definition sem_or_fp (
v1:
val) (
t1:
type) (
v2: 
val) (
t2:
type) (
m: 
mem) : 
option footprint :=
  
sem_binarith_fp
    (
fun sg n1 n2 => 
Some(
Vint(
Int.or n1 n2)))
    (
fun sg n1 n2 => 
Some(
Vlong(
Int64.or n1 n2)))
    (
fun n1 n2 => 
None)
    (
fun n1 n2 => 
None)
    
v1 t1 v2 t2 m.
Definition sem_xor_fp (
v1:
val) (
t1:
type) (
v2: 
val) (
t2:
type) (
m: 
mem) : 
option footprint :=
  
sem_binarith_fp
    (
fun sg n1 n2 => 
Some(
Vint(
Int.xor n1 n2)))
    (
fun sg n1 n2 => 
Some(
Vlong(
Int64.xor n1 n2)))
    (
fun n1 n2 => 
None)
    (
fun n1 n2 => 
None)
    
v1 t1 v2 t2 m.
 Comparisons 
Definition cmp_ptr_fp (
m: 
mem) (
c: 
comparison) (
v1 v2: 
val) : 
option footprint :=
  
if Archi.ptr64 then cmplu_bool_fp m c v1 v2
  else cmpu_bool_fp m c v1 v2.
Definition sem_cmp_fp (
c:
comparison)
           (
v1: 
val) (
t1: 
type) (
v2: 
val) (
t2: 
type) (
m: 
mem) : 
option footprint :=
  
match classify_cmp t1 t2 with
  | 
cmp_case_pp => 
cmp_ptr_fp m c v1 v2
  | 
cmp_case_pi si =>
    
match v2 with
    | 
Vint n2 => 
let v2' := 
Vptrofs (
ptrofs_of_int si n2) 
in cmp_ptr_fp m c v1 v2'
    | 
Vptr _ _ => 
if Archi.ptr64 then None else cmp_ptr_fp m c v1 v2
    | 
_ => 
None
    end
  | 
cmp_case_ip si =>
    
match v1 with
    | 
Vint n1 => 
let v1' := 
Vptrofs (
ptrofs_of_int si n1) 
in cmp_ptr_fp m c v1' 
v2
    | 
Vptr _ _ => 
if Archi.ptr64 then None else cmp_ptr_fp m c v1 v2
    | 
_ => 
None
    end
  | 
cmp_case_pl =>
    
match v2 with
    | 
Vlong n2 => 
let v2' := 
Vptrofs (
Ptrofs.of_int64 n2) 
in cmp_ptr_fp m c v1 v2'
    | 
Vptr _ _ => 
if Archi.ptr64 then cmp_ptr_fp m c v1 v2 else None
    | 
_ => 
None
    end
  | 
cmp_case_lp =>
    
match v1 with
    | 
Vlong n1 => 
let v1' := 
Vptrofs (
Ptrofs.of_int64 n1) 
in cmp_ptr_fp m c v1' 
v2
    | 
Vptr _ _ => 
if Archi.ptr64 then cmp_ptr_fp m c v1 v2 else None
    | 
_ => 
None
    end
  | 
cmp_default =>
    
sem_binarith_fp
      (
fun sg n1 n2 =>
         
Some(
Val.of_bool(
match sg with Signed => 
Int.cmp c n1 n2 | 
Unsigned => 
Int.cmpu c n1 n2 end)))
      (
fun sg n1 n2 =>
         
Some(
Val.of_bool(
match sg with Signed => 
Int64.cmp c n1 n2 | 
Unsigned => 
Int64.cmpu c n1 n2 end)))
      (
fun n1 n2 =>
         
Some(
Val.of_bool(
Float.cmp c n1 n2)))
      (
fun n1 n2 =>
         
Some(
Val.of_bool(
Float32.cmp c n1 n2)))
      
v1 t1 v2 t2 m
  end.
Lemma sem_cmp_sem_cmp_fp:
  
forall c v1 t1 v2 t2 m v,
    
sem_cmp c v1 t1 v2 t2 m = 
Some v ->
    
exists fp, 
sem_cmp_fp c v1 t1 v2 t2 m = 
Some fp.
Proof.
 Combined semantics of unary and binary operators 
Definition sem_unary_operation_fp
           (
op: 
unary_operation) (
v: 
val) (
ty: 
type) (
m: 
mem) : 
option footprint:=
  
match op with
  | 
Onotbool => 
sem_notbool_fp v ty m
  | 
Onotint => 
if sem_notint v ty then Some empfp else None
  | 
Oneg => 
if sem_neg v ty then Some empfp else None
  | 
Oabsfloat => 
if sem_absfloat v ty then Some empfp else None
  end.
Lemma sem_unary_operation_sem_unary_operation_fp:
  
forall op v ty m v',
    
sem_unary_operation op v ty m = 
Some v' ->
    
exists fp, 
sem_unary_operation_fp op v ty m = 
Some fp.
Proof.
Lemma sem_unary_operation_fp_sem_unary_operation:
  
forall op v ty m fp,
    
sem_unary_operation_fp op v ty m = 
Some fp ->
    (
exists v', 
sem_unary_operation op v ty m = 
Some v')
    \/ (
op = 
Onotbool /\
       
exists (
b : 
block) (
ofs : 
ptrofs),
         
v = 
Vptr b ofs /\ 
Mem.weak_valid_pointer m b (
Ptrofs.unsigned ofs) = 
false).
Proof.
Definition sem_binary_operation_fp
           (
cenv: 
composite_env)
           (
op: 
binary_operation)
           (
v1: 
val) (
t1: 
type) (
v2: 
val) (
t2:
type)
           (
m: 
mem) : 
option footprint :=
  
match op with
  | 
Oadd => 
sem_add_fp cenv v1 t1 v2 t2 m
  | 
Osub => 
sem_sub_fp cenv v1 t1 v2 t2 m
  | 
Omul => 
sem_mul_fp v1 t1 v2 t2 m
  | 
Omod => 
sem_mod_fp v1 t1 v2 t2 m
  | 
Odiv => 
sem_div_fp v1 t1 v2 t2 m
  | 
Oand => 
sem_and_fp v1 t1 v2 t2 m
  | 
Oor  => 
sem_or_fp v1 t1 v2 t2 m
  | 
Oxor => 
sem_xor_fp v1 t1 v2 t2 m
  | 
Oshl => 
if sem_shl v1 t1 v2 t2 then Some empfp else None
  | 
Oshr => 
if sem_shr v1 t1 v2 t2 then Some empfp else None
  | 
Oeq => 
sem_cmp_fp Ceq v1 t1 v2 t2 m
  | 
One => 
sem_cmp_fp Cne v1 t1 v2 t2 m
  | 
Olt => 
sem_cmp_fp Clt v1 t1 v2 t2 m
  | 
Ogt => 
sem_cmp_fp Cgt v1 t1 v2 t2 m
  | 
Ole => 
sem_cmp_fp Cle v1 t1 v2 t2 m
  | 
Oge => 
sem_cmp_fp Cge v1 t1 v2 t2 m
  end.
Lemma sem_binary_operation_sem_binary_operation_fp:
  
forall cenv op v1 t1 v2 t2 m v,
    
sem_binary_operation cenv op v1 t1 v2 t2 m = 
Some v ->
    
exists fp, 
sem_binary_operation_fp cenv op v1 t1 v2 t2 m = 
Some fp.
Proof.
Definition sem_incrdecr_fp
           (
cenv: 
composite_env)
           (
id: 
incr_or_decr) (
v: 
val) (
ty: 
type)
           (
m: 
mem) : 
option footprint :=
  
match id with
  | 
Incr => 
sem_add_fp cenv v ty (
Vint Int.one) 
type_int32s m
  | 
Decr => 
sem_sub_fp cenv v ty (
Vint Int.one) 
type_int32s m
  end.
Lemma sem_incrdecr_sem_incrdecr_fp:
  
forall cenv id v ty m v',
    
sem_incrdecr cenv id v ty m = 
Some v' ->
    
exists fp, 
sem_incrdecr_fp cenv id v ty m = 
Some fp.
Proof.