Notation val_inject:= Val.inject.
(* 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)).
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)
(* 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 storebytes_forward: forall m b ofs bytes m' (M: Mem.storebytes m b ofs bytes = Some m'), mem_forward m m'. *)
(* Lemma unchanged_on_sym P m m' b: Mem.unchanged_on P m m' -> Mem.valid_block m b -> Mem.unchanged_on (fun bb z => P bb z /\ bb=b) m' m. *)
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)).
(* Does not hold, since readonly refers to Cur permissions Lemma ec_readonly_strong: forall (ef : external_function) (F V : Type) (ge : Genv.t F V) (vargs : list val) (m1 : mem) (t : trace) (vres : val) (m2 : mem) (EC: external_call ef ge vargs m1 t vres m2) b (VB: Mem.valid_block m1 b), readonly m1 b m2. *)
(* Does not hold, since readonlyLD refers to Cur permissions Lemma external_call_readonlyLD: forall (ef : external_function) (F V : Type) (ge : Genv.t F V) (vargs : list val) (m1 : mem) (t : trace) (vres : val) (m2 : mem), external_call ef ge vargs m1 t vres m2 -> forall b, Mem.valid_block m1 b -> readonlyLD m1 b m2. *)
Definition val_has_type_opt' (v: option val) (ty: typ) :=
match v with
| None => True
| Some v' => Val.has_type v' ty
end.
Definition val_has_type_opt (v: option val) (sig: signature) :=
val_has_type_opt' v (proj_sig_res sig).
Definition is_vundef (v : val) : bool :=
match v with
| Vundef => true
| _ => false
end.
Definition vals_def (vs : list val) :=
List.forallb (fun v => negb (is_vundef v)) vs.
Definition genv2blocksBool {F V : Type} (ge : Genv.t F V):=
(fun b =>
match Genv.invert_symbol ge b with
Some id => true
| None => false
end,
fun b => match Genv.find_var_info ge b with
Some gv => true
| None => false
end).
Definition isGlobalBlock {F V : Type} (ge : Genv.t F V) :=
fun b => (fst (genv2blocksBool ge)) b || (snd (genv2blocksBool ge)) b.
Definition ReadOnlyBlocks {F V} (ge: Genv.t F V) (b:block): bool :=
match Genv.find_var_info ge b with
None => false
| Some gv => gvar_readonly gv && negb (gvar_volatile gv)
end.
Definition RDOnly_fwd (m1 m1':mem) B :=
forall b (Hb: B b = true), readonly m1 b m1'.
Definition mem_respects_readonly {F V} (ge : Genv.t F V) m :=
forall b gv, Genv.find_var_info ge b = Some gv ->
gvar_readonly gv && negb (gvar_volatile gv) = true ->
Genv.load_store_init_data ge m b 0 (gvar_init gv) /\
Mem.valid_block m b /\ (forall ofs : Z, ~ Mem.perm m b ofs Max Writable).

Lemma mem_respects_readonly_forward' {F V} (ge : Genv.t F V) m m'
(MRR: mem_respects_readonly ge m)
(FWD: mem_forward m m')
(RDO: RDOnly_fwd m m' (ReadOnlyBlocks ge)):
mem_respects_readonly ge m'.