(** * Values and memory injections *)

(** A memory injection [f] is a function from addresses to either [None]
  or [Some] of an address and an offset.  It defines a correspondence
  between the blocks of two memory states [m1] and [m2]:
- if [f b = None], the block [b] of [m1] has no equivalent in [m2];
- if [f b = Some(b', ofs)], the block [b] of [m2] corresponds to
  a sub-block at offset [ofs] of the block [b'] in [m2].
*)

Definition meminj : Type := block -> option (block * Z).(** A memory injection defines a relation between values that is the
  identity relation, except for pointer values which are shifted
  as prescribed by the memory injection.  Moreover, [Vundef] values
  inject into any other value. *)

Inductive inject (mi: meminj): val -> val -> Prop :=
  | inject_int:
      forall i, inject mi (Vint i) (Vint i)
  | inject_long:
      forall i, inject mi (Vlong i) (Vlong i)
  | inject_float:
      forall f, inject mi (Vfloat f) (Vfloat f)
  | inject_single:
      forall f, inject mi (Vsingle f) (Vsingle f)
  | inject_ptr:
      forall b1 ofs1 b2 ofs2 delta,
      mi b1 = Some (b2, delta) ->
      ofs2 = Ptrofs.add ofs1 (Ptrofs.repr delta) ->
      inject mi (Vptr b1 ofs1) (Vptr b2 ofs2)
  | val_inject_undef: forall v,
      inject mi Vundef v.(** A memory injection defines a relation between values that is the
  identity relation, except for pointer values which are shifted
  as prescribed by the memory injection.  Moreover, [Vundef] values
  inject into any other value. *)

Inductive inject (mi: meminj): val -> val -> Prop :=
  | inject_int:
      forall i, inject mi (Vint i) (Vint i)
  | inject_long:
      forall i, inject mi (Vlong i) (Vlong i)
  | inject_float:
      forall f, inject mi (Vfloat f) (Vfloat f)
  | inject_single:
      forall f, inject mi (Vsingle f) (Vsingle f)
  | inject_ptr:
      forall b1 ofs1 b2 ofs2 delta,
      mi b1 = Some (b2, delta) ->
      ofs2 = Ptrofs.add ofs1 (Ptrofs.repr delta) ->
      inject mi (Vptr b1 ofs1) (Vptr b2 ofs2)
  | val_inject_undef: forall v,
      inject mi Vundef v.(** A memory injection defines a relation between values that is the
  identity relation, except for pointer values which are shifted
  as prescribed by the memory injection.  Moreover, [Vundef] values
  inject into any other value. *)

Inductive inject (mi: meminj): val -> val -> Prop :=
  | inject_int:
      forall i, inject mi (Vint i) (Vint i)
  | inject_long:
      forall i, inject mi (Vlong i) (Vlong i)
  | inject_float:
      forall f, inject mi (Vfloat f) (Vfloat f)
  | inject_single:
      forall f, inject mi (Vsingle f) (Vsingle f)
  | inject_ptr:
      forall b1 ofs1 b2 ofs2 delta,
      mi b1 = Some (b2, delta) ->
      ofs2 = Ptrofs.add ofs1 (Ptrofs.repr delta) ->
      inject mi (Vptr b1 ofs1) (Vptr b2 ofs2)
  | val_inject_undef: forall v,
      inject mi Vundef v.(** A memory injection defines a relation between values that is the
  identity relation, except for pointer values which are shifted
  as prescribed by the memory injection.  Moreover, [Vundef] values
  inject into any other value. *)

Inductive inject (mi: meminj): val -> val -> Prop :=
  | inject_int:
      forall i, inject mi (Vint i) (Vint i)
  | inject_long:
      forall i, inject mi (Vlong i) (Vlong i)
  | inject_float:
      forall f, inject mi (Vfloat f) (Vfloat f)
  | inject_single:
      forall f, inject mi (Vsingle f) (Vsingle f)
  | inject_ptr:
      forall b1 ofs1 b2 ofs2 delta,
      mi b1 = Some (b2, delta) ->
      ofs2 = Ptrofs.add ofs1 (Ptrofs.repr delta) ->
      inject mi (Vptr b1 ofs1) (Vptr b2 ofs2)
  | val_inject_undef: forall v,
      inject mi Vundef v.(** A memory injection defines a relation between values that is the
  identity relation, except for pointer values which are shifted
  as prescribed by the memory injection.  Moreover, [Vundef] values
  inject into any other value. *)

Inductive inject (mi: meminj): val -> val -> Prop :=
  | inject_int:
      forall i, inject mi (Vint i) (Vint i)
  | inject_long:
      forall i, inject mi (Vlong i) (Vlong i)
  | inject_float:
      forall f, inject mi (Vfloat f) (Vfloat f)
  | inject_single:
      forall f, inject mi (Vsingle f) (Vsingle f)
  | inject_ptr:
      forall b1 ofs1 b2 ofs2 delta,
      mi b1 = Some (b2, delta) ->
      ofs2 = Ptrofs.add ofs1 (Ptrofs.repr delta) ->
      inject mi (Vptr b1 ofs1) (Vptr b2 ofs2)
  | val_inject_undef: forall v,
      inject mi Vundef v.(** A memory injection defines a relation between values that is the
  identity relation, except for pointer values which are shifted
  as prescribed by the memory injection.  Moreover, [Vundef] values
  inject into any other value. *)

Inductive inject (mi: meminj): val -> val -> Prop :=
  | inject_int:
      forall i, inject mi (Vint i) (Vint i)
  | inject_long:
      forall i, inject mi (Vlong i) (Vlong i)
  | inject_float:
      forall f, inject mi (Vfloat f) (Vfloat f)
  | inject_single:
      forall f, inject mi (Vsingle f) (Vsingle f)
  | inject_ptr:
      forall b1 ofs1 b2 ofs2 delta,
      mi b1 = Some (b2, delta) ->
      ofs2 = Ptrofs.add ofs1 (Ptrofs.repr delta) ->
      inject mi (Vptr b1 ofs1) (Vptr b2 ofs2)
  | val_inject_undef: forall v,
      inject mi Vundef v.(** A memory injection defines a relation between values that is the
  identity relation, except for pointer values which are shifted
  as prescribed by the memory injection.  Moreover, [Vundef] values
  inject into any other value. *)

Inductive inject (mi: meminj): val -> val -> Prop :=
  | inject_int:
      forall i, inject mi (Vint i) (Vint i)
  | inject_long:
      forall i, inject mi (Vlong i) (Vlong i)
  | inject_float:
      forall f, inject mi (Vfloat f) (Vfloat f)
  | inject_single:
      forall f, inject mi (Vsingle f) (Vsingle f)
  | inject_ptr:
      forall b1 ofs1 b2 ofs2 delta,
      mi b1 = Some (b2, delta) ->
      ofs2 = Ptrofs.add ofs1 (Ptrofs.repr delta) ->
      inject mi (Vptr b1 ofs1) (Vptr b2 ofs2)
  | val_inject_undef: forall v,
      inject mi Vundef v.Inductive inject_list (mi: meminj): list val -> list val-> Prop:=
  | inject_list_nil :
      inject_list mi nil nil
  | inject_list_cons : forall v v' vl vl' ,
      inject mi v v' -> inject_list mi vl vl'->
      inject_list mi (v :: vl) (v' :: vl').Inductive inject_list (mi: meminj): list val -> list val-> Prop:=
  | inject_list_nil :
      inject_list mi nil nil
  | inject_list_cons : forall v v' vl vl' ,
      inject mi v v' -> inject_list mi vl vl'->
      inject_list mi (v :: vl) (v' :: vl').Inductive inject_list (mi: meminj): list val -> list val-> Prop:=
  | inject_list_nil :
      inject_list mi nil nil
  | inject_list_cons : forall v v' vl vl' ,
      inject mi v v' -> inject_list mi vl vl'->
      inject_list mi (v :: vl) (v' :: vl').

(* Specifications: *)
Lemma inject_ptrofs: forall mi i, inject mi (Vptrofs i) (Vptrofs i).
Lemma load_result_inject: forall chunk v1 v2, inject f v1 v2 -> inject f (Val.load_result chunk v1) (Val.load_result chunk v2).