(** * Relating the memory states *)
(** The [magree] predicate is a variant of [Mem.extends] where we allow the contents of the two memory states to differ arbitrarily on some locations.  The predicate [P] is true on the locations whose contents must be in the [lessdef] relation. *)
Definition locset := block -> Z -> Prop.
Record magree (m1 m2: mem) (P: locset) : Prop := mk_magree {
ma_perm:
forall b ofs k p,
Mem.perm m1 b ofs k p -> Mem.perm m2 b ofs k p;
ma_perm_inv:
forall b ofs k p,
Mem.perm m2 b ofs k p -> Mem.perm m1 b ofs k p \/ ~Mem.perm m1 b ofs Max Nonempty;
ma_memval:
forall b ofs,
Mem.perm m1 b ofs Cur Readable ->
P b ofs ->
memval_lessdef (ZMap.get ofs (PMap.get b (Mem.mem_contents m1)))
(ZMap.get ofs (PMap.get b (Mem.mem_contents m2)));
ma_nextblock:
Mem.nextblock m2 = Mem.nextblock m1
}.

(* Specifications: *)
Lemma magree_monotone:
forall m1 m2 (P Q: locset),
magree m1 m2 P ->
(forall b ofs, Q b ofs -> P b ofs) ->
magree m1 m2 Q.
Lemma mextends_agree:
forall m1 m2 P, Mem.extends m1 m2 -> magree m1 m2 P.
Lemma magree_extends:
forall m1 m2 (P: locset),
(forall b ofs, P b ofs) ->
magree m1 m2 P -> Mem.extends m1 m2.
Lemma magree_loadbytes:
forall m1 m2 P b ofs n bytes,
magree m1 m2 P ->
Mem.loadbytes m1 b ofs n = Some bytes ->
(forall i, ofs <= i < ofs + n -> P b i) ->
exists bytes', Mem.loadbytes m2 b ofs n = Some bytes' /\ list_forall2 memval_lessdef bytes bytes'.
Lemma magree_load:
forall m1 m2 P chunk b ofs v,
magree m1 m2 P ->
Mem.load chunk m1 b ofs = Some v ->
(forall i, ofs <= i < ofs + size_chunk chunk -> P b i) ->
exists v', Mem.load chunk m2 b ofs = Some v' /\ Val.lessdef v v'.
Lemma magree_storebytes_parallel:
forall m1 m2 (P Q: locset) b ofs bytes1 m1' bytes2,
magree m1 m2 P ->
Mem.storebytes m1 b ofs bytes1 = Some m1' ->
(forall b' i, Q b' i ->
b' <> b \/ i < ofs \/ ofs + Z.of_nat (length bytes1) <= i ->
P b' i) ->
list_forall2 memval_lessdef bytes1 bytes2 ->
exists m2', Mem.storebytes m2 b ofs bytes2 = Some m2' /\ magree m1' m2' Q.
Lemma magree_store_parallel:
forall m1 m2 (P Q: locset) chunk b ofs v1 m1' v2,
magree m1 m2 P ->
Mem.store chunk m1 b ofs v1 = Some m1' ->
vagree v1 v2 (store_argument chunk) ->
(forall b' i, Q b' i ->
b' <> b \/ i < ofs \/ ofs + size_chunk chunk <= i ->
P b' i) ->
exists m2', Mem.store chunk m2 b ofs v2 = Some m2' /\ magree m1' m2' Q.
Lemma magree_storebytes_left:
forall m1 m2 P b ofs bytes1 m1',
magree m1 m2 P ->
Mem.storebytes m1 b ofs bytes1 = Some m1' ->
(forall i, ofs <= i < ofs + Z.of_nat (length bytes1) -> ~(P b i)) ->
magree m1' m2 P.
Lemma magree_store_left:
forall m1 m2 P chunk b ofs v1 m1',
magree m1 m2 P ->
Mem.store chunk m1 b ofs v1 = Some m1' ->
(forall i, ofs <= i < ofs + size_chunk chunk -> ~(P b i)) ->
magree m1' m2 P.
Lemma magree_free:
forall m1 m2 (P Q: locset) b lo hi m1',
magree m1 m2 P ->
Mem.free m1 b lo hi = Some m1' ->
(forall b' i, Q b' i ->
b' <> b \/ ~(lo <= i < hi) ->
P b' i) ->
exists m2', Mem.free m2 b lo hi = Some m2' /\ magree m1' m2' Q.
Lemma magree_valid_access:
forall m1 m2 (P: locset) chunk b ofs p,
magree m1 m2 P ->
Mem.valid_access m1 chunk b ofs p ->
Mem.valid_access m2 chunk b ofs p.