(* A minimal preservation property we sometimes require. *)
(* Definition readonly {F V} (ge: Genv.t F V) m1 b m2 := forall gv, Genv.find_var_info ge b = Some gv -> gvar_readonly gv && negb (gvar_volatile gv) = true -> forall ch ofs, Mem.load ch m2 b ofs = Mem.load ch m1 b ofs. *)
Definition readonlyLD m1 b m2 :=
forall chunk ofs
(NWR: forall ofs', ofs <= ofs' < ofs + size_chunk chunk ->
~(Mem.perm m1 b ofs' Cur Writable)),
Mem.load chunk m2 b ofs = Mem.load chunk m1 b ofs /\
(forall ofs', ofs <= ofs' < ofs + size_chunk chunk ->
(forall k p, Mem.perm m1 b ofs' k p <-> Mem.perm m2 b ofs' k p)).
Definition readonly m1 b m2 :=
forall n ofs
(NWR: forall i, 0 <= i < n ->
~(Mem.perm m1 b (ofs + i) Cur Writable)),
Mem.loadbytes m2 b ofs n = Mem.loadbytes m1 b ofs n /\
(forall i, 0 <= i < n ->
(forall k p, Mem.perm m1 b (ofs+i) k p <-> Mem.perm m2 b (ofs+i) k p)).
Definition max_readonlyLD m1 b m2 :=
forall chunk ofs
(NWR: forall ofs', ofs <= ofs' < ofs + size_chunk chunk ->
~(Mem.perm m1 b ofs' Max Writable)),
Mem.load chunk m2 b ofs = Mem.load chunk m1 b ofs /\
(forall ofs', ofs <= ofs' < ofs + size_chunk chunk ->
(forall k p, Mem.perm m1 b ofs' k p <-> Mem.perm m2 b ofs' k p)).
Definition max_readonly m1 b m2 :=
forall n ofs
(NWR: forall i, 0 <= i < n ->
~(Mem.perm m1 b (ofs + i) Max Writable)),
Mem.loadbytes m2 b ofs n = Mem.loadbytes m1 b ofs n /\
(forall i, 0 <= i < n ->
(forall k p, Mem.perm m1 b (ofs+i) k p <-> Mem.perm m2 b (ofs+i) k p)).

(* Specifications: *)
Lemma readonlyLD_max_readonlyLD m1 b m2: readonlyLD m1 b m2 -> max_readonlyLD m1 b m2.
Lemma readonly_max_readonly m1 b m2: readonly m1 b m2 -> max_readonly m1 b m2.
Lemma readonly_readonlyLD m1 b m2: readonly m1 b m2 -> readonlyLD m1 b m2.
Lemma readonly_refl m b: readonly m b m.
Lemma readonly_trans m1 m2 m3 b: readonly m1 b m2 -> readonly m2 b m3 -> readonly m1 b m3.
Definition mem_forward (m1 m2:mem) :=
forall b, Mem.valid_block m1 b ->
(Mem.valid_block m2 b
/\ (forall ofs p, Mem.perm m2 b ofs Max p -> Mem.perm m1 b ofs Max p)
(*/\ readonly m1 b m2*)).  Lemma mem_forward_refl: forall m, mem_forward m m.  Lemma mem_forward_trans: forall m1 m2 m3, mem_forward m1 m2 -> mem_forward m2 m3 -> mem_forward m1 m3.  Lemma forward_unchanged_trans: forall P m1 m2 m3, Mem.unchanged_on P m1 m2 -> Mem.unchanged_on P m2 m3 -> mem_forward m1 m2 -> mem_forward m2 m3 -> mem_forward m1 m3 /\ Mem.unchanged_on P m1 m3.  Lemma matchOptE: forall {A} (a:option A) (P: A -> Prop), match a with Some b => P b | None => False end -> exists b, a = Some b /\ P b.  Lemma compose_meminjD_Some: forall j jj b b2 ofs2, (compose_meminj j jj) b = Some(b2,ofs2) -> exists b1, exists ofs1, exists ofs, j b = Some(b1,ofs1) /\ jj b1 = Some(b2,ofs) /\ ofs2=ofs1+ofs.  Lemma compose_meminj_inject_incr: forall j12 j12' j23 j23' (InjIncr12: inject_incr j12 j12') (InjIncr23: inject_incr j23 j23'), inject_incr (compose_meminj j12 j23) (compose_meminj j12' j23').  Lemma compose_meminj_inject_separated: forall j12 j12' j23 j23' m1 m2 m3 (InjSep12 : inject_separated j12 j12' m1 m2) (InjSep23 : inject_separated j23 j23' m2 m3) (InjIncr12: inject_incr j12 j12') (InjIncr23: inject_incr j23 j23') (BV12: forall b1 b2 ofs, j12 b1 = Some (b2,ofs) -> Mem.valid_block m1 b1 /\ Mem.valid_block m2 b2) (BV23: forall b1 b2 ofs, j23 b1 = Some (b2,ofs) -> Mem.valid_block m2 b1 /\ Mem.valid_block m3 b2), inject_separated (compose_meminj j12 j23) (compose_meminj j12' j23') m1 m3.  Lemma compose_meminj_inject_separated': forall j12 j12' j23 j23' m1 m2 m3 (InjSep12 : inject_separated j12 j12' m1 m2) (InjSep23 : inject_separated j23 j23' m2 m3) (InjIncr12: inject_incr j12 j12') (InjIncr23: inject_incr j23 j23') (MInj12: Mem.inject j12 m1 m2) (MInj23: Mem.inject j23 m2 m3), inject_separated (compose_meminj j12 j23) (compose_meminj j12' j23') m1 m3.  Lemma forall_lessdef_refl: forall vals,  Forall2 Val.lessdef vals vals.  Lemma valinject_hastype:  forall j v v' (V: (val_inject j) v v') T, Val.has_type v' T -> Val.has_type v T.  Definition val_inject_opt (j: meminj) (v1 v2: option val) := match v1, v2 with Some v1', Some v2' => val_inject j v1' v2' | None, None => True | _, _ => False end.  Lemma val_inject_split: forall v1 v3 j12 j23 (V: val_inject (compose_meminj j12 j23) v1 v3), exists v2, val_inject j12 v1 v2 /\ val_inject j23 v2 v3.  Lemma forall_lessdef_trans: forall vals1 vals2 (V12: Forall2 Val.lessdef vals1 vals2) vals3  (V23: Forall2 Val.lessdef vals2 vals3), Forall2 Val.lessdef vals1 vals3.  Lemma extends_loc_out_of_bounds: forall m1 m2 (Ext: Mem.extends m1 m2) b ofs, loc_out_of_bounds m2 b ofs -> loc_out_of_bounds m1 b ofs.  Lemma extends_loc_out_of_reach: forall m1 m2 (Ext: Mem.extends m1 m2) b ofs j (Hj: loc_out_of_reach j m2 b ofs), loc_out_of_reach j m1 b ofs.  Lemma valinject_lessdef: forall v1 v2 v3 j (V12:val_inject j v1 v2) (V23 : Val.lessdef v2 v3), val_inject j v1 v3.  Lemma forall_valinject_lessdef: forall vals1 vals2 j (VInj12 : Forall2 (val_inject j) vals1 vals2) vals3 (LD23 : Forall2 Val.lessdef vals2 vals3), Forall2 (val_inject j) vals1 vals3.  Lemma val_lessdef_inject_compose: forall v1 v2 (LD12 : Val.lessdef v1 v2) j v3 (InjV23 : val_inject j v2 v3), val_inject j v1 v3.  Lemma forall_val_lessdef_inject_compose: forall v1 v2 (LD12 : Forall2 Val.lessdef v1 v2) j v3 (InjV23 : Forall2 (val_inject j) v2 v3), Forall2 (val_inject j) v1 v3.  Lemma forall_val_inject_compose: forall vals1 vals2 j1 (ValsInj12 : Forall2 (val_inject j1) vals1 vals2) vals3 j2 (ValsInj23 : Forall2 (val_inject j2) vals2 vals3), Forall2 (val_inject (compose_meminj j1 j2)) vals1 vals3.  Lemma val_inject_flat: forall m1 m2 j (Inj: Mem.inject j m1 m2) v1 v2 (V: val_inject j v1 v2), val_inject  (Mem.flat_inj (Mem.nextblock m1)) v1 v1.  Lemma forall_val_inject_flat: forall m1 m2 j (Inj: Mem.inject j m1 m2) vals1 vals2 (V: Forall2 (val_inject j) vals1 vals2), Forall2 (val_inject  (Mem.flat_inj (Mem.nextblock m1))) vals1 vals1.  Lemma po_trans: forall a b c, Mem.perm_order'' a b ->  Mem.perm_order'' b c -> Mem.perm_order'' a c.  Lemma extends_perm: forall m1 m2 (Ext: Mem.extends m1 m2) b ofs k p, Mem.perm m1 b ofs k p -> Mem.perm m2 b ofs k p.  Lemma extends_permorder: forall m1 m2 (Ext: Mem.extends m1 m2) (b:block) ofs k, Mem.perm_order'' (PMap.get b (Mem.mem_access m2) ofs k) (PMap.get b (Mem.mem_access m1) ofs k).  Lemma fwd_maxperm: forall m1 m2 (FWD: mem_forward m1 m2) b (V:Mem.valid_block m1 b) ofs p, Mem.perm m2 b ofs Max p -> Mem.perm m1 b ofs Max p.  Lemma po_oo: forall p q, Mem.perm_order' p q = Mem.perm_order'' p (Some q).  Lemma PermExtNotnonempty: forall m1 m2 (Inj: Mem.extends m1 m2) b ofs p (H: ~ Mem.perm m2 b ofs p Nonempty), ~Mem.perm m1 b ofs p Nonempty.  Lemma PermInjNotnonempty: forall j m1 m2 (Inj: Mem.inject j m1 m2) b b2 delta (J:j b = Some(b2,delta)) ofs p (H: ~Mem.perm m2 b2 (ofs+delta) p Nonempty), ~Mem.perm m1 b ofs p Nonempty.  Lemma inject_LOOR_LOOB: forall m1 m2 j (Minj12 : Mem.inject j m1 m2) m3 m3', Mem.unchanged_on (loc_out_of_reach j m1) m3 m3' -> Mem.unchanged_on (loc_out_of_bounds m2) m3 m3'.  Lemma free_neutral: forall (thr : block) (m : mem) (lo hi : Z) (b : block) (m' : Mem.mem') (FREE: Mem.free m b lo hi = Some m'), Mem.inject_neutral thr m -> Mem.inject_neutral thr m'.  Lemma getN_aux: forall n p c B1 v B2, Mem.getN n p c = B1 ++ v::B2 -> v = ZMap.get (p + Z.of_nat (length B1)) c.  Lemma getN_range: forall n ofs M bytes1 v bytes2, Mem.getN n ofs M = bytes1 ++ v::bytes2 -> (length bytes1 < n)%nat.  Lemma loadbytes_D: forall m b ofs n bytes (LD: Mem.loadbytes m b ofs n = Some bytes), Mem.range_perm m b ofs (ofs + n) Cur Readable /\ bytes = Mem.getN (nat_of_Z n) ofs (PMap.get b (Mem.mem_contents m)).  (*A new lemma, used in CompCert2.5 where CompComp-4-CompCert2.1 used decode_val_pointer_inv*)
Lemma load_ptr_is_fragment ch m b ofs b0 i
(LD: Mem.load ch m b ofs = Some (Vptr b0 i)):
exists q n, ZMap.get ofs (Mem.mem_contents m) !! b = Fragment (Vptr b0 i) q n.
(******** Compatibility of memory operation with [mem_forward] ********)
Lemma load_storebytes_nil m b ofs m': Mem.storebytes m b ofs nil = Some m' ->
forall ch bb z, Mem.load ch m' bb z = Mem.load ch m bb z.
Lemma loadbytes_storebytes_nil m b ofs m': Mem.storebytes m b ofs nil = Some m' ->
forall n bb z, Mem.loadbytes m' bb z n = Mem.loadbytes m bb z n.
Lemma storebytes_forward: forall m b ofs bytes m'
(M: Mem.storebytes m b ofs bytes = Some m'),
mem_forward m m'.
Lemma storebytes_readonlyLD: forall m b ofs bytes m'
(M: Mem.storebytes m b ofs bytes = Some m'),
forall b, Mem.valid_block m b -> readonlyLD m b m'.
Lemma storebytes_readonly: forall m b ofs bytes m'
(M: Mem.storebytes m b ofs bytes = Some m'),
forall b, Mem.valid_block m b -> readonly m b m'.
Lemma store_forward: forall m b ofs v ch m'
(M:Mem.store ch m b ofs v = Some m'),
mem_forward m m'.
Lemma store_readonly: forall m b ofs v ch m'
(M:Mem.store ch m b ofs v = Some m'),
forall b, Mem.valid_block m b -> readonly m b m'.