Definition genvs_domain_eq {F1 F2 V1 V2: Type}
(ge1: Genv.t F1 V1) (ge2: Genv.t F2 V2) :=
(forall b, fst (genv2blocks ge1) b <-> fst (genv2blocks ge2) b) /\
(forall b, snd (genv2blocks ge1) b <-> snd (genv2blocks ge2) b) /\
(forall b, (exists f, Genv.find_funct_ptr ge1 b = Some f)
<-> (exists f, Genv.find_funct_ptr ge2 b = Some f)).

(* Specifications: *)
Lemma genvs_domain_eq_preserves:
forall {F1 F2 V1 V2: Type} (ge1: Genv.t F1 V1) (ge2: Genv.t F2 V2) j,
genvs_domain_eq ge1 ge2 ->
(meminj_preserves_globals_ind (genv2blocks ge1) j <->
meminj_preserves_globals_ind (genv2blocks ge2) j).
Lemma genvs_domain_eq_sym:
forall {F1 F2 V1 V2: Type} (ge1: Genv.t F1 V1) (ge2: Genv.t F2 V2),
genvs_domain_eq ge1 ge2 -> genvs_domain_eq ge2 ge1.
Lemma genvs_domain_eq_refl:
forall F V (ge: Genv.t F V), genvs_domain_eq ge ge.
Lemma genvs_domain_eq_trans: forall {F1 F2 F3 V1 V2 V3: Type}
(ge1: Genv.t F1 V1) (ge2: Genv.t F2 V2) (ge3: Genv.t F3 V3),
genvs_domain_eq ge1 ge2 -> genvs_domain_eq ge2 ge3 -> genvs_domain_eq ge1 ge3.
Lemma genvs_domain_eq_match_genvs: forall {F1 V1 F2 V2:Type}
(ge1: Genv.t F1 V1) (ge2: Genv.t F2 V2),
genvs_domain_eq ge1 ge2 -> genv2blocks ge1 = genv2blocks ge2.
Lemma meminj_preserves_globals_ind_compose:
forall {F1 V1 F2 V2} (ge1: Genv.t F1 V1) (ge2: Genv.t F2 V2)
j1 j2 (G: genvs_domain_eq ge1 ge2)
(PG1: meminj_preserves_globals_ind (genv2blocks ge1) j1)
(PG2: meminj_preserves_globals_ind (genv2blocks ge2) j2),
meminj_preserves_globals_ind (genv2blocks ge1) (compose_meminj j1 j2).
Lemma meminj_preserves_incr_sep:
forall {F V:Type} ge j (PG: @meminj_preserves_globals F V ge j)
m tm (MINJ : Mem.inject j m tm)
j' (INCR : inject_incr j j') (SEP: inject_separated j j' m tm),
meminj_preserves_globals ge j'.
Lemma meminj_preserves_incr_sep_vb:
forall {F V:Type} ge j (PG: @meminj_preserves_globals F V ge j)
m tm
(VB: forall b1 b2 ofs, j b1 = Some(b2,ofs) ->
(Mem.valid_block m b1 /\ Mem.valid_block tm b2))
j' (INCR : inject_incr j j') (SEP: inject_separated j j' m tm),
meminj_preserves_globals ge j'.
Lemma mem_forward_nextblock:
forall m m', mem_forward m m' -> Ple  (Mem.nextblock m) (Mem.nextblock m').
Lemma forward_unchanged_on: forall m m' (FWD: mem_forward m m')
b ofs (NP: ~ Mem.perm m b ofs Max Nonempty),
Mem.unchanged_on (fun b' ofs' => b' = b /\ ofs' = ofs) m m'.
Lemma unchanged_on_union:
forall m m' P Q (HP: Mem.unchanged_on P m m') (HQ: Mem.unchanged_on Q m m')
(PQ: block -> Z -> Prop) (HPQ: forall b ofs, PQ b ofs -> P b ofs \/ Q b ofs),
Mem.unchanged_on PQ m m'.
Lemma unchanged_on_validblock: forall m m' (U V: Values.block -> Z -> Prop)
(UV: forall b ofs, Mem.valid_block m b -> (U b ofs -> V b ofs)),
Mem.unchanged_on V m m' -> Mem.unchanged_on U m m'.
Lemma unchanged_on_validblock_invariant: forall m m' U V
(UV: forall b ofs, Mem.valid_block m b -> (U b ofs <-> V b ofs)),
Mem.unchanged_on V m m' <-> Mem.unchanged_on U m m'.
Lemma unchanged_on_perm_intersection: forall m m' U (Fwd: mem_forward m m'),
Mem.unchanged_on U m m' <->
Mem.unchanged_on (fun b z => U b z /\ Mem.perm m b z Max Nonempty)  m m'.
Lemma unchanged_on_trans: forall m1 m2 m3 U
(U1: Mem.unchanged_on U m1 m2)
(U2: Mem.unchanged_on U m2 m3)
(Fwd12: mem_forward m1 m2),
Mem.unchanged_on U m1 m3.