(***********************************************************************)

Goal forall mu (WD: SM_wd mu) m1 m2 m2'
(U: Mem.unchanged_on (local_out_of_reach mu m1) m2 m2'),
Mem.unchanged_on (fun b ofs => pubBlocksTgt mu b = true /\
                  loc_out_of_reach (pub_of mu) m1 b ofs) m2 m2'.Goal forall mu (WD: SM_wd mu) m1 m2 m2'
(U: Mem.unchanged_on (local_out_of_reach mu m1) m2 m2'),
Mem.unchanged_on (fun b ofs => locBlocksTgt mu b = true /\
                    pubBlocksTgt mu b = false) m2 m2'.Goal forall mu m1 m2 m2' (WD:SM_wd mu)
  (U1: Mem.unchanged_on (fun b ofs => locBlocksTgt mu b = true /\
                    pubBlocksTgt mu b = false) m2 m2')
  (U2: Mem.unchanged_on (fun b ofs => pubBlocksTgt mu b = true /\
                  loc_out_of_reach (pub_of mu) m1 b ofs) m2 m2'),
Mem.unchanged_on (local_out_of_reach mu m1) m2 m2'.

(* Specifications: *)
Lemma eff_atexternal_check: forall {F1 V1 C1 F2 V2 C2:Type} (ge1: Genv.t F1 V1) (ge2: Genv.t F2 V2) mu (WDmu: SM_wd mu) (GenvsDomEq: genvs_domain_eq ge1 ge2) m1 m2 (MemInjMu: Mem.inject (as_inj mu) m1 m2) vals1 vals2 (ValInjMu: Forall2 (val_inject (as_inj mu)) vals1 vals2) (MatchGenv: meminj_preserves_globals ge1 (extern_of mu) /\ (forall b, isGlobalBlock ge1 b = true -> frgnBlocksSrc mu b = true)), (forall b, isGlobalBlock ge1 b = true -> REACH m1 (exportedSrc mu vals1) b = true) /\ (forall b, isGlobalBlock ge2 b = true -> REACH m2 (exportedTgt mu vals2) b = true).
Lemma eff_after_check1: forall mu (WD: SM_wd mu) m1 m2 (SMValMu: sm_valid mu m1 m2) (*selected standard assumptions:*) (MemInjMu: Mem.inject (as_inj mu) m1 m2) vals1 vals2 (ValInjMu: Forall2 (val_inject (as_inj mu)) vals1 vals2) pubSrc' (pubSrcHyp: pubSrc' = fun b => andb (locBlocksSrc mu b) (REACH m1 (exportedSrc mu vals1) b)) pubTgt' (pubTgtHyp: pubTgt' = fun b => andb (locBlocksTgt mu b) (REACH m2 (exportedTgt mu vals2) b)) nu (NuHyp: nu = replace_locals mu pubSrc' pubTgt'), SM_wd nu /\ sm_valid nu m1 m2 /\ Mem.inject (as_inj nu) m1 m2 /\ Forall2 (val_inject (as_inj nu)) vals1 vals2.
Lemma eff_after_check2: forall nu' ret1 m1' m2' ret2 (MemInjNu': Mem.inject (as_inj nu') m1' m2') (RValInjNu': val_inject (as_inj nu') ret1 ret2) frgnSrc' (frgnSrcHyp: frgnSrc' = fun b => andb (DomSrc nu' b) (andb (negb (locBlocksSrc nu' b)) (REACH m1' (exportedSrc nu' (ret1::nil)) b))) frgnTgt' (frgnTgtHyp: frgnTgt' = fun b => andb (DomTgt nu' b) (andb (negb (locBlocksTgt nu' b)) (REACH m2' (exportedTgt nu' (ret2::nil)) b))) mu' (Mu'Hyp: mu' = replace_externs nu' frgnSrc' frgnTgt') (WD: SM_wd nu') (SMValid: sm_valid nu' m1' m2'), SM_wd mu' /\ sm_valid mu' m1' m2'.
Lemma eff_after_check3: forall nu' ret1 m1' m2' ret2 (MemInjNu': Mem.inject (as_inj nu') m1' m2') (RValInjNu': val_inject (as_inj nu') ret1 ret2) frgnSrc' (frgnSrcHyp: frgnSrc' = fun b => andb (DomSrc nu' b) (andb (negb (locBlocksSrc nu' b)) (REACH m1' (exportedSrc nu' (ret1::nil)) b))) frgnTgt' (frgnTgtHyp: frgnTgt' = fun b => andb (DomTgt nu' b) (andb (negb (locBlocksTgt nu' b)) (REACH m2' (exportedTgt nu' (ret2::nil)) b))) mu' (Mu'Hyp: mu' = replace_externs nu' frgnSrc' frgnTgt'), Mem.inject (as_inj mu') m1' m2' /\ val_inject (as_inj mu') ret1 ret2.
Lemma eff_after_check4: forall mu pubSrc' pubTgt' nu (NuHyp: nu = replace_locals mu pubSrc' pubTgt') nu' (INC: extern_incr nu nu') mu' frgnSrc' frgnTgt' (Mu'Hyp: mu' = replace_externs nu' frgnSrc' frgnTgt') (SMwdNu': SM_wd nu'), inject_incr (as_inj mu) (as_inj mu').
Lemma eff_after_check5a: forall mu pubSrc' pubTgt' nu (NuHyp: nu = replace_locals mu pubSrc' pubTgt') kappa m1 m2 (SEP: sm_inject_separated nu kappa m1 m2), sm_inject_separated mu kappa m1 m2.
Lemma eff_after_check5b: forall nu' mu' frgnSrc' frgnTgt' (Mu'Hyp: mu' = replace_externs nu' frgnSrc' frgnTgt') kappa m1 m2 (SEP: sm_inject_separated kappa nu' m1 m2), sm_inject_separated kappa mu' m1 m2.
Lemma eff_after_check5: forall mu pubSrc' pubTgt' nu (NuHyp: nu = replace_locals mu pubSrc' pubTgt') nu' mu' frgnSrc' frgnTgt' (Mu'Hyp: mu' = replace_externs nu' frgnSrc' frgnTgt') m1 m2 (SEP: sm_inject_separated nu nu' m1 m2), sm_inject_separated mu mu' m1 m2.
Lemma eff_after_check5_explicitProof: forall mu pubSrc' pubTgt' nu (NuHyp: nu = replace_locals mu pubSrc' pubTgt') nu' mu' frgnSrc' frgnTgt' (Mu'Hyp: mu' = replace_externs nu' frgnSrc' frgnTgt') m1 m2 (SEP: sm_inject_separated nu nu' m1 m2), sm_inject_separated mu mu' m1 m2.
Lemma halted_check_aux: forall mu m1 v1 b1 b2 delta (WD: SM_wd mu), join (foreign_of mu) (fun b => if locBlocksSrc mu b && REACH m1 (exportedSrc mu (v1 :: nil)) b then local_of mu b else None) b1 = Some (b2, delta) -> as_inj mu b1= Some (b2, delta).
Lemma halted_loc_check_aux: forall mu m1 v1 b1 b2 delta (WD: SM_wd mu), join (foreign_of mu) (fun b => if locBlocksSrc mu b && REACH m1 (exportedSrc mu (v1 :: nil)) b then local_of mu b else None) b1 = Some (b2, delta) -> locvisible_of mu b1= Some (b2, delta).
Lemma halted_loc_check: forall mu m1 m2 v1 v2 (MInj: Mem.inject (locvisible_of mu) m1 m2) (VInj: val_inject (locvisible_of mu) v1 v2) (WD: SM_wd mu), exists pubSrc' pubTgt' nu, (pubSrc' = fun b => (locBlocksSrc mu b) && (REACH m1 (exportedSrc mu (v1::nil)) b)) /\ (pubTgt' = fun b => (locBlocksTgt mu b) && (REACH m2 (exportedTgt mu (v2::nil)) b)) /\ (nu = replace_locals mu pubSrc' pubTgt') /\ SM_wd nu /\ val_inject (shared_of nu) v1 v2 /\ Mem.inject (shared_of nu) m1 m2.
Lemma intern_incr_vis_inv: forall mu nu (WDmu: SM_wd mu) (WDnu: SM_wd nu) (INC: intern_incr mu nu) b1 b2 d (AI: as_inj mu b1 = Some(b2,d)) (VIS: vis nu b1 = true), vis mu b1 = true.
Lemma intern_incr_vis: forall mu nu (INC: intern_incr mu nu) b (VIS: vis mu b = true), vis nu b = true.
Lemma restrict_sm_intern_incr: forall mu1 mu2 (WD2 : SM_wd mu2) (INC : intern_incr mu1 mu2), intern_incr (restrict_sm mu1 (vis mu1)) (restrict_sm mu2 (vis mu2)).
Lemma intern_incr_restrict: forall mu1 mu2 (WD2 : SM_wd mu2) (INC : intern_incr mu1 mu2), inject_incr (restrict (as_inj mu1) (vis mu1)) (restrict (as_inj mu2) (vis mu2)).
Lemma vis_restrict_sm: forall mu X, vis (restrict_sm mu X) = vis mu.
Lemma REACH_split: forall m X Y b (RCH:REACH m (fun b' => X b' || Y b') b = true), REACH m X b = true \/ REACH m Y b = true.
Lemma reachD: forall m R L b (RCH :reach m (fun u => R u = true) L b), exists r, R r = true /\ reach m (fun bb => bb=r) L b.
Lemma reachD': forall m R L b (RCH :reach m (fun u => R u = true) L b), exists r, R r = true /\ reach m (fun bb => bb=r) L b /\ match rev L with nil => True | HD::TL => exists z, HD = (r,z) end.
Lemma reachD'': forall m R L b (RCH :reach m (fun u => R u = true) L b), exists r M, R r = true /\ reach m (fun bb => bb=r) M b /\ match rev M with nil => True | HD::TL => exists z, HD = (r,z) /\ (forall zz, ~ In (r,zz) TL) /\ (forall x zx, R x = true -> In (x,zx) M -> x=r) end.
Lemma encode_val_pointer_inv': forall chunk v b ofs n B1 mvl, encode_val chunk v = B1++Pointer b ofs n :: mvl -> chunk = Mint32 /\ v = Vptr b ofs.
Lemma list_split: forall {A} n (L:list A) (Hn : (n < length L)%nat), exists vl1 u vl2, L = vl1 ++ u :: vl2 /\ length vl1 = n.
Lemma REACH_Store: forall m chunk b i v m' (ST: Mem.store chunk m b (Int.unsigned i) v = Some m') Roots (VISb: Roots b = true) (VISv : forall b', getBlocks (v :: nil) b' = true -> Roots b' = true) (R: REACH_closed m Roots), REACH_closed m' Roots.
Lemma REACH_Storebytes: forall m b i bytes m' (ST: Mem.storebytes m b (Int.unsigned i) bytes = Some m') Roots (VISb: Roots b = true) (VISv : forall b' z n, In (Pointer b' z n) bytes -> Roots b' = true) (R: REACH_closed m Roots), REACH_closed m' Roots.
Lemma REACH_load_vis: forall chunk m b i b1 ofs1 (LD: Mem.load chunk m b (Int.unsigned i) = Some (Vptr b1 ofs1)) mu (VIS: vis mu b = true), REACH m (vis mu) b1 = true.
Lemma nextblock_storev: forall chunk m addr v m', Mem.storev chunk m addr v = Some m' -> Mem.nextblock m' = Mem.nextblock m.
Lemma nextblock_freelist: forall fbl m m', Mem.free_list m fbl = Some m' -> Mem.nextblock m' = Mem.nextblock m.
Lemma perm_freelist: forall fbl m m' b ofs k p, Mem.free_list m fbl = Some m' -> Mem.perm m' b ofs k p -> Mem.perm m b ofs k p.
Lemma store_freshloc: forall ch m addr v m' (ST: Mem.storev ch m addr v = Some m'), freshloc m m' = fun b => false.
Lemma freshloc_alloc: forall m1 lo hi m2 b (ALLOC: Mem.alloc m1 lo hi = (m2, b)), freshloc m1 m2 = fun bb => eq_block bb b.
Lemma freshloc_free: forall m sp i n m' (F: Mem.free m sp i n = Some m'), freshloc m m' = fun b => false.
Lemma freshloc_free_list: forall m n m' (F: Mem.free_list m n = Some m'), freshloc m m' = fun b => false.
Lemma free_parallel_inject: forall j (m1 m2 : mem) (b : block) (lo hi : Z) (m1' : mem) , Mem.inject j m1 m2 -> Mem.free m1 b lo hi = Some m1' -> forall b2 d (J: j b = Some(b2,d)), exists m2' : mem, Mem.free m2 b2 (lo+d) (hi+d) = Some m2' /\ Mem.inject j m1' m2'.
Lemma REACH_closed_free: forall m1 b lo hi m2 (F: Mem.free m1 b lo hi = Some m2) X (RC: REACH_closed m1 X), REACH_closed m2 X.
Lemma REACH_closed_freelist: forall X l m m' (FL : Mem.free_list m l = Some m') (RC : REACH_closed m X), REACH_closed m' X.