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.

(* Specifications: *)
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)).
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)).