(** * Memory extensions *)

(**  A store [m2] extends a store [m1] if [m2] can be obtained from [m1]
  by increasing the sizes of the memory blocks of [m1] (decreasing
  the low bounds, increasing the high bounds), and replacing some of
  the [Vundef] values stored in [m1] by more defined values stored
  in [m2] at the same locations. *)

Record extends' (m1 m2: mem) : Prop :=
  mk_extends {
    mext_next: nextblock m1 = nextblock m2;
    mext_inj:  mem_inj inject_id m1 m2;
    mext_perm_inv: forall b ofs k p,
      perm m2 b ofs k p ->
      perm m1 b ofs k p \/ ~perm m1 b ofs Max Nonempty
  }.(** * Memory extensions *)

(**  A store [m2] extends a store [m1] if [m2] can be obtained from [m1]
  by increasing the sizes of the memory blocks of [m1] (decreasing
  the low bounds, increasing the high bounds), and replacing some of
  the [Vundef] values stored in [m1] by more defined values stored
  in [m2] at the same locations. *)

Record extends' (m1 m2: mem) : Prop :=
  mk_extends {
    mext_next: nextblock m1 = nextblock m2;
    mext_inj:  mem_inj inject_id m1 m2;
    mext_perm_inv: forall b ofs k p,
      perm m2 b ofs k p ->
      perm m1 b ofs k p \/ ~perm m1 b ofs Max Nonempty
  }.(** * Memory extensions *)

(**  A store [m2] extends a store [m1] if [m2] can be obtained from [m1]
  by increasing the sizes of the memory blocks of [m1] (decreasing
  the low bounds, increasing the high bounds), and replacing some of
  the [Vundef] values stored in [m1] by more defined values stored
  in [m2] at the same locations. *)

Record extends' (m1 m2: mem) : Prop :=
  mk_extends {
    mext_next: nextblock m1 = nextblock m2;
    mext_inj:  mem_inj inject_id m1 m2;
    mext_perm_inv: forall b ofs k p,
      perm m2 b ofs k p ->
      perm m1 b ofs k p \/ ~perm m1 b ofs Max Nonempty
  }.(** * Memory extensions *)

(**  A store [m2] extends a store [m1] if [m2] can be obtained from [m1]
  by increasing the sizes of the memory blocks of [m1] (decreasing
  the low bounds, increasing the high bounds), and replacing some of
  the [Vundef] values stored in [m1] by more defined values stored
  in [m2] at the same locations. *)

Record extends' (m1 m2: mem) : Prop :=
  mk_extends {
    mext_next: nextblock m1 = nextblock m2;
    mext_inj:  mem_inj inject_id m1 m2;
    mext_perm_inv: forall b ofs k p,
      perm m2 b ofs k p ->
      perm m1 b ofs k p \/ ~perm m1 b ofs Max Nonempty
  }.(** * Memory extensions *)

(**  A store [m2] extends a store [m1] if [m2] can be obtained from [m1]
  by increasing the sizes of the memory blocks of [m1] (decreasing
  the low bounds, increasing the high bounds), and replacing some of
  the [Vundef] values stored in [m1] by more defined values stored
  in [m2] at the same locations. *)

Record extends' (m1 m2: mem) : Prop :=
  mk_extends {
    mext_next: nextblock m1 = nextblock m2;
    mext_inj:  mem_inj inject_id m1 m2;
    mext_perm_inv: forall b ofs k p,
      perm m2 b ofs k p ->
      perm m1 b ofs k p \/ ~perm m1 b ofs Max Nonempty
  }.Definition extends := extends'.

