Section FRAME_PROPERTIES.
Variable f: Linear.function.
Let b := function_bounds f.
Let fe := make_env b.
Variable tf: Mach.function.
Hypothesis TRANSF_F: transf_function f = OK tf.
Remark bound_stack_data_stacksize:
f.(Linear.fn_stacksize) <= b.(bound_stack_data).
(** * Memory assertions used to describe the contents of stack frames *)
Local Opaque Z.add Z.mul Z.divide.
(** Accessing the stack frame using [load_stack] and [store_stack]. *)
(** [contains_locations j sp pos bound sl ls] is a separation logic assertion that holds if the memory area at block [sp], offset [pos], size [4 * bound], reflects the values of the stack locations of kind [sl] given by the location map [ls], up to the memory injection [j].  Two such [contains_locations] assertions will be used later, one to reason about the values of [Local] slots, the other about the values of [Outgoing] slots. *)
Program Definition contains_locations (j: meminj) (sp: block) (pos bound: Z) (sl: slot) (ls: locset) : massert := {|
m_pred := fun m =>
(8 | pos) /\ 0 <= pos /\ pos + 4 * bound <= Ptrofs.modulus /\
Mem.range_perm m sp pos (pos + 4 * bound) Cur Freeable /\
forall ofs ty, 0 <= ofs -> ofs + typesize ty <= bound -> (typealign ty | ofs) ->
exists v, Mem.load (chunk_of_type ty) m sp (pos + 4 * ofs) = Some v
/\ Val.inject j (ls (S sl ofs ty)) v;
m_footprint := fun b ofs =>
b = sp /\ pos <= ofs < pos + 4 * bound
|}.
Next Obligation.
intuition auto.
- red; intros. eapply Mem.perm_unchanged_on; eauto. simpl; auto.
- exploit H4; eauto. intros (v & A & B). exists v; split; auto.
eapply Mem.load_unchanged_on; eauto.
simpl; intros. rewrite size_type_chunk, typesize_typesize in H8.
split; auto. omega.
Qed.
Next Obligation.
eauto with mem.
Qed.
Remark valid_access_location:
forall m sp pos bound ofs ty p,
(8 | pos) ->
Mem.range_perm m sp pos (pos + 4 * bound) Cur Freeable ->
0 <= ofs -> ofs + typesize ty <= bound -> (typealign ty | ofs) ->
Mem.valid_access m (chunk_of_type ty) sp (pos + 4 * ofs) p.
(** [contains_callee_saves j sp pos rl ls] is a memory assertion that holds if block [sp], starting at offset [pos], contains the values of the callee-save registers [rl] as given by the location map [ls], up to the memory injection [j].  The memory layout of the registers in [rl] is the same as that implemented by [save_callee_save_rec]. *)
Fixpoint contains_callee_saves (j: meminj) (sp: block) (pos: Z) (rl: list mreg) (ls: locset) : massert :=
match rl with
| nil => pure True
| r :: rl =>
let ty := mreg_type r in
let sz := AST.typesize ty in
let pos1 := align pos sz in
contains (chunk_of_type ty) sp pos1 (fun v => Val.inject j (ls (R r)) v)
** contains_callee_saves j sp (pos1 + sz) rl ls
end.
(** Separation logic assertions describing the stack frame at [sp]. It must contain: - the values of the [Local] stack slots of [ls], as per [contains_locations] - the values of the [Outgoing] stack slots of [ls], as per [contains_locations] - the [parent] pointer representing the back link to the caller's frame - the [retaddr] pointer representing the saved return address - the initial values of the used callee-save registers as given by [ls0], as per [contains_callee_saves].  In addition, we use a nonseparating conjunction to record the fact that we have full access rights on the stack frame, except the part that represents the Linear stack data. *)
Definition frame_contents_1 (j: meminj) (sp: block) (ls ls0: locset) (parent retaddr: val) :=
contains_locations j sp fe.(fe_ofs_local) b.(bound_local) Local ls
** contains_locations j sp fe_ofs_arg b.(bound_outgoing) Outgoing ls
** hasvalue Mptr sp fe.(fe_ofs_link) parent
** hasvalue Mptr sp fe.(fe_ofs_retaddr) retaddr
** contains_callee_saves j sp fe.(fe_ofs_callee_save) b.(used_callee_save) ls0.
Definition frame_contents (j: meminj) (sp: block) (ls ls0: locset) (parent retaddr: val) :=
mconj (frame_contents_1 j sp ls ls0 parent retaddr)
(range sp 0 fe.(fe_stack_data) **
range sp (fe.(fe_stack_data) + b.(bound_stack_data)) fe.(fe_size)).
(** Accessing components of the frame. *)

Lemma frame_get_local:
forall ofs ty j sp ls ls0 parent retaddr m P,
m |= frame_contents j sp ls ls0 parent retaddr ** P ->
slot_within_bounds b Local ofs ty -> slot_valid f Local ofs ty = true ->
exists v,
load_stack m (Vptr sp Ptrofs.zero) ty (Ptrofs.repr (offset_local fe ofs)) = Some v
/\ Val.inject j (ls (S Local ofs ty)) v.