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.

Lemma contains_callee_saves_exten:
forall j sp ls ls' rl pos,
(forall r, In r rl -> ls' (R r) = ls (R r)) ->
massert_eqv (contains_callee_saves j sp pos rl ls)
(contains_callee_saves j sp pos rl ls').