(** * Correctness of stack allocation of local variables *)

(** This section shows the correctness of the translation of Csharpminor
  local variables as sub-blocks of the Cminor stack data.  This is the most difficult part of the proof. *)

Definition cenv_remove (cenv: compilenv) (vars: list (ident * Z)) : compilenv :=
  fold_right (fun id_lv ce => PTree.remove (fst id_lv) ce) cenv vars.Remark cenv_remove_gso:
  forall id vars cenv,
  ~In id (map fst vars) ->
  PTree.get id (cenv_remove cenv vars) = PTree.get id cenv.Remark cenv_remove_gss:
  forall id vars cenv,
  In id (map fst vars) ->
  PTree.get id (cenv_remove cenv vars) = None.Definition cenv_compat (cenv: compilenv) (vars: list (ident * Z)) (tsz: Z) : Prop :=
  forall id sz,
  In (id, sz) vars ->
  exists ofs,
      PTree.get id cenv = Some ofs
   /\ Mem.inj_offset_aligned ofs sz
   /\ 0 <= ofs
   /\ ofs + Zmax 0 sz <= tsz.Definition cenv_separated (cenv: compilenv) (vars: list (ident * Z)) : Prop :=
  forall id1 sz1 ofs1 id2 sz2 ofs2,
  In (id1, sz1) vars -> In (id2, sz2) vars ->
  PTree.get id1 cenv = Some ofs1 -> PTree.get id2 cenv = Some ofs2 ->
  id1 <> id2 ->
  ofs1 + sz1 <= ofs2 \/ ofs2 + sz2 <= ofs1.Definition cenv_mem_separated (cenv: compilenv) (vars: list (ident * Z)) (f: meminj) (sp: block) (m: mem) : Prop :=
  forall id sz ofs b delta ofs' k p,
  In (id, sz) vars -> PTree.get id cenv = Some ofs ->
  f b = Some (sp, delta) ->
  Mem.perm m b ofs' k p ->
  ofs <= ofs' + delta < sz + ofs -> False.(** Properties of the compilation environment produced by [build_compilenv] *)

Remark block_alignment_pos:
  forall sz, block_alignment sz > 0.Remark assign_variable_incr:
  forall id sz cenv stksz cenv' stksz',
  assign_variable (cenv, stksz) (id, sz) = (cenv', stksz') -> stksz <= stksz'.Remark assign_variables_incr:
  forall vars cenv sz cenv' sz',
  assign_variables (cenv, sz) vars = (cenv', sz') -> sz <= sz'.Remark inj_offset_aligned_block:
  forall stacksize sz,
  Mem.inj_offset_aligned (align stacksize (block_alignment sz)) sz.Remark inj_offset_aligned_block':
  forall stacksize sz,
  Mem.inj_offset_aligned (align stacksize (block_alignment sz)) (Zmax 0 sz).

(* Specifications: *)
Lemma assign_variable_sound: forall cenv1 sz1 id sz cenv2 sz2 vars, assign_variable (cenv1, sz1) (id, sz) = (cenv2, sz2) -> ~In id (map fst vars) -> 0 <= sz1 -> cenv_compat cenv1 vars sz1 -> cenv_separated cenv1 vars -> cenv_compat cenv2 (vars ++ (id, sz) :: nil) sz2 /\ cenv_separated cenv2 (vars ++ (id, sz) :: nil).
Lemma assign_variables_sound: forall vars' cenv1 sz1 cenv2 sz2 vars, assign_variables (cenv1, sz1) vars' = (cenv2, sz2) -> list_norepet (map fst vars' ++ map fst vars) -> 0 <= sz1 -> cenv_compat cenv1 vars sz1 -> cenv_separated cenv1 vars -> cenv_compat cenv2 (vars ++ vars') sz2 /\ cenv_separated cenv2 (vars ++ vars').
Lemma assign_variable_sound: forall cenv1 sz1 id sz cenv2 sz2 vars, assign_variable (cenv1, sz1) (id, sz) = (cenv2, sz2) -> ~In id (map fst vars) -> 0 <= sz1 -> cenv_compat cenv1 vars sz1 -> cenv_separated cenv1 vars -> cenv_compat cenv2 (vars ++ (id, sz) :: nil) sz2 /\ cenv_separated cenv2 (vars ++ (id, sz) :: nil).
Lemma assign_variables_sound: forall vars' cenv1 sz1 cenv2 sz2 vars, assign_variables (cenv1, sz1) vars' = (cenv2, sz2) -> list_norepet (map fst vars' ++ map fst vars) -> 0 <= sz1 -> cenv_compat cenv1 vars sz1 -> cenv_separated cenv1 vars -> cenv_compat cenv2 (vars ++ vars') sz2 /\ cenv_separated cenv2 (vars ++ vars').