(* Specifications: *)
Theorem extends_refl: forall m, extends m m.
Theorem load_extends: forall chunk m1 m2 b ofs v1, extends m1 m2 -> load chunk m1 b ofs = Some v1 -> exists v2, load chunk m2 b ofs = Some v2 /\ Val.lessdef v1 v2.
Theorem loadv_extends: forall chunk m1 m2 addr1 addr2 v1, extends m1 m2 -> loadv chunk m1 addr1 = Some v1 -> Val.lessdef addr1 addr2 -> exists v2, loadv chunk m2 addr2 = Some v2 /\ Val.lessdef v1 v2.
Theorem loadbytes_extends: forall m1 m2 b ofs len bytes1, extends m1 m2 -> loadbytes m1 b ofs len = Some bytes1 -> exists bytes2, loadbytes m2 b ofs len = Some bytes2 /\ list_forall2 memval_lessdef bytes1 bytes2.
Theorem store_within_extends: forall chunk m1 m2 b ofs v1 m1' v2, extends m1 m2 -> store chunk m1 b ofs v1 = Some m1' -> Val.lessdef v1 v2 -> exists m2', store chunk m2 b ofs v2 = Some m2' /\ extends m1' m2'.
Theorem store_outside_extends: forall chunk m1 m2 b ofs v m2', extends m1 m2 -> store chunk m2 b ofs v = Some m2' -> (forall ofs', perm m1 b ofs' Cur Readable -> ofs <= ofs' < ofs + size_chunk chunk -> False) -> extends m1 m2'.
Theorem storev_extends: forall chunk m1 m2 addr1 v1 m1' addr2 v2, extends m1 m2 -> storev chunk m1 addr1 v1 = Some m1' -> Val.lessdef addr1 addr2 -> Val.lessdef v1 v2 -> exists m2', storev chunk m2 addr2 v2 = Some m2' /\ extends m1' m2'.
Theorem storebytes_within_extends: forall m1 m2 b ofs bytes1 m1' bytes2, extends m1 m2 -> storebytes m1 b ofs bytes1 = Some m1' -> list_forall2 memval_lessdef bytes1 bytes2 -> exists m2', storebytes m2 b ofs bytes2 = Some m2' /\ extends m1' m2'.
Theorem storebytes_outside_extends: forall m1 m2 b ofs bytes2 m2', extends m1 m2 -> storebytes m2 b ofs bytes2 = Some m2' -> (forall ofs', perm m1 b ofs' Cur Readable -> ofs <= ofs' < ofs + Z.of_nat (length bytes2) -> False) -> extends m1 m2'.
Theorem alloc_extends: forall m1 m2 lo1 hi1 b m1' lo2 hi2, extends m1 m2 -> alloc m1 lo1 hi1 = (m1', b) -> lo2 <= lo1 -> hi1 <= hi2 -> exists m2', alloc m2 lo2 hi2 = (m2', b) /\ extends m1' m2'.
Theorem free_left_extends: forall m1 m2 b lo hi m1', extends m1 m2 -> free m1 b lo hi = Some m1' -> extends m1' m2.
Theorem free_right_extends: forall m1 m2 b lo hi m2', extends m1 m2 -> free m2 b lo hi = Some m2' -> (forall ofs k p, perm m1 b ofs k p -> lo <= ofs < hi -> False) -> extends m1 m2'.
Theorem free_parallel_extends: forall m1 m2 b lo hi m1', extends m1 m2 -> free m1 b lo hi = Some m1' -> exists m2', free m2 b lo hi = Some m2' /\ extends m1' m2'.
Theorem valid_block_extends: forall m1 m2 b, extends m1 m2 -> (valid_block m1 b <-> valid_block m2 b).
Theorem perm_extends: forall m1 m2 b ofs k p, extends m1 m2 -> perm m1 b ofs k p -> perm m2 b ofs k p.
Theorem perm_extends_inv: forall m1 m2 b ofs k p, extends m1 m2 -> perm m2 b ofs k p -> perm m1 b ofs k p \/ ~perm m1 b ofs Max Nonempty.
Theorem valid_access_extends: forall m1 m2 chunk b ofs p, extends m1 m2 -> valid_access m1 chunk b ofs p -> valid_access m2 chunk b ofs p.
Theorem valid_pointer_extends: forall m1 m2 b ofs, extends m1 m2 -> valid_pointer m1 b ofs = true -> valid_pointer m2 b ofs = true.
Theorem weak_valid_pointer_extends: forall m1 m2 b ofs, extends m1 m2 -> weak_valid_pointer m1 b ofs = true -> weak_valid_pointer m2 b ofs = true.
Theorem extends_refl: forall m, extends m m.
Theorem load_extends: forall chunk m1 m2 b ofs v1, extends m1 m2 -> load chunk m1 b ofs = Some v1 -> exists v2, load chunk m2 b ofs = Some v2 /\ Val.lessdef v1 v2.
Theorem loadv_extends: forall chunk m1 m2 addr1 addr2 v1, extends m1 m2 -> loadv chunk m1 addr1 = Some v1 -> Val.lessdef addr1 addr2 -> exists v2, loadv chunk m2 addr2 = Some v2 /\ Val.lessdef v1 v2.
Theorem loadbytes_extends: forall m1 m2 b ofs len bytes1, extends m1 m2 -> loadbytes m1 b ofs len = Some bytes1 -> exists bytes2, loadbytes m2 b ofs len = Some bytes2 /\ list_forall2 memval_lessdef bytes1 bytes2.
Theorem store_within_extends: forall chunk m1 m2 b ofs v1 m1' v2, extends m1 m2 -> store chunk m1 b ofs v1 = Some m1' -> Val.lessdef v1 v2 -> exists m2', store chunk m2 b ofs v2 = Some m2' /\ extends m1' m2'.
Theorem store_outside_extends: forall chunk m1 m2 b ofs v m2', extends m1 m2 -> store chunk m2 b ofs v = Some m2' -> (forall ofs', perm m1 b ofs' Cur Readable -> ofs <= ofs' < ofs + size_chunk chunk -> False) -> extends m1 m2'.
Theorem storev_extends: forall chunk m1 m2 addr1 v1 m1' addr2 v2, extends m1 m2 -> storev chunk m1 addr1 v1 = Some m1' -> Val.lessdef addr1 addr2 -> Val.lessdef v1 v2 -> exists m2', storev chunk m2 addr2 v2 = Some m2' /\ extends m1' m2'.
Theorem storebytes_within_extends: forall m1 m2 b ofs bytes1 m1' bytes2, extends m1 m2 -> storebytes m1 b ofs bytes1 = Some m1' -> list_forall2 memval_lessdef bytes1 bytes2 -> exists m2', storebytes m2 b ofs bytes2 = Some m2' /\ extends m1' m2'.
Theorem storebytes_outside_extends: forall m1 m2 b ofs bytes2 m2', extends m1 m2 -> storebytes m2 b ofs bytes2 = Some m2' -> (forall ofs', perm m1 b ofs' Cur Readable -> ofs <= ofs' < ofs + Z.of_nat (length bytes2) -> False) -> extends m1 m2'.
Theorem alloc_extends: forall m1 m2 lo1 hi1 b m1' lo2 hi2, extends m1 m2 -> alloc m1 lo1 hi1 = (m1', b) -> lo2 <= lo1 -> hi1 <= hi2 -> exists m2', alloc m2 lo2 hi2 = (m2', b) /\ extends m1' m2'.
Theorem free_left_extends: forall m1 m2 b lo hi m1', extends m1 m2 -> free m1 b lo hi = Some m1' -> extends m1' m2.
Theorem free_right_extends: forall m1 m2 b lo hi m2', extends m1 m2 -> free m2 b lo hi = Some m2' -> (forall ofs k p, perm m1 b ofs k p -> lo <= ofs < hi -> False) -> extends m1 m2'.
Theorem free_parallel_extends: forall m1 m2 b lo hi m1', extends m1 m2 -> free m1 b lo hi = Some m1' -> exists m2', free m2 b lo hi = Some m2' /\ extends m1' m2'.
Theorem valid_block_extends: forall m1 m2 b, extends m1 m2 -> (valid_block m1 b <-> valid_block m2 b).
Theorem perm_extends: forall m1 m2 b ofs k p, extends m1 m2 -> perm m1 b ofs k p -> perm m2 b ofs k p.
Theorem perm_extends_inv: forall m1 m2 b ofs k p, extends m1 m2 -> perm m2 b ofs k p -> perm m1 b ofs k p \/ ~perm m1 b ofs Max Nonempty.
Theorem valid_access_extends: forall m1 m2 chunk b ofs p, extends m1 m2 -> valid_access m1 chunk b ofs p -> valid_access m2 chunk b ofs p.
Theorem valid_pointer_extends: forall m1 m2 b ofs, extends m1 m2 -> valid_pointer m1 b ofs = true -> valid_pointer m2 b ofs = true.
Theorem weak_valid_pointer_extends: forall m1 m2 b ofs, extends m1 m2 -> weak_valid_pointer m1 b ofs = true -> weak_valid_pointer m2 b ofs = true.