(** ** Matching between C#minor's variable environment and Cminor's stack pointer *)
Inductive match_var (f: meminj) (sp: block): option (block * Z) -> option Z -> Prop :=
| match_var_local: forall b sz ofs,
Val.inject f (Vptr b Ptrofs.zero) (Vptr sp (Ptrofs.repr ofs)) ->
match_var f sp (Some(b, sz)) (Some ofs)
| match_var_global:
match_var f sp None None.
(** Matching between a C#minor environment [e] and a Cminor stack pointer [sp]. The [lo] and [hi] parameters delimit the range of addresses for the blocks referenced from [te]. *)
Record match_env (f: meminj) (cenv: compilenv)
(e: Csharpminor.env) (sp: block)
(lo hi: block) : Prop :=
mk_match_env {
(** C#minor local variables match sub-blocks of the Cminor stack data block. *)
me_vars:
forall id, match_var f sp (e!id) (cenv!id);
(** [lo, hi] is a proper interval. *)
me_low_high:
Ple lo hi;
(** Every block appearing in the C#minor environment [e] must be in the range [lo, hi]. *)
me_bounded:
forall id b sz, PTree.get id e = Some(b, sz) -> Ple lo b /\ Plt b hi;
(** All blocks mapped to sub-blocks of the Cminor stack data must be images of variables from the C#minor environment [e] *)
me_inv:
forall b delta,
f b = Some(sp, delta) ->
exists id, exists sz, PTree.get id e = Some(b, sz);
(** All C#minor blocks below [lo] (i.e. allocated before the blocks referenced from [e]) must map to blocks that are below [sp] (i.e. allocated before the stack data for the current Cminor function). *)
me_incr:
forall b tb delta,
f b = Some(tb, delta) -> Plt b lo -> Plt tb sp
}.
Ltac geninv x :=
let H := fresh in (generalize x; intro H; inv H).

(* Specifications: *)
Lemma match_env_invariant:
forall f1 cenv e sp lo hi f2,
match_env f1 cenv e sp lo hi ->
inject_incr f1 f2 ->
(forall b delta, f2 b = Some(sp, delta) -> f1 b = Some(sp, delta)) ->
(forall b, Plt b lo -> f2 b = f1 b) ->
match_env f2 cenv e sp lo hi.