(** * 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
}.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
}.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
}.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
}.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
}.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.
Lemma add_need_all_eagree: forall e e' r ne, eagree e e' (add_need_all r ne) -> eagree e e' ne.
Lemma add_need_eagree: forall e e' r nv ne, eagree e e' (add_need r nv ne) -> eagree e e' ne.
Lemma add_needs_all_eagree: forall rl e e' ne, eagree e e' (add_needs_all rl ne) -> eagree e e' ne.
Lemma add_needs_eagree: forall rl nvl e e' ne, eagree e e' (add_needs rl nvl ne) -> eagree e e' ne.
Lemma add_ros_need_eagree: forall e e' ros ne, eagree e e' (add_ros_need_all ros ne) -> eagree e e' ne.
Lemma eagree_init_regs: forall rl vl1 vl2 ne, Val.lessdef_list vl1 vl2 -> eagree (init_regs vl1 rl) (init_regs vl2 rl) ne.
Lemma symbols_preserved: forall (s: ident), Genv.find_symbol tge s = Genv.find_symbol ge s.
Lemma senv_preserved: Senv.equiv ge tge.
Lemma functions_translated: forall (v: val) (f: RTL.fundef), Genv.find_funct ge v = Some f -> exists cu tf, Genv.find_funct tge v = Some tf /\ transf_fundef (romem_for cu) f = OK tf /\ linkorder cu prog.
Lemma function_ptr_translated: forall (b: block) (f: RTL.fundef), Genv.find_funct_ptr ge b = Some f -> exists cu tf, Genv.find_funct_ptr tge b = Some tf /\ transf_fundef (romem_for cu) f = OK tf /\ linkorder cu prog.
Lemma sig_function_translated: forall rm f tf, transf_fundef rm f = OK tf -> funsig tf = funsig f.
Lemma stacksize_translated: forall rm f tf, transf_function rm f = OK tf -> tf.(fn_stacksize) = f.(fn_stacksize).