aboutsummaryrefslogtreecommitdiffstats
path: root/backend/Stackingproof.v
diff options
context:
space:
mode:
Diffstat (limited to 'backend/Stackingproof.v')
-rw-r--r--backend/Stackingproof.v2806
1 files changed, 1030 insertions, 1776 deletions
diff --git a/backend/Stackingproof.v b/backend/Stackingproof.v
index a76fdbba..15953131 100644
--- a/backend/Stackingproof.v
+++ b/backend/Stackingproof.v
@@ -16,11 +16,13 @@
Require Import Coqlib Errors.
Require Import Integers AST Linking.
-Require Import Values Memory Events Globalenvs Smallstep.
+Require Import Values Memory Separation Events Globalenvs Smallstep.
Require Import LTL Op Locations Linear Mach.
Require Import Bounds Conventions Stacklayout Lineartyping.
Require Import Stacking.
+Local Open Scope sep_scope.
+
Definition match_prog (p: Linear.program) (tp: Mach.program) :=
match_program (fun _ f tf => transf_fundef f = OK tf) eq p tp.
@@ -30,7 +32,7 @@ Proof.
intros. eapply match_transform_partial_program; eauto.
Qed.
-(** * Properties of frame offsets *)
+(** * Basic properties of the translation *)
Lemma typesize_typesize:
forall ty, AST.typesize ty = 4 * Locations.typesize ty.
@@ -44,6 +46,30 @@ Proof.
destruct ty; reflexivity.
Qed.
+Remark align_type_chunk:
+ forall ty, align_chunk (chunk_of_type ty) = 4 * Locations.typealign ty.
+Proof.
+ destruct ty; reflexivity.
+Qed.
+
+Lemma slot_outgoing_argument_valid:
+ forall f ofs ty sg,
+ In (S Outgoing ofs ty) (loc_arguments sg) -> slot_valid f Outgoing ofs ty = true.
+Proof.
+ intros. exploit loc_arguments_acceptable; eauto. intros [A B].
+ unfold slot_valid. unfold proj_sumbool.
+ rewrite zle_true by omega.
+ rewrite pred_dec_true by auto.
+ auto.
+Qed.
+
+Lemma load_result_inject:
+ forall j ty v v',
+ Val.inject j v v' -> Val.has_type v ty -> Val.inject j v (Val.load_result (chunk_of_type ty) v').
+Proof.
+ destruct 1; intros; auto; destruct ty; simpl; try contradiction; econstructor; eauto.
+Qed.
+
Section PRESERVATION.
Variable return_address_offset: Mach.function -> Mach.code -> int -> Prop.
@@ -108,486 +134,417 @@ Proof.
unfold b, function_bounds, bound_stack_data. apply Zmax1.
Qed.
-(** A frame index is valid if it lies within the resource bounds
- of the current function. *)
-
-Definition index_valid (idx: frame_index) :=
- match idx with
- | FI_link => True
- | FI_retaddr => True
- | FI_local x ty => ty <> Tlong /\ 0 <= x /\ x + typesize ty <= b.(bound_local)
- | FI_arg x ty => ty <> Tlong /\ 0 <= x /\ x + typesize ty <= b.(bound_outgoing)
- | FI_saved_int x => 0 <= x < b.(bound_int_callee_save)
- | FI_saved_float x => 0 <= x < b.(bound_float_callee_save)
- end.
-
-Definition type_of_index (idx: frame_index) :=
- match idx with
- | FI_link => Tint
- | FI_retaddr => Tint
- | FI_local x ty => ty
- | FI_arg x ty => ty
- | FI_saved_int x => Tany32
- | FI_saved_float x => Tany64
- end.
-
-(** Non-overlap between the memory areas corresponding to two
- frame indices. *)
-
-Definition index_diff (idx1 idx2: frame_index) : Prop :=
- match idx1, idx2 with
- | FI_link, FI_link => False
- | FI_retaddr, FI_retaddr => False
- | FI_local x1 ty1, FI_local x2 ty2 =>
- x1 + typesize ty1 <= x2 \/ x2 + typesize ty2 <= x1
- | FI_arg x1 ty1, FI_arg x2 ty2 =>
- x1 + typesize ty1 <= x2 \/ x2 + typesize ty2 <= x1
- | FI_saved_int x1, FI_saved_int x2 => x1 <> x2
- | FI_saved_float x1, FI_saved_float x2 => x1 <> x2
- | _, _ => True
- end.
-
-Lemma index_diff_sym:
- forall idx1 idx2, index_diff idx1 idx2 -> index_diff idx2 idx1.
-Proof.
- unfold index_diff; intros.
- destruct idx1; destruct idx2; intuition.
-Qed.
-
-Ltac AddPosProps :=
- generalize (bound_local_pos b); intro;
- generalize (bound_int_callee_save_pos b); intro;
- generalize (bound_float_callee_save_pos b); intro;
- generalize (bound_outgoing_pos b); intro;
- generalize (bound_stack_data_pos b); intro.
-
-Lemma size_pos: 0 <= fe.(fe_size).
-Proof.
- generalize (frame_env_separated b). intuition.
- AddPosProps.
- unfold fe. omega.
-Qed.
-
-Opaque function_bounds.
-
-Ltac InvIndexValid :=
- match goal with
- | [ H: ?ty <> Tlong /\ _ |- _ ] =>
- destruct H; generalize (typesize_pos ty) (typesize_typesize ty); intros
- end.
-
-Lemma offset_of_index_disj:
- forall idx1 idx2,
- index_valid idx1 -> index_valid idx2 ->
- index_diff idx1 idx2 ->
- offset_of_index fe idx1 + AST.typesize (type_of_index idx1) <= offset_of_index fe idx2 \/
- offset_of_index fe idx2 + AST.typesize (type_of_index idx2) <= offset_of_index fe idx1.
-Proof.
- intros idx1 idx2 V1 V2 DIFF.
- generalize (frame_env_separated b). intuition. fold fe in H.
- AddPosProps.
- destruct idx1; destruct idx2;
- simpl in V1; simpl in V2; repeat InvIndexValid; simpl in DIFF;
- unfold offset_of_index, type_of_index;
- change (AST.typesize Tany32) with 4; change (AST.typesize Tany64) with 8;
- change (AST.typesize Tint) with 4;
- omega.
-Qed.
-
-Lemma offset_of_index_disj_stack_data_1:
- forall idx,
- index_valid idx ->
- offset_of_index fe idx + AST.typesize (type_of_index idx) <= fe.(fe_stack_data)
- \/ fe.(fe_stack_data) + b.(bound_stack_data) <= offset_of_index fe idx.
-Proof.
- intros idx V.
- generalize (frame_env_separated b). intuition. fold fe in H.
- AddPosProps.
- destruct idx;
- simpl in V; repeat InvIndexValid;
- unfold offset_of_index, type_of_index;
- change (AST.typesize Tany32) with 4; change (AST.typesize Tany64) with 8;
- change (AST.typesize Tint) with 4;
- omega.
-Qed.
-
-Lemma offset_of_index_disj_stack_data_2:
- forall idx,
- index_valid idx ->
- offset_of_index fe idx + AST.typesize (type_of_index idx) <= fe.(fe_stack_data)
- \/ fe.(fe_stack_data) + f.(Linear.fn_stacksize) <= offset_of_index fe idx.
-Proof.
- intros.
- exploit offset_of_index_disj_stack_data_1; eauto.
- generalize bound_stack_data_stacksize.
- omega.
-Qed.
-
-(** Alignment properties *)
-
-Remark aligned_4_4x: forall x, (4 | 4 * x).
-Proof. intro. exists x; ring. Qed.
-
-Remark aligned_4_8x: forall x, (4 | 8 * x).
-Proof. intro. exists (x * 2); ring. Qed.
+(** * Memory assertions used to describe the contents of stack frames *)
-Remark aligned_8_4:
- forall x, (8 | x) -> (4 | x).
-Proof. intros. apply Zdivides_trans with 8; auto. exists 2; auto. Qed.
+Local Opaque Z.add Z.mul Z.divide.
-Hint Resolve Zdivide_0 Zdivide_refl Zdivide_plus_r
- aligned_4_4x aligned_4_8x aligned_8_4: align_4.
-Hint Extern 4 (?X | ?Y) => (exists (Y/X); reflexivity) : align_4.
+(** Accessing the stack frame using [load_stack] and [store_stack]. *)
-Lemma offset_of_index_aligned:
- forall idx, (4 | offset_of_index fe idx).
+Lemma contains_get_stack:
+ forall spec m ty sp ofs,
+ m |= contains (chunk_of_type ty) sp ofs spec ->
+ exists v, load_stack m (Vptr sp Int.zero) ty (Int.repr ofs) = Some v /\ spec v.
Proof.
- intros.
- generalize (frame_env_aligned b). intuition. fold fe in H. intuition.
- destruct idx; try (destruct t);
- unfold offset_of_index, type_of_index, AST.typesize;
- auto with align_4.
+ intros. unfold load_stack.
+ replace (Val.add (Vptr sp Int.zero) (Vint (Int.repr ofs))) with (Vptr sp (Int.repr ofs)).
+ eapply loadv_rule; eauto.
+ simpl. rewrite Int.add_zero_l; auto.
Qed.
-Lemma offset_of_index_aligned_2:
- forall idx, index_valid idx ->
- (align_chunk (chunk_of_type (type_of_index idx)) | offset_of_index fe idx).
+Lemma hasvalue_get_stack:
+ forall ty m sp ofs v,
+ m |= hasvalue (chunk_of_type ty) sp ofs v ->
+ load_stack m (Vptr sp Int.zero) ty (Int.repr ofs) = Some v.
Proof.
- intros. replace (align_chunk (chunk_of_type (type_of_index idx))) with 4.
- apply offset_of_index_aligned.
- assert (type_of_index idx <> Tlong) by
- (destruct idx; simpl; simpl in H; intuition congruence).
- destruct (type_of_index idx); auto; congruence.
+ intros. exploit contains_get_stack; eauto. intros (v' & A & B). congruence.
Qed.
-Lemma fe_stack_data_aligned:
- (8 | fe_stack_data fe).
-Proof.
- intros.
- generalize (frame_env_aligned b). intuition. fold fe in H. intuition.
+Lemma contains_set_stack:
+ forall (spec: val -> Prop) v spec1 m ty sp ofs P,
+ m |= contains (chunk_of_type ty) sp ofs spec1 ** P ->
+ spec (Val.load_result (chunk_of_type ty) v) ->
+ exists m',
+ store_stack m (Vptr sp Int.zero) ty (Int.repr ofs) v = Some m'
+ /\ m' |= contains (chunk_of_type ty) sp ofs spec ** P.
+Proof.
+ intros. unfold store_stack.
+ replace (Val.add (Vptr sp Int.zero) (Vint (Int.repr ofs))) with (Vptr sp (Int.repr ofs)).
+ eapply storev_rule; eauto.
+ simpl. rewrite Int.add_zero_l; auto.
+Qed.
+
+(** [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 <= Int.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.
-(** The following lemmas give sufficient conditions for indices
- of various kinds to be valid. *)
+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.
+Proof.
+ intros; split.
+- red; intros. apply Mem.perm_implies with Freeable; auto with mem.
+ apply H0. rewrite size_type_chunk, typesize_typesize in H4. omega.
+- rewrite align_type_chunk. apply Z.divide_add_r.
+ apply Zdivide_trans with 8; auto.
+ exists (8 / (4 * typealign ty)); destruct ty; reflexivity.
+ apply Z.mul_divide_mono_l. auto.
+Qed.
+
+Lemma get_location:
+ forall m j sp pos bound sl ls ofs ty,
+ m |= contains_locations j sp pos bound sl ls ->
+ 0 <= ofs -> ofs + typesize ty <= bound -> (typealign ty | ofs) ->
+ exists v,
+ load_stack m (Vptr sp Int.zero) ty (Int.repr (pos + 4 * ofs)) = Some v
+ /\ Val.inject j (ls (S sl ofs ty)) v.
+Proof.
+ intros. destruct H as (D & E & F & G & H).
+ exploit H; eauto. intros (v & U & V). exists v; split; auto.
+ unfold load_stack; simpl. rewrite Int.add_zero_l, Int.unsigned_repr; auto.
+ unfold Int.max_unsigned. generalize (typesize_pos ty). omega.
+Qed.
+
+Lemma set_location:
+ forall m j sp pos bound sl ls P ofs ty v v',
+ m |= contains_locations j sp pos bound sl ls ** P ->
+ 0 <= ofs -> ofs + typesize ty <= bound -> (typealign ty | ofs) ->
+ Val.inject j v v' ->
+ exists m',
+ store_stack m (Vptr sp Int.zero) ty (Int.repr (pos + 4 * ofs)) v' = Some m'
+ /\ m' |= contains_locations j sp pos bound sl (Locmap.set (S sl ofs ty) v ls) ** P.
+Proof.
+ intros. destruct H as (A & B & C). destruct A as (D & E & F & G & H).
+ edestruct Mem.valid_access_store as [m' STORE].
+ eapply valid_access_location; eauto.
+ assert (PERM: Mem.range_perm m' sp pos (pos + 4 * bound) Cur Freeable).
+ { red; intros; eauto with mem. }
+ exists m'; split.
+- unfold store_stack; simpl. rewrite Int.add_zero_l, Int.unsigned_repr; eauto.
+ unfold Int.max_unsigned. generalize (typesize_pos ty). omega.
+- simpl. intuition auto.
++ unfold Locmap.set.
+ destruct (Loc.eq (S sl ofs ty) (S sl ofs0 ty0)); [|destruct (Loc.diff_dec (S sl ofs ty) (S sl ofs0 ty0))].
+* (* same location *)
+ inv e. rename ofs0 into ofs. rename ty0 into ty.
+ exists (Val.load_result (chunk_of_type ty) v'); split.
+ eapply Mem.load_store_similar_2; eauto. omega.
+ inv H3; destruct (chunk_of_type ty); simpl; econstructor; eauto.
+* (* different locations *)
+ exploit H; eauto. intros (v0 & X & Y). exists v0; split; auto.
+ rewrite <- X; eapply Mem.load_store_other; eauto.
+ destruct d. congruence. right. rewrite ! size_type_chunk, ! typesize_typesize. omega.
+* (* overlapping locations *)
+ destruct (Mem.valid_access_load m' (chunk_of_type ty0) sp (pos + 4 * ofs0)) as [v'' LOAD].
+ apply Mem.valid_access_implies with Writable; auto with mem.
+ eapply valid_access_location; eauto.
+ exists v''; auto.
++ apply (m_invar P) with m; auto.
+ eapply Mem.store_unchanged_on; eauto.
+ intros i; rewrite size_type_chunk, typesize_typesize. intros; red; intros.
+ eelim C; eauto. simpl. split; auto. omega.
+Qed.
+
+Lemma initial_locations:
+ forall j sp pos bound P sl ls m,
+ m |= range sp pos (pos + 4 * bound) ** P ->
+ (8 | pos) ->
+ (forall ofs ty, ls (S sl ofs ty) = Vundef) ->
+ m |= contains_locations j sp pos bound sl ls ** P.
+Proof.
+ intros. destruct H as (A & B & C). destruct A as (D & E & F). split.
+- simpl; intuition auto. red; intros; eauto with mem.
+ destruct (Mem.valid_access_load m (chunk_of_type ty) sp (pos + 4 * ofs)) as [v LOAD].
+ eapply valid_access_location; eauto.
+ red; intros; eauto with mem.
+ exists v; split; auto. rewrite H1; auto.
+- split; assumption.
+Qed.
+
+Lemma contains_locations_exten:
+ forall ls ls' j sp pos bound sl,
+ (forall ofs ty, ls' (S sl ofs ty) = ls (S sl ofs ty)) ->
+ massert_imp (contains_locations j sp pos bound sl ls)
+ (contains_locations j sp pos bound sl ls').
+Proof.
+ intros; split; simpl; intros; auto.
+ intuition auto. rewrite H. eauto.
+Qed.
+
+Lemma contains_locations_incr:
+ forall j j' sp pos bound sl ls,
+ inject_incr j j' ->
+ massert_imp (contains_locations j sp pos bound sl ls)
+ (contains_locations j' sp pos bound sl ls).
+Proof.
+ intros; split; simpl; intros; auto.
+ intuition auto. exploit H5; eauto. intros (v & A & B). exists v; eauto.
+Qed.
+
+(** [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 index_local_valid:
- forall ofs ty,
+Lemma contains_callee_saves_incr:
+ forall j j' sp ls,
+ inject_incr j j' ->
+ forall rl pos,
+ massert_imp (contains_callee_saves j sp pos rl ls)
+ (contains_callee_saves j' sp pos rl ls).
+Proof.
+ induction rl as [ | r1 rl]; simpl; intros.
+- reflexivity.
+- apply sepconj_morph_1; auto. apply contains_imp. eauto.
+Qed.
+
+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').
+Proof.
+ induction rl as [ | r1 rl]; simpl; intros.
+- reflexivity.
+- apply sepconj_morph_2; auto. rewrite H by auto. reflexivity.
+Qed.
+
+(** 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 Mint32 sp fe.(fe_ofs_link) parent
+ ** hasvalue Mint32 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 ->
- index_valid (FI_local ofs ty).
+ exists v,
+ load_stack m (Vptr sp Int.zero) ty (Int.repr (offset_local fe ofs)) = Some v
+ /\ Val.inject j (ls (S Local ofs ty)) v.
Proof.
- unfold slot_within_bounds, slot_valid, index_valid; intros.
- InvBooleans.
- split. destruct ty; auto || discriminate. auto.
+ unfold frame_contents, frame_contents_1; intros. unfold slot_valid in H1; InvBooleans.
+ apply mconj_proj1 in H. apply sep_proj1 in H. apply sep_proj1 in H.
+ eapply get_location; eauto.
Qed.
-Lemma index_arg_valid:
- forall ofs ty,
+Lemma frame_get_outgoing:
+ 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 Outgoing ofs ty -> slot_valid f Outgoing ofs ty = true ->
- index_valid (FI_arg ofs ty).
+ exists v,
+ load_stack m (Vptr sp Int.zero) ty (Int.repr (offset_arg ofs)) = Some v
+ /\ Val.inject j (ls (S Outgoing ofs ty)) v.
Proof.
- unfold slot_within_bounds, slot_valid, index_valid; intros.
- InvBooleans.
- split. destruct ty; auto || discriminate. auto.
+ unfold frame_contents, frame_contents_1; intros. unfold slot_valid in H1; InvBooleans.
+ apply mconj_proj1 in H. apply sep_proj1 in H. apply sep_pick2 in H.
+ eapply get_location; eauto.
Qed.
-Lemma index_saved_int_valid:
- forall r,
- In r int_callee_save_regs ->
- index_int_callee_save r < b.(bound_int_callee_save) ->
- index_valid (FI_saved_int (index_int_callee_save r)).
+Lemma frame_get_parent:
+ forall j sp ls ls0 parent retaddr m P,
+ m |= frame_contents j sp ls ls0 parent retaddr ** P ->
+ load_stack m (Vptr sp Int.zero) Tint (Int.repr fe.(fe_ofs_link)) = Some parent.
Proof.
- intros. red. split.
- apply Zge_le. apply index_int_callee_save_pos; auto.
- auto.
+ unfold frame_contents, frame_contents_1; intros.
+ apply mconj_proj1 in H. apply sep_proj1 in H. apply sep_pick3 in H.
+ eapply hasvalue_get_stack; eauto.
Qed.
-Lemma index_saved_float_valid:
- forall r,
- In r float_callee_save_regs ->
- index_float_callee_save r < b.(bound_float_callee_save) ->
- index_valid (FI_saved_float (index_float_callee_save r)).
+Lemma frame_get_retaddr:
+ forall j sp ls ls0 parent retaddr m P,
+ m |= frame_contents j sp ls ls0 parent retaddr ** P ->
+ load_stack m (Vptr sp Int.zero) Tint (Int.repr fe.(fe_ofs_retaddr)) = Some retaddr.
Proof.
- intros. red. split.
- apply Zge_le. apply index_float_callee_save_pos; auto.
- auto.
+ unfold frame_contents, frame_contents_1; intros.
+ apply mconj_proj1 in H. apply sep_proj1 in H. apply sep_pick4 in H.
+ eapply hasvalue_get_stack; eauto.
Qed.
-Hint Resolve index_local_valid index_arg_valid
- index_saved_int_valid index_saved_float_valid: stacking.
-
-(** The offset of a valid index lies within the bounds of the frame. *)
-
-Lemma offset_of_index_valid:
- forall idx,
- index_valid idx ->
- 0 <= offset_of_index fe idx /\
- offset_of_index fe idx + AST.typesize (type_of_index idx) <= fe.(fe_size).
-Proof.
- intros idx V.
- generalize (frame_env_separated b). intros [A B]. fold fe in A. fold fe in B.
- AddPosProps.
- destruct idx; simpl in V; repeat InvIndexValid;
- unfold offset_of_index, type_of_index;
- change (AST.typesize Tany32) with 4; change (AST.typesize Tany64) with 8;
- change (AST.typesize Tint) with 4;
- omega.
-Qed.
+(** Assigning a [Local] or [Outgoing] stack slot. *)
-(** The image of the Linear stack data block lies within the bounds of the frame. *)
-
-Lemma stack_data_offset_valid:
- 0 <= fe.(fe_stack_data) /\ fe.(fe_stack_data) + b.(bound_stack_data) <= fe.(fe_size).
-Proof.
- generalize (frame_env_separated b). intros [A B]. fold fe in A. fold fe in B.
- AddPosProps.
- omega.
-Qed.
-
-(** Offsets for valid index are representable as signed machine integers
- without loss of precision. *)
-
-Lemma offset_of_index_no_overflow:
- forall idx,
- index_valid idx ->
- Int.unsigned (Int.repr (offset_of_index fe idx)) = offset_of_index fe idx.
-Proof.
- intros.
- generalize (offset_of_index_valid idx H). intros [A B].
- apply Int.unsigned_repr.
- generalize (AST.typesize_pos (type_of_index idx)).
- generalize size_no_overflow.
- omega.
-Qed.
-
-(** Likewise, for offsets within the Linear stack slot, after shifting. *)
-
-Lemma shifted_stack_offset_no_overflow:
- forall ofs,
- 0 <= Int.unsigned ofs < Linear.fn_stacksize f ->
- Int.unsigned (Int.add ofs (Int.repr fe.(fe_stack_data)))
- = Int.unsigned ofs + fe.(fe_stack_data).
-Proof.
- intros. unfold Int.add.
- generalize size_no_overflow stack_data_offset_valid bound_stack_data_stacksize; intros.
- AddPosProps.
- replace (Int.unsigned (Int.repr (fe_stack_data fe))) with (fe_stack_data fe).
- apply Int.unsigned_repr. omega.
- symmetry. apply Int.unsigned_repr. omega.
-Qed.
-
-(** * Contents of frame slots *)
-
-Inductive index_contains (m: mem) (sp: block) (idx: frame_index) (v: val) : Prop :=
- | index_contains_intro:
- index_valid idx ->
- Mem.load (chunk_of_type (type_of_index idx)) m sp (offset_of_index fe idx) = Some v ->
- index_contains m sp idx v.
-
-Lemma index_contains_load_stack:
- forall m sp idx v,
- index_contains m sp idx v ->
- load_stack m (Vptr sp Int.zero) (type_of_index idx)
- (Int.repr (offset_of_index fe idx)) = Some v.
+Lemma frame_set_local:
+ forall ofs ty v v' 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 ->
+ Val.inject j v v' ->
+ exists m',
+ store_stack m (Vptr sp Int.zero) ty (Int.repr (offset_local fe ofs)) v' = Some m'
+ /\ m' |= frame_contents j sp (Locmap.set (S Local ofs ty) v ls) ls0 parent retaddr ** P.
+Proof.
+ intros. unfold frame_contents in H.
+ exploit mconj_proj1; eauto. unfold frame_contents_1.
+ rewrite ! sep_assoc; intros SEP.
+ unfold slot_valid in H1; InvBooleans. simpl in H0.
+ exploit set_location; eauto. intros (m' & A & B).
+ exists m'; split; auto.
+ assert (forall i k p, Mem.perm m sp i k p -> Mem.perm m' sp i k p).
+ { intros. unfold store_stack in A; simpl in A. eapply Mem.perm_store_1; eauto. }
+ eapply frame_mconj. eauto.
+ unfold frame_contents_1; rewrite ! sep_assoc; exact B.
+ eapply sep_preserved.
+ eapply sep_proj1. eapply mconj_proj2. eassumption.
+ intros; eapply range_preserved; eauto.
+ intros; eapply range_preserved; eauto.
+Qed.
+
+Lemma frame_set_outgoing:
+ forall ofs ty v v' j sp ls ls0 parent retaddr m P,
+ m |= frame_contents j sp ls ls0 parent retaddr ** P ->
+ slot_within_bounds b Outgoing ofs ty -> slot_valid f Outgoing ofs ty = true ->
+ Val.inject j v v' ->
+ exists m',
+ store_stack m (Vptr sp Int.zero) ty (Int.repr (offset_arg ofs)) v' = Some m'
+ /\ m' |= frame_contents j sp (Locmap.set (S Outgoing ofs ty) v ls) ls0 parent retaddr ** P.
Proof.
- intros. inv H.
- unfold load_stack, Mem.loadv, Val.add. rewrite Int.add_commut. rewrite Int.add_zero.
- rewrite offset_of_index_no_overflow; auto.
+ intros. unfold frame_contents in H.
+ exploit mconj_proj1; eauto. unfold frame_contents_1.
+ rewrite ! sep_assoc, sep_swap. intros SEP.
+ unfold slot_valid in H1; InvBooleans. simpl in H0.
+ exploit set_location; eauto. intros (m' & A & B).
+ exists m'; split; auto.
+ assert (forall i k p, Mem.perm m sp i k p -> Mem.perm m' sp i k p).
+ { intros. unfold store_stack in A; simpl in A. eapply Mem.perm_store_1; eauto. }
+ eapply frame_mconj. eauto.
+ unfold frame_contents_1; rewrite ! sep_assoc, sep_swap; eauto.
+ eapply sep_preserved.
+ eapply sep_proj1. eapply mconj_proj2. eassumption.
+ intros; eapply range_preserved; eauto.
+ intros; eapply range_preserved; eauto.
Qed.
-(** Good variable properties for [index_contains] *)
+(** Invariance by change of location maps. *)
-Lemma gss_index_contains_base:
- forall idx m m' sp v,
- Mem.store (chunk_of_type (type_of_index idx)) m sp (offset_of_index fe idx) v = Some m' ->
- index_valid idx ->
- exists v',
- index_contains m' sp idx v'
- /\ decode_encode_val v (chunk_of_type (type_of_index idx)) (chunk_of_type (type_of_index idx)) v'.
-Proof.
- intros.
- exploit Mem.load_store_similar. eauto. reflexivity. omega.
- intros [v' [A B]].
- exists v'; split; auto. constructor; auto.
-Qed.
-
-Lemma gss_index_contains:
- forall idx m m' sp v,
- Mem.store (chunk_of_type (type_of_index idx)) m sp (offset_of_index fe idx) v = Some m' ->
- index_valid idx ->
- Val.has_type v (type_of_index idx) ->
- index_contains m' sp idx v.
-Proof.
- intros. exploit gss_index_contains_base; eauto. intros [v' [A B]].
- assert (v' = v).
- destruct v; destruct (type_of_index idx); simpl in *;
- try contradiction; auto.
- subst v'. auto.
-Qed.
-
-Lemma gso_index_contains:
- forall idx m m' sp v idx' v',
- Mem.store (chunk_of_type (type_of_index idx)) m sp (offset_of_index fe idx) v = Some m' ->
- index_valid idx ->
- index_contains m sp idx' v' ->
- index_diff idx idx' ->
- index_contains m' sp idx' v'.
-Proof.
- intros. inv H1. constructor; auto.
- rewrite <- H4. eapply Mem.load_store_other; eauto.
- right. repeat rewrite size_type_chunk.
- apply offset_of_index_disj; auto. apply index_diff_sym; auto.
-Qed.
-
-Lemma store_other_index_contains:
- forall chunk m blk ofs v' m' sp idx v,
- Mem.store chunk m blk ofs v' = Some m' ->
- blk <> sp \/
- (fe.(fe_stack_data) <= ofs /\ ofs + size_chunk chunk <= fe.(fe_stack_data) + f.(Linear.fn_stacksize)) ->
- index_contains m sp idx v ->
- index_contains m' sp idx v.
-Proof.
- intros. inv H1. constructor; auto. rewrite <- H3.
- eapply Mem.load_store_other; eauto.
- destruct H0. auto. right.
- exploit offset_of_index_disj_stack_data_2; eauto. intros.
- rewrite size_type_chunk.
- omega.
-Qed.
-
-Definition frame_perm_freeable (m: mem) (sp: block): Prop :=
- forall ofs,
- 0 <= ofs < fe.(fe_size) ->
- ofs < fe.(fe_stack_data) \/ fe.(fe_stack_data) + f.(Linear.fn_stacksize) <= ofs ->
- Mem.perm m sp ofs Cur Freeable.
-
-Lemma offset_of_index_perm:
- forall m sp idx,
- index_valid idx ->
- frame_perm_freeable m sp ->
- Mem.range_perm m sp (offset_of_index fe idx) (offset_of_index fe idx + AST.typesize (type_of_index idx)) Cur Freeable.
+Lemma frame_contents_exten:
+ forall ls ls0 ls' ls0' j sp parent retaddr P m,
+ (forall sl ofs ty, ls' (S sl ofs ty) = ls (S sl ofs ty)) ->
+ (forall r, In r b.(used_callee_save) -> ls0' (R r) = ls0 (R r)) ->
+ m |= frame_contents j sp ls ls0 parent retaddr ** P ->
+ m |= frame_contents j sp ls' ls0' parent retaddr ** P.
Proof.
- intros.
- exploit offset_of_index_valid; eauto. intros [A B].
- exploit offset_of_index_disj_stack_data_2; eauto. intros.
- red; intros. apply H0. omega. omega.
+ unfold frame_contents, frame_contents_1; intros.
+ rewrite <- ! (contains_locations_exten ls ls') by auto.
+ erewrite <- contains_callee_saves_exten by eauto.
+ assumption.
Qed.
-Lemma store_index_succeeds:
- forall m sp idx v,
- index_valid idx ->
- frame_perm_freeable m sp ->
- exists m',
- Mem.store (chunk_of_type (type_of_index idx)) m sp (offset_of_index fe idx) v = Some m'.
-Proof.
- intros.
- destruct (Mem.valid_access_store m (chunk_of_type (type_of_index idx)) sp (offset_of_index fe idx) v) as [m' ST].
- constructor.
- rewrite size_type_chunk.
- apply Mem.range_perm_implies with Freeable; auto with mem.
- apply offset_of_index_perm; auto.
- apply offset_of_index_aligned_2; auto.
- exists m'; auto.
-Qed.
+(** Invariance by assignment to registers. *)
-Lemma store_stack_succeeds:
- forall m sp idx v m',
- index_valid idx ->
- Mem.store (chunk_of_type (type_of_index idx)) m sp (offset_of_index fe idx) v = Some m' ->
- store_stack m (Vptr sp Int.zero) (type_of_index idx) (Int.repr (offset_of_index fe idx)) v = Some m'.
+Corollary frame_set_reg:
+ forall r v j sp ls ls0 parent retaddr m P,
+ m |= frame_contents j sp ls ls0 parent retaddr ** P ->
+ m |= frame_contents j sp (Locmap.set (R r) v ls) ls0 parent retaddr ** P.
Proof.
- intros. unfold store_stack, Mem.storev, Val.add.
- rewrite Int.add_commut. rewrite Int.add_zero.
- rewrite offset_of_index_no_overflow; auto.
+ intros. apply frame_contents_exten with ls ls0; auto.
Qed.
-(** A variant of [index_contains], up to a memory injection. *)
-
-Definition index_contains_inj (j: meminj) (m: mem) (sp: block) (idx: frame_index) (v: val) : Prop :=
- exists v', index_contains m sp idx v' /\ Val.inject j v v'.
-
-Lemma gss_index_contains_inj:
- forall j idx m m' sp v v',
- Mem.store (chunk_of_type (type_of_index idx)) m sp (offset_of_index fe idx) v' = Some m' ->
- index_valid idx ->
- Val.has_type v (type_of_index idx) ->
- Val.inject j v v' ->
- index_contains_inj j m' sp idx v.
+Corollary frame_undef_regs:
+ forall j sp ls ls0 parent retaddr m P rl,
+ m |= frame_contents j sp ls ls0 parent retaddr ** P ->
+ m |= frame_contents j sp (LTL.undef_regs rl ls) ls0 parent retaddr ** P.
Proof.
- intros. exploit gss_index_contains_base; eauto. intros [v'' [A B]].
- exists v''; split; auto.
- inv H2; destruct (type_of_index idx); simpl in *; try contradiction; subst; auto.
- econstructor; eauto.
- econstructor; eauto.
- econstructor; eauto.
+Local Opaque sepconj.
+ induction rl; simpl; intros.
+- auto.
+- apply frame_set_reg; auto.
Qed.
-Lemma gss_index_contains_inj':
- forall j idx m m' sp v v',
- Mem.store (chunk_of_type (type_of_index idx)) m sp (offset_of_index fe idx) v' = Some m' ->
- index_valid idx ->
- Val.inject j v v' ->
- index_contains_inj j m' sp idx (Val.load_result (chunk_of_type (type_of_index idx)) v).
+Corollary frame_set_regs:
+ forall j sp ls0 parent retaddr m P rl vl ls,
+ m |= frame_contents j sp ls ls0 parent retaddr ** P ->
+ m |= frame_contents j sp (Locmap.setlist (map R rl) vl ls) ls0 parent retaddr ** P.
Proof.
- intros. exploit gss_index_contains_base; eauto. intros [v'' [A B]].
- exists v''; split; auto.
- inv H1; destruct (type_of_index idx); simpl in *; try contradiction; subst; auto.
- econstructor; eauto.
- econstructor; eauto.
- econstructor; eauto.
+ induction rl; destruct vl; simpl; intros; trivial. apply IHrl. apply frame_set_reg; auto.
Qed.
-Lemma gso_index_contains_inj:
- forall j idx m m' sp v idx' v',
- Mem.store (chunk_of_type (type_of_index idx)) m sp (offset_of_index fe idx) v = Some m' ->
- index_valid idx ->
- index_contains_inj j m sp idx' v' ->
- index_diff idx idx' ->
- index_contains_inj j m' sp idx' v'.
+Corollary frame_set_res:
+ forall j sp ls0 parent retaddr m P res v ls,
+ m |= frame_contents j sp ls ls0 parent retaddr ** P ->
+ m |= frame_contents j sp (Locmap.setres res v ls) ls0 parent retaddr ** P.
Proof.
- intros. destruct H1 as [v'' [A B]]. exists v''; split; auto.
- eapply gso_index_contains; eauto.
+ induction res; simpl; intros.
+- apply frame_set_reg; auto.
+- auto.
+- eauto.
Qed.
-Lemma store_other_index_contains_inj:
- forall j chunk m b ofs v' m' sp idx v,
- Mem.store chunk m b ofs v' = Some m' ->
- b <> sp \/
- (fe.(fe_stack_data) <= ofs /\ ofs + size_chunk chunk <= fe.(fe_stack_data) + f.(Linear.fn_stacksize)) ->
- index_contains_inj j m sp idx v ->
- index_contains_inj j m' sp idx v.
-Proof.
- intros. destruct H1 as [v'' [A B]]. exists v''; split; auto.
- eapply store_other_index_contains; eauto.
-Qed.
+(** Invariance by change of memory injection. *)
-Lemma index_contains_inj_incr:
- forall j m sp idx v j',
- index_contains_inj j m sp idx v ->
+Lemma frame_contents_incr:
+ forall j sp ls ls0 parent retaddr m P j',
+ m |= frame_contents j sp ls ls0 parent retaddr ** P ->
inject_incr j j' ->
- index_contains_inj j' m sp idx v.
-Proof.
- intros. destruct H as [v'' [A B]]. exists v''; split; auto. eauto.
-Qed.
-
-Lemma index_contains_inj_undef:
- forall j m sp idx,
- index_valid idx ->
- frame_perm_freeable m sp ->
- index_contains_inj j m sp idx Vundef.
+ m |= frame_contents j' sp ls ls0 parent retaddr ** P.
Proof.
- intros.
- exploit (Mem.valid_access_load m (chunk_of_type (type_of_index idx)) sp (offset_of_index fe idx)).
- constructor.
- rewrite size_type_chunk.
- apply Mem.range_perm_implies with Freeable; auto with mem.
- apply offset_of_index_perm; auto.
- apply offset_of_index_aligned_2; auto.
- intros [v C].
- exists v; split; auto. constructor; auto.
+ unfold frame_contents, frame_contents_1; intros.
+ rewrite <- (contains_locations_incr j j') by auto.
+ rewrite <- (contains_locations_incr j j') by auto.
+ erewrite <- contains_callee_saves_incr by eauto.
+ assumption.
Qed.
-Hint Resolve store_other_index_contains_inj index_contains_inj_incr: stacking.
-
(** * Agreement between location sets and Mach states *)
(** Agreement with Mach register states *)
@@ -595,89 +552,29 @@ Hint Resolve store_other_index_contains_inj index_contains_inj_incr: stacking.
Definition agree_regs (j: meminj) (ls: locset) (rs: regset) : Prop :=
forall r, Val.inject j (ls (R r)) (rs r).
-(** Agreement over data stored in memory *)
+(** Agreement over locations *)
-Record agree_frame (j: meminj) (ls ls0: locset)
- (m: mem) (sp: block)
- (m': mem) (sp': block)
- (parent retaddr: val) : Prop :=
- mk_agree_frame {
+Record agree_locs (ls ls0: locset) : Prop :=
+ mk_agree_locs {
(** Unused registers have the same value as in the caller *)
agree_unused_reg:
forall r, ~(mreg_within_bounds b r) -> ls (R r) = ls0 (R r);
- (** Local and outgoing stack slots (on the Linear side) have
- the same values as the one loaded from the current Mach frame
- at the corresponding offsets. *)
- agree_locals:
- forall ofs ty,
- slot_within_bounds b Local ofs ty -> slot_valid f Local ofs ty = true ->
- index_contains_inj j m' sp' (FI_local ofs ty) (ls (S Local ofs ty));
- agree_outgoing:
- forall ofs ty,
- slot_within_bounds b Outgoing ofs ty -> slot_valid f Outgoing ofs ty = true ->
- index_contains_inj j m' sp' (FI_arg ofs ty) (ls (S Outgoing ofs ty));
-
(** Incoming stack slots have the same value as the
corresponding Outgoing stack slots in the caller *)
agree_incoming:
forall ofs ty,
In (S Incoming ofs ty) (loc_parameters f.(Linear.fn_sig)) ->
- ls (S Incoming ofs ty) = ls0 (S Outgoing ofs ty);
-
- (** The back link and return address slots of the Mach frame contain
- the [parent] and [retaddr] values, respectively. *)
- agree_link:
- index_contains m' sp' FI_link parent;
- agree_retaddr:
- index_contains m' sp' FI_retaddr retaddr;
-
- (** The areas of the frame reserved for saving used callee-save
- registers always contain the values that those registers had
- in the caller. *)
- agree_saved_int:
- forall r,
- In r int_callee_save_regs ->
- index_int_callee_save r < b.(bound_int_callee_save) ->
- index_contains_inj j m' sp' (FI_saved_int (index_int_callee_save r)) (ls0 (R r));
- agree_saved_float:
- forall r,
- In r float_callee_save_regs ->
- index_float_callee_save r < b.(bound_float_callee_save) ->
- index_contains_inj j m' sp' (FI_saved_float (index_float_callee_save r)) (ls0 (R r));
-
- (** Mapping between the Linear stack pointer and the Mach stack pointer *)
- agree_inj:
- j sp = Some(sp', fe.(fe_stack_data));
- agree_inj_unique:
- forall b delta, j b = Some(sp', delta) -> b = sp /\ delta = fe.(fe_stack_data);
-
- (** The Linear and Mach stack pointers are valid *)
- agree_valid_linear:
- Mem.valid_block m sp;
- agree_valid_mach:
- Mem.valid_block m' sp';
-
- (** Bounds of the Linear stack data block *)
- agree_bounds:
- forall ofs p, Mem.perm m sp ofs Max p -> 0 <= ofs < f.(Linear.fn_stacksize);
-
- (** Permissions on the frame part of the Mach stack block *)
- agree_perm:
- frame_perm_freeable m' sp'
- }.
-
-Hint Resolve agree_unused_reg agree_locals agree_outgoing agree_incoming
- agree_link agree_retaddr agree_saved_int agree_saved_float
- agree_valid_linear agree_valid_mach agree_perm: stacking.
+ ls (S Incoming ofs ty) = ls0 (S Outgoing ofs ty)
+}.
(** Auxiliary predicate used at call points *)
Definition agree_callee_save (ls ls0: locset) : Prop :=
forall l,
match l with
- | R r => ~In r destroyed_at_call
+ | R r => is_callee_save r = true
| S _ _ _ => True
end ->
ls l = ls0 l.
@@ -698,7 +595,7 @@ Lemma agree_reglist:
agree_regs j ls rs -> Val.inject_list j (reglist ls rl) (rs##rl).
Proof.
induction rl; simpl; intros.
- auto. constructor. eauto with stacking. auto.
+ auto. constructor; auto using agree_reg.
Qed.
Hint Resolve agree_reg agree_reglist: stacking.
@@ -795,310 +692,130 @@ Proof.
unfold call_regs; intros; red; intros; auto.
Qed.
-(** ** Properties of [agree_frame] *)
+(** ** Properties of [agree_locs] *)
(** Preservation under assignment of machine register. *)
-Lemma agree_frame_set_reg:
- forall j ls ls0 m sp m' sp' parent ra r v,
- agree_frame j ls ls0 m sp m' sp' parent ra ->
+Lemma agree_locs_set_reg:
+ forall ls ls0 r v,
+ agree_locs ls ls0 ->
mreg_within_bounds b r ->
- agree_frame j (Locmap.set (R r) v ls) ls0 m sp m' sp' parent ra.
+ agree_locs (Locmap.set (R r) v ls) ls0.
Proof.
intros. inv H; constructor; auto; intros.
rewrite Locmap.gso. auto. red. intuition congruence.
Qed.
-Lemma agree_frame_set_regs:
- forall j ls0 m sp m' sp' parent ra rl vl ls,
- agree_frame j ls ls0 m sp m' sp' parent ra ->
+Lemma agree_locs_set_regs:
+ forall ls0 rl vl ls,
+ agree_locs ls ls0 ->
(forall r, In r rl -> mreg_within_bounds b r) ->
- agree_frame j (Locmap.setlist (map R rl) vl ls) ls0 m sp m' sp' parent ra.
+ agree_locs (Locmap.setlist (map R rl) vl ls) ls0.
Proof.
- induction rl; destruct vl; simpl; intros; intuition.
- apply IHrl; auto.
- eapply agree_frame_set_reg; eauto.
+ induction rl; destruct vl; simpl; intros; auto.
+ apply IHrl; auto. apply agree_locs_set_reg; auto.
Qed.
-Lemma agree_frame_set_res:
- forall j ls0 m sp m' sp' parent ra res v ls,
- agree_frame j ls ls0 m sp m' sp' parent ra ->
+Lemma agree_locs_set_res:
+ forall ls0 res v ls,
+ agree_locs ls ls0 ->
(forall r, In r (params_of_builtin_res res) -> mreg_within_bounds b r) ->
- agree_frame j (Locmap.setres res v ls) ls0 m sp m' sp' parent ra.
+ agree_locs (Locmap.setres res v ls) ls0.
Proof.
induction res; simpl; intros.
-- eapply agree_frame_set_reg; eauto.
+- eapply agree_locs_set_reg; eauto.
- auto.
- apply IHres2; auto using in_or_app.
Qed.
-Lemma agree_frame_undef_regs:
- forall j ls0 m sp m' sp' parent ra regs ls,
- agree_frame j ls ls0 m sp m' sp' parent ra ->
+Lemma agree_locs_undef_regs:
+ forall ls0 regs ls,
+ agree_locs ls ls0 ->
(forall r, In r regs -> mreg_within_bounds b r) ->
- agree_frame j (LTL.undef_regs regs ls) ls0 m sp m' sp' parent ra.
+ agree_locs (LTL.undef_regs regs ls) ls0.
Proof.
induction regs; simpl; intros.
auto.
- apply agree_frame_set_reg; auto.
+ apply agree_locs_set_reg; auto.
Qed.
Lemma caller_save_reg_within_bounds:
forall r,
- In r destroyed_at_call -> mreg_within_bounds b r.
+ is_callee_save r = false -> mreg_within_bounds b r.
Proof.
- intros. red.
- destruct (zlt (index_int_callee_save r) 0).
- destruct (zlt (index_float_callee_save r) 0).
- generalize (bound_int_callee_save_pos b) (bound_float_callee_save_pos b); omega.
- exfalso. eapply float_callee_save_not_destroyed; eauto. eapply index_float_callee_save_pos2; eauto.
- exfalso. eapply int_callee_save_not_destroyed; eauto. eapply index_int_callee_save_pos2; eauto.
+ intros; red; intros. congruence.
Qed.
-Lemma agree_frame_undef_locs:
- forall j ls0 m sp m' sp' parent ra regs ls,
- agree_frame j ls ls0 m sp m' sp' parent ra ->
- incl regs destroyed_at_call ->
- agree_frame j (LTL.undef_regs regs ls) ls0 m sp m' sp' parent ra.
+Lemma agree_locs_undef_locs_1:
+ forall ls0 regs ls,
+ agree_locs ls ls0 ->
+ (forall r, In r regs -> is_callee_save r = false) ->
+ agree_locs (LTL.undef_regs regs ls) ls0.
Proof.
- intros. eapply agree_frame_undef_regs; eauto.
+ intros. eapply agree_locs_undef_regs; eauto.
intros. apply caller_save_reg_within_bounds. auto.
Qed.
-(** Preservation by assignment to local slot *)
-
-Lemma agree_frame_set_local:
- forall j ls ls0 m sp m' sp' parent retaddr ofs ty v v' m'',
- agree_frame j ls ls0 m sp m' sp' parent retaddr ->
- slot_within_bounds b Local ofs ty -> slot_valid f Local ofs ty = true ->
- Val.inject j v v' ->
- Mem.store (chunk_of_type ty) m' sp' (offset_of_index fe (FI_local ofs ty)) v' = Some m'' ->
- agree_frame j (Locmap.set (S Local ofs ty) v ls) ls0 m sp m'' sp' parent retaddr.
+Lemma agree_locs_undef_locs:
+ forall ls0 regs ls,
+ agree_locs ls ls0 ->
+ existsb is_callee_save regs = false ->
+ agree_locs (LTL.undef_regs regs ls) ls0.
Proof.
- intros. inv H.
- change (chunk_of_type ty) with (chunk_of_type (type_of_index (FI_local ofs ty))) in H3.
- constructor; auto; intros.
-(* local *)
- unfold Locmap.set.
- destruct (Loc.eq (S Local ofs ty) (S Local ofs0 ty0)).
- inv e. eapply gss_index_contains_inj'; eauto with stacking.
- destruct (Loc.diff_dec (S Local ofs ty) (S Local ofs0 ty0)).
- eapply gso_index_contains_inj. eauto. eauto with stacking. eauto.
- simpl. simpl in d. intuition.
- apply index_contains_inj_undef. auto with stacking.
- red; intros. eapply Mem.perm_store_1; eauto.
-(* outgoing *)
- rewrite Locmap.gso. eapply gso_index_contains_inj; eauto with stacking.
- red; auto. red; left; congruence.
-(* parent *)
- eapply gso_index_contains; eauto with stacking. red; auto.
-(* retaddr *)
- eapply gso_index_contains; eauto with stacking. red; auto.
-(* int callee save *)
- eapply gso_index_contains_inj; eauto with stacking. simpl; auto.
-(* float callee save *)
- eapply gso_index_contains_inj; eauto with stacking. simpl; auto.
-(* valid *)
- eauto with mem.
-(* perm *)
- red; intros. eapply Mem.perm_store_1; eauto.
+ intros. eapply agree_locs_undef_locs_1; eauto.
+ intros. destruct (is_callee_save r) eqn:CS; auto.
+ assert (existsb is_callee_save regs = true).
+ { apply existsb_exists. exists r; auto. }
+ congruence.
Qed.
-(** Preservation by assignment to outgoing slot *)
+(** Preservation by assignment to local slot *)
-Lemma agree_frame_set_outgoing:
- forall j ls ls0 m sp m' sp' parent retaddr ofs ty v v' m'',
- agree_frame j ls ls0 m sp m' sp' parent retaddr ->
- slot_within_bounds b Outgoing ofs ty -> slot_valid f Outgoing ofs ty = true ->
- Val.inject j v v' ->
- Mem.store (chunk_of_type ty) m' sp' (offset_of_index fe (FI_arg ofs ty)) v' = Some m'' ->
- agree_frame j (Locmap.set (S Outgoing ofs ty) v ls) ls0 m sp m'' sp' parent retaddr.
+Lemma agree_locs_set_slot:
+ forall ls ls0 sl ofs ty v,
+ agree_locs ls ls0 ->
+ slot_writable sl = true ->
+ agree_locs (Locmap.set (S sl ofs ty) v ls) ls0.
Proof.
- intros. inv H.
- change (chunk_of_type ty) with (chunk_of_type (type_of_index (FI_arg ofs ty))) in H3.
- constructor; auto; intros.
-(* local *)
- rewrite Locmap.gso. eapply gso_index_contains_inj; eauto with stacking. red; auto.
- red; left; congruence.
-(* outgoing *)
- unfold Locmap.set. destruct (Loc.eq (S Outgoing ofs ty) (S Outgoing ofs0 ty0)).
- inv e. eapply gss_index_contains_inj'; eauto with stacking.
- destruct (Loc.diff_dec (S Outgoing ofs ty) (S Outgoing ofs0 ty0)).
- eapply gso_index_contains_inj; eauto with stacking.
- red. red in d. intuition.
- apply index_contains_inj_undef. auto with stacking.
- red; intros. eapply Mem.perm_store_1; eauto.
-(* parent *)
- eapply gso_index_contains; eauto with stacking. red; auto.
-(* retaddr *)
- eapply gso_index_contains; eauto with stacking. red; auto.
-(* int callee save *)
- eapply gso_index_contains_inj; eauto with stacking. simpl; auto.
-(* float callee save *)
- eapply gso_index_contains_inj; eauto with stacking. simpl; auto.
-(* valid *)
- eauto with mem stacking.
-(* perm *)
- red; intros. eapply Mem.perm_store_1; eauto.
-Qed.
-
-(** General invariance property with respect to memory changes. *)
-
-Lemma agree_frame_invariant:
- forall j ls ls0 m sp m' sp' parent retaddr m1 m1',
- agree_frame j ls ls0 m sp m' sp' parent retaddr ->
- (Mem.valid_block m sp -> Mem.valid_block m1 sp) ->
- (forall ofs p, Mem.perm m1 sp ofs Max p -> Mem.perm m sp ofs Max p) ->
- (Mem.valid_block m' sp' -> Mem.valid_block m1' sp') ->
- (forall chunk ofs v,
- ofs + size_chunk chunk <= fe.(fe_stack_data) \/
- fe.(fe_stack_data) + f.(Linear.fn_stacksize) <= ofs ->
- Mem.load chunk m' sp' ofs = Some v ->
- Mem.load chunk m1' sp' ofs = Some v) ->
- (forall ofs k p,
- ofs < fe.(fe_stack_data) \/ fe.(fe_stack_data) + f.(Linear.fn_stacksize) <= ofs ->
- Mem.perm m' sp' ofs k p -> Mem.perm m1' sp' ofs k p) ->
- agree_frame j ls ls0 m1 sp m1' sp' parent retaddr.
-Proof.
- intros.
- assert (IC: forall idx v,
- index_contains m' sp' idx v -> index_contains m1' sp' idx v).
- intros. inv H5.
- exploit offset_of_index_disj_stack_data_2; eauto. intros.
- constructor; eauto. apply H3; auto. rewrite size_type_chunk; auto.
- assert (ICI: forall idx v,
- index_contains_inj j m' sp' idx v -> index_contains_inj j m1' sp' idx v).
- intros. destruct H5 as [v' [A B]]. exists v'; split; auto.
- inv H; constructor; auto; intros.
- eauto.
- red; intros. apply H4; auto.
-Qed.
-
-(** A variant of the latter, for use with external calls *)
-
-Lemma agree_frame_extcall_invariant:
- forall j ls ls0 m sp m' sp' parent retaddr m1 m1',
- agree_frame j ls ls0 m sp m' sp' parent retaddr ->
- (Mem.valid_block m sp -> Mem.valid_block m1 sp) ->
- (forall ofs p, Mem.perm m1 sp ofs Max p -> Mem.perm m sp ofs Max p) ->
- (Mem.valid_block m' sp' -> Mem.valid_block m1' sp') ->
- Mem.unchanged_on (loc_out_of_reach j m) m' m1' ->
- agree_frame j ls ls0 m1 sp m1' sp' parent retaddr.
-Proof.
- intros.
- assert (REACH: forall ofs,
- ofs < fe.(fe_stack_data) \/ fe.(fe_stack_data) + f.(Linear.fn_stacksize) <= ofs ->
- loc_out_of_reach j m sp' ofs).
- intros; red; intros. exploit agree_inj_unique; eauto. intros [EQ1 EQ2]; subst.
- red; intros. exploit agree_bounds; eauto. omega.
- eapply agree_frame_invariant; eauto.
- intros. eapply Mem.load_unchanged_on; eauto. intros. apply REACH. omega. auto.
- intros. eapply Mem.perm_unchanged_on; eauto with mem. auto.
-Qed.
-
-(** Preservation by parallel stores in the Linear and Mach codes *)
-
-Lemma agree_frame_parallel_stores:
- forall j ls ls0 m sp m' sp' parent retaddr chunk addr addr' v v' m1 m1',
- agree_frame j ls ls0 m sp m' sp' parent retaddr ->
- Mem.inject j m m' ->
- Val.inject j addr addr' ->
- Mem.storev chunk m addr v = Some m1 ->
- Mem.storev chunk m' addr' v' = Some m1' ->
- agree_frame j ls ls0 m1 sp m1' sp' parent retaddr.
-Proof.
-Opaque Int.add.
- intros until m1'. intros AG MINJ VINJ STORE1 STORE2.
- inv VINJ; simpl in *; try discriminate.
- eapply agree_frame_invariant; eauto.
- eauto with mem.
- eauto with mem.
- eauto with mem.
- intros. rewrite <- H1. eapply Mem.load_store_other; eauto.
- destruct (eq_block sp' b2); auto.
- subst b2. right.
- exploit agree_inj_unique; eauto. intros [P Q]. subst b1 delta.
- exploit Mem.store_valid_access_3. eexact STORE1. intros [A B].
- rewrite shifted_stack_offset_no_overflow.
- exploit agree_bounds. eauto. apply Mem.perm_cur_max. apply A.
- instantiate (1 := Int.unsigned ofs1). generalize (size_chunk_pos chunk). omega.
- intros C.
- exploit agree_bounds. eauto. apply Mem.perm_cur_max. apply A.
- instantiate (1 := Int.unsigned ofs1 + size_chunk chunk - 1). generalize (size_chunk_pos chunk). omega.
- intros D.
- omega.
- eapply agree_bounds. eauto. apply Mem.perm_cur_max. apply A.
- generalize (size_chunk_pos chunk). omega.
- intros; eauto with mem.
-Qed.
-
-(** Preservation by increasing memory injections (allocations and external calls) *)
-
-Lemma agree_frame_inject_incr:
- forall j ls ls0 m sp m' sp' parent retaddr m1 m1' j',
- agree_frame j ls ls0 m sp m' sp' parent retaddr ->
- inject_incr j j' -> inject_separated j j' m1 m1' ->
- Mem.valid_block m1' sp' ->
- agree_frame j' ls ls0 m sp m' sp' parent retaddr.
-Proof.
- intros. inv H. constructor; auto; intros; eauto with stacking.
- case_eq (j b0).
- intros [b' delta'] EQ. rewrite (H0 _ _ _ EQ) in H. inv H. auto.
- intros EQ. exploit H1. eauto. eauto. intros [A B]. contradiction.
-Qed.
-
-Remark inject_alloc_separated:
- forall j m1 m2 j' b1 b2 delta,
- inject_incr j j' ->
- j' b1 = Some(b2, delta) ->
- (forall b, b <> b1 -> j' b = j b) ->
- ~Mem.valid_block m1 b1 -> ~Mem.valid_block m2 b2 ->
- inject_separated j j' m1 m2.
-Proof.
- intros. red. intros.
- destruct (eq_block b0 b1). subst b0. rewrite H0 in H5; inv H5. tauto.
- rewrite H1 in H5. congruence. auto.
+ intros. destruct H; constructor; intros.
+- rewrite Locmap.gso; auto. red; auto.
+- rewrite Locmap.gso; auto. red. left. destruct sl; discriminate.
Qed.
(** Preservation at return points (when [ls] is changed but not [ls0]). *)
-Lemma agree_frame_return:
- forall j ls ls0 m sp m' sp' parent retaddr ls',
- agree_frame j ls ls0 m sp m' sp' parent retaddr ->
+Lemma agree_locs_return:
+ forall ls ls0 ls',
+ agree_locs ls ls0 ->
agree_callee_save ls' ls ->
- agree_frame j ls' ls0 m sp m' sp' parent retaddr.
+ agree_locs ls' ls0.
Proof.
intros. red in H0. inv H; constructor; auto; intros.
- rewrite H0; auto. red; intros; elim H. apply caller_save_reg_within_bounds; auto.
- rewrite H0; auto.
- rewrite H0; auto.
- rewrite H0; auto.
+- rewrite H0; auto. unfold mreg_within_bounds in H. tauto.
+- rewrite H0; auto.
Qed.
(** Preservation at tailcalls (when [ls0] is changed but not [ls]). *)
-Lemma agree_frame_tailcall:
- forall j ls ls0 m sp m' sp' parent retaddr ls0',
- agree_frame j ls ls0 m sp m' sp' parent retaddr ->
+Lemma agree_locs_tailcall:
+ forall ls ls0 ls0',
+ agree_locs ls ls0 ->
agree_callee_save ls0 ls0' ->
- agree_frame j ls ls0' m sp m' sp' parent retaddr.
+ agree_locs ls ls0'.
Proof.
intros. red in H0. inv H; constructor; auto; intros.
- rewrite <- H0; auto. red; intros; elim H. apply caller_save_reg_within_bounds; auto.
- rewrite <- H0; auto.
- rewrite <- H0. auto. red; intros. eapply int_callee_save_not_destroyed; eauto.
- rewrite <- H0. auto. red; intros. eapply float_callee_save_not_destroyed; eauto.
+- rewrite <- H0; auto. unfold mreg_within_bounds in H. tauto.
+- rewrite <- H0; auto.
Qed.
-(** Properties of [agree_callee_save]. *)
+(** ** Properties of [agree_callee_save]. *)
Lemma agree_callee_save_return_regs:
forall ls1 ls2,
agree_callee_save (return_regs ls1 ls2) ls1.
Proof.
intros; red; intros.
- unfold return_regs. destruct l; auto.
- rewrite pred_dec_false; auto.
+ unfold return_regs. destruct l; auto. rewrite H; auto.
Qed.
Lemma agree_callee_save_set_result:
@@ -1108,74 +825,60 @@ Lemma agree_callee_save_set_result:
Proof.
intros sg. generalize (loc_result_caller_save sg).
generalize (loc_result sg).
-Opaque destroyed_at_call.
induction l; simpl; intros.
auto.
destruct vl; auto.
apply IHl; auto.
red; intros. rewrite Locmap.gso. apply H0; auto.
- destruct l0; simpl; auto.
+ destruct l0; simpl; auto. red; intros; subst a.
+ assert (is_callee_save r = false) by auto. congruence.
Qed.
-(** Properties of destroyed registers. *)
+(** ** Properties of destroyed registers. *)
-Lemma check_mreg_list_incl:
- forall l1 l2,
- forallb (fun r => In_dec mreg_eq r l2) l1 = true ->
- incl l1 l2.
-Proof.
- intros; red; intros.
- rewrite forallb_forall in H. eapply proj_sumbool_true. eauto.
-Qed.
+Definition no_callee_saves (l: list mreg) : Prop :=
+ existsb is_callee_save l = false.
Remark destroyed_by_op_caller_save:
- forall op, incl (destroyed_by_op op) destroyed_at_call.
+ forall op, no_callee_saves (destroyed_by_op op).
Proof.
- destruct op; apply check_mreg_list_incl; compute; auto.
+ unfold no_callee_saves; destruct op; reflexivity.
Qed.
Remark destroyed_by_load_caller_save:
- forall chunk addr, incl (destroyed_by_load chunk addr) destroyed_at_call.
+ forall chunk addr, no_callee_saves (destroyed_by_load chunk addr).
Proof.
- intros. destruct chunk; apply check_mreg_list_incl; compute; auto.
+ unfold no_callee_saves; destruct chunk; reflexivity.
Qed.
Remark destroyed_by_store_caller_save:
- forall chunk addr, incl (destroyed_by_store chunk addr) destroyed_at_call.
+ forall chunk addr, no_callee_saves (destroyed_by_store chunk addr).
Proof.
- intros. destruct chunk; apply check_mreg_list_incl; compute; auto.
+ unfold no_callee_saves; destruct chunk; reflexivity.
Qed.
Remark destroyed_by_cond_caller_save:
- forall cond, incl (destroyed_by_cond cond) destroyed_at_call.
+ forall cond, no_callee_saves (destroyed_by_cond cond).
Proof.
- destruct cond; apply check_mreg_list_incl; compute; auto.
+ unfold no_callee_saves; destruct cond; reflexivity.
Qed.
Remark destroyed_by_jumptable_caller_save:
- incl destroyed_by_jumptable destroyed_at_call.
+ no_callee_saves destroyed_by_jumptable.
Proof.
- apply check_mreg_list_incl; compute; auto.
+ red; reflexivity.
Qed.
Remark destroyed_by_setstack_caller_save:
- forall ty, incl (destroyed_by_setstack ty) destroyed_at_call.
+ forall ty, no_callee_saves (destroyed_by_setstack ty).
Proof.
- destruct ty; apply check_mreg_list_incl; compute; auto.
+ unfold no_callee_saves; destruct ty; reflexivity.
Qed.
Remark destroyed_at_function_entry_caller_save:
- incl destroyed_at_function_entry destroyed_at_call.
+ no_callee_saves destroyed_at_function_entry.
Proof.
- apply check_mreg_list_incl; compute; auto.
-Qed.
-
-Remark temp_for_parent_frame_caller_save:
- In temp_for_parent_frame destroyed_at_call.
-Proof.
- Transparent temp_for_parent_frame.
- Transparent destroyed_at_call.
- unfold temp_for_parent_frame; simpl; tauto.
+ red; reflexivity.
Qed.
Hint Resolve destroyed_by_op_caller_save destroyed_by_load_caller_save
@@ -1186,7 +889,8 @@ Hint Resolve destroyed_by_op_caller_save destroyed_by_load_caller_save
Remark destroyed_by_setstack_function_entry:
forall ty, incl (destroyed_by_setstack ty) destroyed_at_function_entry.
Proof.
- destruct ty; apply check_mreg_list_incl; compute; auto.
+Local Transparent destroyed_by_setstack destroyed_at_function_entry.
+ unfold incl; destruct ty; simpl; tauto.
Qed.
Remark transl_destroyed_by_op:
@@ -1216,129 +920,67 @@ Qed.
Section SAVE_CALLEE_SAVE.
-Variable bound: frame_env -> Z.
-Variable number: mreg -> Z.
-Variable mkindex: Z -> frame_index.
-Variable ty: typ.
Variable j: meminj.
Variable cs: list stackframe.
Variable fb: block.
Variable sp: block.
-Variable csregs: list mreg.
Variable ls: locset.
-Inductive stores_in_frame: mem -> mem -> Prop :=
- | stores_in_frame_refl: forall m,
- stores_in_frame m m
- | stores_in_frame_step: forall m1 chunk ofs v m2 m3,
- ofs + size_chunk chunk <= fe.(fe_stack_data)
- \/ fe.(fe_stack_data) + f.(Linear.fn_stacksize) <= ofs ->
- Mem.store chunk m1 sp ofs v = Some m2 ->
- stores_in_frame m2 m3 ->
- stores_in_frame m1 m3.
-
-Remark stores_in_frame_trans:
- forall m1 m2, stores_in_frame m1 m2 ->
- forall m3, stores_in_frame m2 m3 -> stores_in_frame m1 m3.
-Proof.
- induction 1; intros. auto. econstructor; eauto.
-Qed.
-
-Hypothesis number_inj:
- forall r1 r2, In r1 csregs -> In r2 csregs -> r1 <> r2 -> number r1 <> number r2.
-Hypothesis mkindex_valid:
- forall r, In r csregs -> number r < bound fe -> index_valid (mkindex (number r)).
-Hypothesis mkindex_typ:
- forall z, type_of_index (mkindex z) = ty.
-Hypothesis mkindex_inj:
- forall z1 z2, z1 <> z2 -> mkindex z1 <> mkindex z2.
-Hypothesis mkindex_diff:
- forall r idx,
- idx <> mkindex (number r) -> index_diff (mkindex (number r)) idx.
-Hypothesis csregs_typ:
- forall r, In r csregs -> mreg_type r = ty.
-
Hypothesis ls_temp_undef:
- forall r, In r (destroyed_by_setstack ty) -> ls (R r) = Vundef.
+ forall ty r, In r (destroyed_by_setstack ty) -> ls (R r) = Vundef.
Hypothesis wt_ls: forall r, Val.has_type (ls (R r)) (mreg_type r).
-Lemma save_callee_save_regs_correct:
- forall l k rs m,
- incl l csregs ->
- list_norepet l ->
- frame_perm_freeable m sp ->
+Lemma save_callee_save_rec_correct:
+ forall k l pos rs m P,
+ (forall r, In r l -> is_callee_save r = true) ->
+ m |= range sp pos (size_callee_save_area_rec l pos) ** P ->
agree_regs j ls rs ->
exists rs', exists m',
- star step tge
- (State cs fb (Vptr sp Int.zero)
- (save_callee_save_regs bound number mkindex ty fe l k) rs m)
- E0 (State cs fb (Vptr sp Int.zero) k rs' m')
- /\ (forall r,
- In r l -> number r < bound fe ->
- index_contains_inj j m' sp (mkindex (number r)) (ls (R r)))
- /\ (forall idx v,
- index_valid idx ->
- (forall r,
- In r l -> number r < bound fe -> idx <> mkindex (number r)) ->
- index_contains m sp idx v ->
- index_contains m' sp idx v)
- /\ stores_in_frame m m'
- /\ frame_perm_freeable m' sp
+ star step tge
+ (State cs fb (Vptr sp Int.zero) (save_callee_save_rec l pos k) rs m)
+ E0 (State cs fb (Vptr sp Int.zero) k rs' m')
+ /\ m' |= contains_callee_saves j sp pos l ls ** P
+ /\ (forall ofs k p, Mem.perm m sp ofs k p -> Mem.perm m' sp ofs k p)
/\ agree_regs j ls rs'.
Proof.
- induction l; intros; simpl save_callee_save_regs.
- (* base case *)
- exists rs; exists m. split. apply star_refl.
- split. intros. elim H3.
- split. auto.
- split. constructor.
+ induction l as [ | r l]; simpl; intros until P; intros CS SEP AG.
+- exists rs, m.
+ split. apply star_refl.
+ split. rewrite sep_pure; split; auto. eapply sep_drop; eauto.
+ split. auto.
auto.
- (* inductive case *)
- assert (R1: incl l csregs). eauto with coqlib.
- assert (R2: list_norepet l). inversion H0; auto.
- unfold save_callee_save_reg.
- destruct (zlt (number a) (bound fe)).
- (* a store takes place *)
- exploit store_index_succeeds. apply (mkindex_valid a); auto with coqlib.
- eauto. instantiate (1 := rs a). intros [m1 ST].
- exploit (IHl k (undef_regs (destroyed_by_setstack ty) rs) m1). auto with coqlib. auto.
- red; eauto with mem.
- apply agree_regs_exten with ls rs. auto.
- intros. destruct (In_dec mreg_eq r (destroyed_by_setstack ty)).
- left. apply ls_temp_undef; auto.
- right; split. auto. apply undef_regs_other; auto.
- intros [rs' [m' [A [B [C [D [E F]]]]]]].
- exists rs'; exists m'.
- split. eapply star_left; eauto. econstructor.
- rewrite <- (mkindex_typ (number a)).
- apply store_stack_succeeds; auto with coqlib.
- auto. traceEq.
- split; intros.
- simpl in H3. destruct (mreg_eq a r). subst r.
- assert (index_contains_inj j m1 sp (mkindex (number a)) (ls (R a))).
- eapply gss_index_contains_inj; eauto.
- rewrite mkindex_typ. rewrite <- (csregs_typ a). apply wt_ls.
- auto with coqlib.
- destruct H5 as [v' [P Q]].
- exists v'; split; auto. apply C; auto.
- intros. apply mkindex_inj. apply number_inj; auto with coqlib.
- inv H0. intuition congruence.
- apply B; auto with coqlib.
- intuition congruence.
- split. intros.
- apply C; auto with coqlib.
- eapply gso_index_contains; eauto with coqlib.
- split. econstructor; eauto.
- rewrite size_type_chunk. apply offset_of_index_disj_stack_data_2; eauto with coqlib.
+- set (ty := mreg_type r) in *.
+ set (sz := AST.typesize ty) in *.
+ set (pos1 := align pos sz) in *.
+ assert (SZPOS: sz > 0) by (apply AST.typesize_pos).
+ assert (SZREC: pos1 + sz <= size_callee_save_area_rec l (pos1 + sz)) by (apply size_callee_save_area_rec_incr).
+ assert (POS1: pos <= pos1) by (apply align_le; auto).
+ assert (AL1: (align_chunk (chunk_of_type ty) | pos1)).
+ { unfold pos1. apply Zdivide_trans with sz.
+ unfold sz; rewrite <- size_type_chunk. apply align_size_chunk_divides.
+ apply align_divides; auto. }
+ apply range_drop_left with (mid := pos1) in SEP; [ | omega ].
+ apply range_split with (mid := pos1 + sz) in SEP; [ | omega ].
+ unfold sz at 1 in SEP. rewrite <- size_type_chunk in SEP.
+ apply range_contains in SEP; auto.
+ exploit (contains_set_stack (fun v' => Val.inject j (ls (R r)) v') (rs r)).
+ eexact SEP.
+ apply load_result_inject; auto. apply wt_ls.
+ clear SEP; intros (m1 & STORE & SEP).
+ set (rs1 := undef_regs (destroyed_by_setstack ty) rs).
+ assert (AG1: agree_regs j ls rs1).
+ { red; intros. unfold rs1. destruct (In_dec mreg_eq r0 (destroyed_by_setstack ty)).
+ erewrite ls_temp_undef by eauto. auto.
+ rewrite undef_regs_other by auto. apply AG. }
+ rewrite sep_swap in SEP.
+ exploit (IHl (pos1 + sz) rs1 m1); eauto.
+ intros (rs2 & m2 & A & B & C & D).
+ exists rs2, m2.
+ split. eapply star_left; eauto. constructor. exact STORE. auto. traceEq.
+ split. rewrite sep_assoc, sep_swap. exact B.
+ split. intros. apply C. unfold store_stack in STORE; simpl in STORE. eapply Mem.perm_store_1; eauto.
auto.
- (* no store takes place *)
- exploit (IHl k rs m); auto with coqlib.
- intros [rs' [m' [A [B [C [D [E F]]]]]]].
- exists rs'; exists m'; intuition.
- simpl in H3. destruct H3. subst r. omegaContradiction. apply B; auto.
- apply C; auto with coqlib.
- intros. eapply H4; eauto. auto with coqlib.
Qed.
End SAVE_CALLEE_SAVE.
@@ -1366,127 +1008,7 @@ Proof.
rewrite Locmap.gso. apply IHrl. red; auto.
Qed.
-Lemma save_callee_save_correct:
- forall j ls0 rs sp cs fb k m,
- let ls := LTL.undef_regs destroyed_at_function_entry ls0 in
- agree_regs j ls rs ->
- (forall r, Val.has_type (ls (R r)) (mreg_type r)) ->
- frame_perm_freeable m sp ->
- exists rs', exists m',
- star step tge
- (State cs fb (Vptr sp Int.zero) (save_callee_save fe k) rs m)
- E0 (State cs fb (Vptr sp Int.zero) k rs' m')
- /\ (forall r,
- In r int_callee_save_regs -> index_int_callee_save r < b.(bound_int_callee_save) ->
- index_contains_inj j m' sp (FI_saved_int (index_int_callee_save r)) (ls (R r)))
- /\ (forall r,
- In r float_callee_save_regs -> index_float_callee_save r < b.(bound_float_callee_save) ->
- index_contains_inj j m' sp (FI_saved_float (index_float_callee_save r)) (ls (R r)))
- /\ (forall idx v,
- index_valid idx ->
- match idx with FI_saved_int _ => False | FI_saved_float _ => False | _ => True end ->
- index_contains m sp idx v ->
- index_contains m' sp idx v)
- /\ stores_in_frame sp m m'
- /\ frame_perm_freeable m' sp
- /\ agree_regs j ls rs'.
-Proof.
- intros.
- assert (UNDEF: forall r ty, In r (destroyed_by_setstack ty) -> ls (R r) = Vundef).
- intros. unfold ls. apply LTL_undef_regs_same. eapply destroyed_by_setstack_function_entry; eauto.
- exploit (save_callee_save_regs_correct
- fe_num_int_callee_save
- index_int_callee_save
- FI_saved_int Tany32
- j cs fb sp int_callee_save_regs ls).
- intros. apply index_int_callee_save_inj; auto.
- intros. simpl. split. apply Zge_le. apply index_int_callee_save_pos; auto. assumption.
- auto.
- intros; congruence.
- intros; simpl. destruct idx; auto. congruence.
- intros. apply int_callee_save_type. auto.
- eauto.
- auto.
- apply incl_refl.
- apply int_callee_save_norepet.
- eauto.
- eauto.
- intros [rs1 [m1 [A [B [C [D [E F]]]]]]].
- exploit (save_callee_save_regs_correct
- fe_num_float_callee_save
- index_float_callee_save
- FI_saved_float Tany64
- j cs fb sp float_callee_save_regs ls).
- intros. apply index_float_callee_save_inj; auto.
- intros. simpl. split. apply Zge_le. apply index_float_callee_save_pos; auto. assumption.
- simpl; auto.
- intros; congruence.
- intros; simpl. destruct idx; auto. congruence.
- intros. apply float_callee_save_type. auto.
- eauto.
- auto.
- apply incl_refl.
- apply float_callee_save_norepet.
- eexact E.
- eexact F.
- intros [rs2 [m2 [P [Q [R [S [T U]]]]]]].
- exists rs2; exists m2.
- split. unfold save_callee_save, save_callee_save_int, save_callee_save_float.
- eapply star_trans; eauto.
- split; intros.
- destruct (B r H2 H3) as [v [X Y]]. exists v; split; auto. apply R.
- apply index_saved_int_valid; auto.
- intros. congruence.
- auto.
- split. intros. apply Q; auto.
- split. intros. apply R. auto.
- intros. destruct idx; contradiction||congruence.
- apply C. auto.
- intros. destruct idx; contradiction||congruence.
- auto.
- split. eapply stores_in_frame_trans; eauto.
- auto.
-Qed.
-
-(** Properties of sequences of stores in the frame. *)
-
-Lemma stores_in_frame_inject:
- forall j sp sp' m,
- (forall b delta, j b = Some(sp', delta) -> b = sp /\ delta = fe.(fe_stack_data)) ->
- (forall ofs k p, Mem.perm m sp ofs k p -> 0 <= ofs < f.(Linear.fn_stacksize)) ->
- forall m1 m2, stores_in_frame sp' m1 m2 -> Mem.inject j m m1 -> Mem.inject j m m2.
-Proof.
- induction 3; intros.
- auto.
- apply IHstores_in_frame.
- intros. eapply Mem.store_outside_inject; eauto.
- intros. exploit H; eauto. intros [A B]; subst.
- exploit H0; eauto. omega.
-Qed.
-
-Lemma stores_in_frame_valid:
- forall b sp m m', stores_in_frame sp m m' -> Mem.valid_block m b -> Mem.valid_block m' b.
-Proof.
- induction 1; intros. auto. apply IHstores_in_frame. eauto with mem.
-Qed.
-
-Lemma stores_in_frame_perm:
- forall b ofs k p sp m m', stores_in_frame sp m m' -> Mem.perm m b ofs k p -> Mem.perm m' b ofs k p.
-Proof.
- induction 1; intros. auto. apply IHstores_in_frame. eauto with mem.
-Qed.
-
-Lemma stores_in_frame_contents:
- forall chunk b ofs sp, Plt b sp ->
- forall m m', stores_in_frame sp m m' ->
- Mem.load chunk m' b ofs = Mem.load chunk m b ofs.
-Proof.
- induction 2. auto.
- rewrite IHstores_in_frame. eapply Mem.load_store_other; eauto.
- left. apply Plt_ne; auto.
-Qed.
-
-Lemma undef_regs_type:
+Remark undef_regs_type:
forall ty l rl ls,
Val.has_type (ls l) ty -> Val.has_type (LTL.undef_regs rl ls l) ty.
Proof.
@@ -1496,21 +1018,60 @@ Proof.
destruct (Loc.diff_dec (R a) l); auto. red; auto.
Qed.
+Lemma save_callee_save_correct:
+ forall j ls ls0 rs sp cs fb k m P,
+ m |= range sp fe.(fe_ofs_callee_save) (size_callee_save_area b fe.(fe_ofs_callee_save)) ** P ->
+ (forall r, Val.has_type (ls (R r)) (mreg_type r)) ->
+ agree_callee_save ls ls0 ->
+ agree_regs j ls rs ->
+ let ls1 := LTL.undef_regs destroyed_at_function_entry (LTL.call_regs ls) in
+ let rs1 := undef_regs destroyed_at_function_entry rs in
+ exists rs', exists m',
+ star step tge
+ (State cs fb (Vptr sp Int.zero) (save_callee_save fe k) rs1 m)
+ E0 (State cs fb (Vptr sp Int.zero) k rs' m')
+ /\ m' |= contains_callee_saves j sp fe.(fe_ofs_callee_save) b.(used_callee_save) ls0 ** P
+ /\ (forall ofs k p, Mem.perm m sp ofs k p -> Mem.perm m' sp ofs k p)
+ /\ agree_regs j ls1 rs'.
+Proof.
+ intros until P; intros SEP TY AGCS AG; intros ls1 rs1.
+ exploit (save_callee_save_rec_correct j cs fb sp ls1).
+- intros. unfold ls1. apply LTL_undef_regs_same. eapply destroyed_by_setstack_function_entry; eauto.
+- intros. unfold ls1. apply undef_regs_type. apply TY.
+- exact b.(used_callee_save_prop).
+- eexact SEP.
+- instantiate (1 := rs1). apply agree_regs_undef_regs. apply agree_regs_call_regs. auto.
+- clear SEP. intros (rs' & m' & EXEC & SEP & PERMS & AG').
+ exists rs', m'.
+ split. eexact EXEC.
+ split. rewrite (contains_callee_saves_exten j sp ls0 ls1). exact SEP.
+ intros. apply b.(used_callee_save_prop) in H.
+ unfold ls1. rewrite LTL_undef_regs_others. unfold call_regs.
+ apply AGCS; auto.
+ red; intros.
+ assert (existsb is_callee_save destroyed_at_function_entry = false)
+ by (apply destroyed_at_function_entry_caller_save).
+ assert (existsb is_callee_save destroyed_at_function_entry = true).
+ { apply existsb_exists. exists r; auto. }
+ congruence.
+ split. exact PERMS. exact AG'.
+Qed.
+
(** As a corollary of the previous lemmas, we obtain the following
correctness theorem for the execution of a function prologue
(allocation of the frame + saving of the link and return address +
saving of the used callee-save registers). *)
Lemma function_prologue_correct:
- forall j ls ls0 ls1 rs rs1 m1 m1' m2 sp parent ra cs fb k,
+ forall j ls ls0 ls1 rs rs1 m1 m1' m2 sp parent ra cs fb k P,
agree_regs j ls rs ->
agree_callee_save ls ls0 ->
(forall r, Val.has_type (ls (R r)) (mreg_type r)) ->
ls1 = LTL.undef_regs destroyed_at_function_entry (LTL.call_regs ls) ->
rs1 = undef_regs destroyed_at_function_entry rs ->
- Mem.inject j m1 m1' ->
Mem.alloc m1 0 f.(Linear.fn_stacksize) = (m2, sp) ->
Val.has_type parent Tint -> Val.has_type ra Tint ->
+ m1' |= minjection j m1 ** globalenv_inject ge j ** P ->
exists j', exists rs', exists m2', exists sp', exists m3', exists m4', exists m5',
Mem.alloc m1' 0 tf.(fn_stacksize) = (m2', sp')
/\ store_stack m2' (Vptr sp' Int.zero) Tint tf.(fn_link_ofs) parent = Some m3'
@@ -1519,143 +1080,97 @@ Lemma function_prologue_correct:
(State cs fb (Vptr sp' Int.zero) (save_callee_save fe k) rs1 m4')
E0 (State cs fb (Vptr sp' Int.zero) k rs' m5')
/\ agree_regs j' ls1 rs'
- /\ agree_frame j' ls1 ls0 m2 sp m5' sp' parent ra
- /\ inject_incr j j'
- /\ inject_separated j j' m1 m1'
- /\ Mem.inject j' m2 m5'
- /\ stores_in_frame sp' m2' m5'.
+ /\ agree_locs ls1 ls0
+ /\ m5' |= frame_contents j' sp' ls1 ls0 parent ra ** minjection j' m2 ** globalenv_inject ge j' ** P
+ /\ j' sp = Some(sp', fe.(fe_stack_data))
+ /\ inject_incr j j'.
Proof.
- intros until k; intros AGREGS AGCS WTREGS LS1 RS1 INJ1 ALLOC TYPAR TYRA.
+ intros until P; intros AGREGS AGCS WTREGS LS1 RS1 ALLOC TYPAR TYRA SEP.
rewrite unfold_transf_function.
unfold fn_stacksize, fn_link_ofs, fn_retaddr_ofs.
+ (* Stack layout info *)
+Local Opaque b fe.
+ generalize (frame_env_range b) (frame_env_aligned b). replace (make_env b) with fe by auto. simpl.
+ intros LAYOUT1 LAYOUT2.
(* Allocation step *)
- caseEq (Mem.alloc m1' 0 (fe_size fe)). intros m2' sp' ALLOC'.
- exploit Mem.alloc_left_mapped_inject.
- eapply Mem.alloc_right_inject; eauto.
- eauto.
- instantiate (1 := sp'). eauto with mem.
- instantiate (1 := fe_stack_data fe).
- generalize stack_data_offset_valid (bound_stack_data_pos b) size_no_overflow; omega.
- intros; right.
- exploit Mem.perm_alloc_inv. eexact ALLOC'. eauto. rewrite dec_eq_true.
- generalize size_no_overflow. omega.
- intros. apply Mem.perm_implies with Freeable; auto with mem.
- eapply Mem.perm_alloc_2; eauto.
- generalize stack_data_offset_valid bound_stack_data_stacksize; omega.
- red. intros. apply Zdivides_trans with 8.
- destruct chunk; simpl; auto with align_4.
- apply fe_stack_data_aligned.
- intros.
- assert (Mem.valid_block m1' sp'). eapply Mem.valid_block_inject_2; eauto.
- assert (~Mem.valid_block m1' sp') by eauto with mem.
- contradiction.
- intros [j' [INJ2 [INCR [MAP1 MAP2]]]].
- assert (PERM: frame_perm_freeable m2' sp').
- red; intros. eapply Mem.perm_alloc_2; eauto.
+ destruct (Mem.alloc m1' 0 (fe_size fe)) as [m2' sp'] eqn:ALLOC'.
+ exploit alloc_parallel_rule_2.
+ eexact SEP. eexact ALLOC. eexact ALLOC'.
+ instantiate (1 := fe_stack_data fe). tauto.
+ reflexivity.
+ instantiate (1 := fe_stack_data fe + bound_stack_data b). rewrite Z.max_comm. reflexivity.
+ generalize (bound_stack_data_pos b) size_no_overflow; omega.
+ tauto.
+ tauto.
+ clear SEP. intros (j' & SEP & INCR & SAME).
+ (* Remember the freeable permissions using a mconj *)
+ assert (SEPCONJ:
+ m2' |= mconj (range sp' 0 (fe_stack_data fe) ** range sp' (fe_stack_data fe + bound_stack_data b) (fe_size fe))
+ (range sp' 0 (fe_stack_data fe) ** range sp' (fe_stack_data fe + bound_stack_data b) (fe_size fe))
+ ** minjection j' m2 ** globalenv_inject ge j' ** P).
+ { apply mconj_intro; rewrite sep_assoc; assumption. }
+ (* Dividing up the frame *)
+ apply (frame_env_separated b) in SEP. replace (make_env b) with fe in SEP by auto.
(* Store of parent *)
- exploit (store_index_succeeds m2' sp' FI_link parent). red; auto. auto.
- intros [m3' STORE2].
- (* Store of retaddr *)
- exploit (store_index_succeeds m3' sp' FI_retaddr ra). red; auto. red; eauto with mem.
- intros [m4' STORE3].
+ rewrite sep_swap3 in SEP.
+ apply (range_contains Mint32) in SEP; [|tauto].
+ exploit (contains_set_stack (fun v' => v' = parent) parent (fun _ => True) m2' Tint).
+ eexact SEP. apply Val.load_result_same; auto.
+ clear SEP; intros (m3' & STORE_PARENT & SEP).
+ rewrite sep_swap3 in SEP.
+ (* Store of return address *)
+ rewrite sep_swap4 in SEP.
+ apply (range_contains Mint32) in SEP; [|tauto].
+ exploit (contains_set_stack (fun v' => v' = ra) ra (fun _ => True) m3' Tint).
+ eexact SEP. apply Val.load_result_same; auto.
+ clear SEP; intros (m4' & STORE_RETADDR & SEP).
+ rewrite sep_swap4 in SEP.
(* Saving callee-save registers *)
- assert (PERM4: frame_perm_freeable m4' sp').
- red; intros. eauto with mem.
- exploit save_callee_save_correct.
- instantiate (1 := rs1). instantiate (1 := call_regs ls). instantiate (1 := j').
- subst rs1. apply agree_regs_undef_regs.
- apply agree_regs_call_regs. eapply agree_regs_inject_incr; eauto.
- intros. apply undef_regs_type. simpl. apply WTREGS.
- eexact PERM4.
- rewrite <- LS1.
- intros [rs' [m5' [STEPS [ICS [FCS [OTHERS [STORES [PERM5 AGREGS']]]]]]]].
- (* stores in frames *)
- assert (SIF: stores_in_frame sp' m2' m5').
- econstructor; eauto.
- rewrite size_type_chunk. apply offset_of_index_disj_stack_data_2; auto. red; auto.
- econstructor; eauto.
- rewrite size_type_chunk. apply offset_of_index_disj_stack_data_2; auto. red; auto.
- (* separation *)
- assert (SEP: forall b0 delta, j' b0 = Some(sp', delta) -> b0 = sp /\ delta = fe_stack_data fe).
- intros. destruct (eq_block b0 sp).
- subst b0. rewrite MAP1 in H; inv H; auto.
- rewrite MAP2 in H; auto.
- assert (Mem.valid_block m1' sp'). eapply Mem.valid_block_inject_2; eauto.
- assert (~Mem.valid_block m1' sp') by eauto with mem.
- contradiction.
- (* Conclusions *)
- exists j'; exists rs'; exists m2'; exists sp'; exists m3'; exists m4'; exists m5'.
+ rewrite sep_swap5 in SEP.
+ exploit (save_callee_save_correct j' ls ls0 rs); eauto.
+ apply agree_regs_inject_incr with j; auto.
+ replace (LTL.undef_regs destroyed_at_function_entry (call_regs ls)) with ls1 by auto.
+ replace (undef_regs destroyed_at_function_entry rs) with rs1 by auto.
+ clear SEP; intros (rs2 & m5' & SAVE_CS & SEP & PERMS & AGREGS').
+ rewrite sep_swap5 in SEP.
+ (* Materializing the Local and Outgoing locations *)
+ exploit (initial_locations j'). eexact SEP. tauto.
+ instantiate (1 := Local). instantiate (1 := ls1).
+ intros; rewrite LS1. rewrite LTL_undef_regs_slot. reflexivity.
+ clear SEP; intros SEP.
+ rewrite sep_swap in SEP.
+ exploit (initial_locations j'). eexact SEP. tauto.
+ instantiate (1 := Outgoing). instantiate (1 := ls1).
+ intros; rewrite LS1. rewrite LTL_undef_regs_slot. reflexivity.
+ clear SEP; intros SEP.
+ rewrite sep_swap in SEP.
+ (* Now we frame this *)
+ assert (SEPFINAL: m5' |= frame_contents j' sp' ls1 ls0 parent ra ** minjection j' m2 ** globalenv_inject ge j' ** P).
+ { eapply frame_mconj. eexact SEPCONJ.
+ unfold frame_contents_1; rewrite ! sep_assoc. exact SEP.
+ assert (forall ofs k p, Mem.perm m2' sp' ofs k p -> Mem.perm m5' sp' ofs k p).
+ { intros. apply PERMS.
+ unfold store_stack in STORE_PARENT, STORE_RETADDR.
+ simpl in STORE_PARENT, STORE_RETADDR.
+ eauto using Mem.perm_store_1. }
+ eapply sep_preserved. eapply sep_proj1. eapply mconj_proj2. eexact SEPCONJ.
+ intros; apply range_preserved with m2'; auto.
+ intros; apply range_preserved with m2'; auto.
+ }
+ clear SEP SEPCONJ.
+(* Conclusions *)
+ exists j', rs2, m2', sp', m3', m4', m5'.
split. auto.
- (* store parent *)
- split. change Tint with (type_of_index FI_link).
- change (fe_ofs_link fe) with (offset_of_index fe FI_link).
- apply store_stack_succeeds; auto. red; auto.
- (* store retaddr *)
- split. change Tint with (type_of_index FI_retaddr).
- change (fe_ofs_retaddr fe) with (offset_of_index fe FI_retaddr).
- apply store_stack_succeeds; auto. red; auto.
- (* saving of registers *)
- split. eexact STEPS.
- (* agree_regs *)
- split. auto.
- (* agree frame *)
- split. constructor; intros.
- (* unused regs *)
- assert (~In r destroyed_at_call).
- red; intros; elim H; apply caller_save_reg_within_bounds; auto.
- rewrite LS1. rewrite LTL_undef_regs_others. unfold call_regs.
- apply AGCS; auto. red; intros; elim H0.
- apply destroyed_at_function_entry_caller_save; auto.
- (* locals *)
- rewrite LS1. rewrite LTL_undef_regs_slot. unfold call_regs.
- apply index_contains_inj_undef; auto with stacking.
- (* outgoing *)
- rewrite LS1. rewrite LTL_undef_regs_slot. unfold call_regs.
- apply index_contains_inj_undef; auto with stacking.
- (* incoming *)
- rewrite LS1. rewrite LTL_undef_regs_slot. unfold call_regs.
- apply AGCS; auto.
- (* parent *)
- apply OTHERS; auto. red; auto.
- eapply gso_index_contains; eauto. red; auto.
- eapply gss_index_contains; eauto. red; auto.
- red; auto.
- (* retaddr *)
- apply OTHERS; auto. red; auto.
- eapply gss_index_contains; eauto. red; auto.
- (* int callee save *)
- assert (~In r destroyed_at_call).
- red; intros. eapply int_callee_save_not_destroyed; eauto.
- exploit ICS; eauto. rewrite LS1. rewrite LTL_undef_regs_others. unfold call_regs.
- rewrite AGCS; auto.
- red; intros; elim H1. apply destroyed_at_function_entry_caller_save; auto.
- (* float callee save *)
- assert (~In r destroyed_at_call).
- red; intros. eapply float_callee_save_not_destroyed; eauto.
- exploit FCS; eauto. rewrite LS1. rewrite LTL_undef_regs_others. unfold call_regs.
- rewrite AGCS; auto.
- red; intros; elim H1. apply destroyed_at_function_entry_caller_save; auto.
- (* inj *)
- auto.
- (* inj_unique *)
- auto.
- (* valid sp *)
- eauto with mem.
- (* valid sp' *)
- eapply stores_in_frame_valid with (m := m2'); eauto with mem.
- (* bounds *)
- exploit Mem.perm_alloc_inv. eexact ALLOC. eauto. rewrite dec_eq_true. auto.
- (* perms *)
- auto.
- (* incr *)
- split. auto.
- (* separated *)
- split. eapply inject_alloc_separated; eauto with mem.
- (* inject *)
- split. eapply stores_in_frame_inject; eauto.
- intros. exploit Mem.perm_alloc_inv. eexact ALLOC. eauto. rewrite dec_eq_true. auto.
- (* stores in frame *)
- auto.
+ split. exact STORE_PARENT.
+ split. exact STORE_RETADDR.
+ split. eexact SAVE_CS.
+ split. exact AGREGS'.
+ split. rewrite LS1. apply agree_locs_undef_locs; [|reflexivity].
+ constructor; intros. unfold call_regs. apply AGCS.
+ unfold mreg_within_bounds in H; tauto.
+ unfold call_regs. apply AGCS. auto.
+ split. exact SEPFINAL.
+ split. exact SAME. exact INCR.
Qed.
(** The following lemmas show the correctness of the register reloading
@@ -1665,11 +1180,6 @@ Qed.
Section RESTORE_CALLEE_SAVE.
-Variable bound: frame_env -> Z.
-Variable number: mreg -> Z.
-Variable mkindex: Z -> frame_index.
-Variable ty: typ.
-Variable csregs: list mreg.
Variable j: meminj.
Variable cs: list stackframe.
Variable fb: block.
@@ -1677,133 +1187,80 @@ Variable sp: block.
Variable ls0: locset.
Variable m: mem.
-Hypothesis mkindex_valid:
- forall r, In r csregs -> number r < bound fe -> index_valid (mkindex (number r)).
-Hypothesis mkindex_typ:
- forall z, type_of_index (mkindex z) = ty.
-Hypothesis number_within_bounds:
- forall r, In r csregs ->
- (number r < bound fe <-> mreg_within_bounds b r).
-Hypothesis mkindex_val:
- forall r,
- In r csregs -> number r < bound fe ->
- index_contains_inj j m sp (mkindex (number r)) (ls0 (R r)).
-
Definition agree_unused (ls0: locset) (rs: regset) : Prop :=
forall r, ~(mreg_within_bounds b r) -> Val.inject j (ls0 (R r)) (rs r).
-Lemma restore_callee_save_regs_correct:
- forall l rs k,
- incl l csregs ->
- list_norepet l ->
+Lemma restore_callee_save_rec_correct:
+ forall l ofs rs k,
+ m |= contains_callee_saves j sp ofs l ls0 ->
agree_unused ls0 rs ->
+ (forall r, In r l -> mreg_within_bounds b r) ->
exists rs',
star step tge
- (State cs fb (Vptr sp Int.zero)
- (restore_callee_save_regs bound number mkindex ty fe l k) rs m)
+ (State cs fb (Vptr sp Int.zero) (restore_callee_save_rec l ofs k) rs m)
E0 (State cs fb (Vptr sp Int.zero) k rs' m)
/\ (forall r, In r l -> Val.inject j (ls0 (R r)) (rs' r))
/\ (forall r, ~(In r l) -> rs' r = rs r)
/\ agree_unused ls0 rs'.
Proof.
- induction l; intros; simpl restore_callee_save_regs.
- (* base case *)
- exists rs. intuition. apply star_refl.
- (* inductive case *)
- assert (R0: In a csregs). apply H; auto with coqlib.
- assert (R1: incl l csregs). eauto with coqlib.
- assert (R2: list_norepet l). inversion H0; auto.
- unfold restore_callee_save_reg.
- destruct (zlt (number a) (bound fe)).
- exploit (mkindex_val a); auto. intros [v [X Y]].
- set (rs1 := Regmap.set a v rs).
- exploit (IHl rs1 k); eauto.
- red; intros. unfold rs1. unfold Regmap.set. destruct (RegEq.eq r a).
- subst r. auto.
- auto.
- intros [rs' [A [B [C D]]]].
- exists rs'. split.
- eapply star_left.
- constructor. rewrite <- (mkindex_typ (number a)). apply index_contains_load_stack. eauto.
- eauto. traceEq.
- split. intros. destruct H2.
- subst r. rewrite C. unfold rs1. rewrite Regmap.gss. auto. inv H0; auto.
- auto.
- split. intros. simpl in H2. rewrite C. unfold rs1. apply Regmap.gso.
- apply sym_not_eq; tauto. tauto.
- auto.
- (* no load takes place *)
- exploit (IHl rs k); auto.
- intros [rs' [A [B [C D]]]].
- exists rs'. split. assumption.
- split. intros. destruct H2.
- subst r. apply D.
- rewrite <- number_within_bounds. auto. auto. auto.
- split. intros. simpl in H2. apply C. tauto.
- auto.
+ induction l as [ | r l]; simpl; intros.
+- (* base case *)
+ exists rs. intuition auto. apply star_refl.
+- (* inductive case *)
+ set (ty := mreg_type r) in *.
+ set (sz := AST.typesize ty) in *.
+ set (ofs1 := align ofs sz).
+ assert (SZPOS: sz > 0) by (apply AST.typesize_pos).
+ assert (OFSLE: ofs <= ofs1) by (apply align_le; auto).
+ assert (BOUND: mreg_within_bounds b r) by eauto.
+ exploit contains_get_stack.
+ eapply sep_proj1; eassumption.
+ intros (v & LOAD & SPEC).
+ exploit (IHl (ofs1 + sz) (rs#r <- v)).
+ eapply sep_proj2; eassumption.
+ red; intros. rewrite Regmap.gso. auto. intuition congruence.
+ eauto.
+ intros (rs' & A & B & C & D).
+ exists rs'.
+ split. eapply star_step; eauto.
+ econstructor. exact LOAD. traceEq.
+ split. intros.
+ destruct (In_dec mreg_eq r0 l). auto.
+ assert (r = r0) by tauto. subst r0.
+ rewrite C by auto. rewrite Regmap.gss. exact SPEC.
+ split. intros.
+ rewrite C by tauto. apply Regmap.gso. intuition auto.
+ exact D.
Qed.
End RESTORE_CALLEE_SAVE.
Lemma restore_callee_save_correct:
- forall j ls ls0 m sp m' sp' pa ra cs fb rs k,
- agree_frame j ls ls0 m sp m' sp' pa ra ->
+ forall m j sp ls ls0 pa ra P rs k cs fb,
+ m |= frame_contents j sp ls ls0 pa ra ** P ->
agree_unused j ls0 rs ->
exists rs',
star step tge
- (State cs fb (Vptr sp' Int.zero) (restore_callee_save fe k) rs m')
- E0 (State cs fb (Vptr sp' Int.zero) k rs' m')
+ (State cs fb (Vptr sp Int.zero) (restore_callee_save fe k) rs m)
+ E0 (State cs fb (Vptr sp Int.zero) k rs' m)
/\ (forall r,
- In r int_callee_save_regs \/ In r float_callee_save_regs ->
- Val.inject j (ls0 (R r)) (rs' r))
+ is_callee_save r = true -> Val.inject j (ls0 (R r)) (rs' r))
/\ (forall r,
- ~(In r int_callee_save_regs) ->
- ~(In r float_callee_save_regs) ->
- rs' r = rs r).
+ is_callee_save r = false -> rs' r = rs r).
Proof.
intros.
- exploit (restore_callee_save_regs_correct
- fe_num_int_callee_save
- index_int_callee_save
- FI_saved_int
- Tany32
- int_callee_save_regs
- j cs fb sp' ls0 m'); auto.
- intros. unfold mreg_within_bounds. split; intros.
- split; auto. destruct (zlt (index_float_callee_save r) 0).
- generalize (bound_float_callee_save_pos b). omega.
- eelim int_float_callee_save_disjoint. eauto.
- eapply index_float_callee_save_pos2. eauto. auto.
- destruct H2; auto.
- eapply agree_saved_int; eauto.
- apply incl_refl.
- apply int_callee_save_norepet.
- eauto.
- intros [rs1 [A [B [C D]]]].
- exploit (restore_callee_save_regs_correct
- fe_num_float_callee_save
- index_float_callee_save
- FI_saved_float
- Tany64
- float_callee_save_regs
- j cs fb sp' ls0 m'); auto.
- intros. unfold mreg_within_bounds. split; intros.
- split; auto. destruct (zlt (index_int_callee_save r) 0).
- generalize (bound_int_callee_save_pos b). omega.
- eelim int_float_callee_save_disjoint.
- eapply index_int_callee_save_pos2. eauto. eauto. auto.
- destruct H2; auto.
- eapply agree_saved_float; eauto.
- apply incl_refl.
- apply float_callee_save_norepet.
- eexact D.
- intros [rs2 [P [Q [R S]]]].
- exists rs2.
- split. unfold restore_callee_save. eapply star_trans; eauto.
- split. intros. destruct H1.
- rewrite R. apply B; auto. red; intros. exploit int_float_callee_save_disjoint; eauto.
- apply Q; auto.
- intros. rewrite R; auto.
+ unfold frame_contents, frame_contents_1 in H.
+ apply mconj_proj1 in H. rewrite ! sep_assoc in H. apply sep_pick5 in H.
+ exploit restore_callee_save_rec_correct; eauto.
+ intros; unfold mreg_within_bounds; auto.
+ intros (rs' & A & B & C & D).
+ exists rs'.
+ split. eexact A.
+ split; intros.
+ destruct (In_dec mreg_eq r (used_callee_save b)).
+ apply B; auto.
+ rewrite C by auto. apply H0. unfold mreg_within_bounds; tauto.
+ apply C. red; intros. apply (used_callee_save_prop b) in H2. congruence.
Qed.
(** As a corollary, we obtain the following correctness result for
@@ -1812,10 +1269,11 @@ Qed.
of the frame). *)
Lemma function_epilogue_correct:
- forall j ls ls0 m sp m' sp' pa ra cs fb rs k m1,
+ forall m' j sp' ls ls0 pa ra P m rs sp m1 k cs fb,
+ m' |= frame_contents j sp' ls ls0 pa ra ** minjection j m ** P ->
agree_regs j ls rs ->
- agree_frame j ls ls0 m sp m' sp' pa ra ->
- Mem.inject j m m' ->
+ agree_locs ls ls0 ->
+ j sp = Some(sp', fe.(fe_stack_data)) ->
Mem.free m sp 0 f.(Linear.fn_stacksize) = Some m1 ->
exists rs1, exists m1',
load_stack m' (Vptr sp' Int.zero) Tint tf.(fn_link_ofs) = Some pa
@@ -1826,268 +1284,138 @@ Lemma function_epilogue_correct:
E0 (State cs fb (Vptr sp' Int.zero) k rs1 m')
/\ agree_regs j (return_regs ls0 ls) rs1
/\ agree_callee_save (return_regs ls0 ls) ls0
- /\ Mem.inject j m1 m1'.
-Proof.
- intros.
- (* can free *)
- destruct (Mem.range_perm_free m' sp' 0 (fn_stacksize tf)) as [m1' FREE].
- rewrite unfold_transf_function; unfold fn_stacksize. red; intros.
- assert (EITHER: fe_stack_data fe <= ofs < fe_stack_data fe + Linear.fn_stacksize f
- \/ (ofs < fe_stack_data fe \/ fe_stack_data fe + Linear.fn_stacksize f <= ofs))
- by omega.
- destruct EITHER.
- replace ofs with ((ofs - fe_stack_data fe) + fe_stack_data fe) by omega.
- eapply Mem.perm_inject with (f := j). eapply agree_inj; eauto. eauto.
- eapply Mem.free_range_perm; eauto. omega.
- eapply agree_perm; eauto.
- (* inject after free *)
- assert (INJ1: Mem.inject j m1 m1').
- eapply Mem.free_inject with (l := (sp, 0, f.(Linear.fn_stacksize)) :: nil); eauto.
- simpl. rewrite H2. auto.
- intros. exploit agree_inj_unique; eauto. intros [P Q]; subst b1 delta.
- exists 0; exists (Linear.fn_stacksize f); split. auto with coqlib.
- eapply agree_bounds. eauto. eapply Mem.perm_max. eauto.
- (* can execute epilogue *)
- exploit restore_callee_save_correct; eauto.
- instantiate (1 := rs). red; intros.
- rewrite <- (agree_unused_reg _ _ _ _ _ _ _ _ _ H0). auto. auto.
- intros [rs1 [A [B C]]].
- (* conclusions *)
- exists rs1; exists m1'.
- split. rewrite unfold_transf_function; unfold fn_link_ofs.
- eapply index_contains_load_stack with (idx := FI_link); eauto with stacking.
- split. rewrite unfold_transf_function; unfold fn_retaddr_ofs.
- eapply index_contains_load_stack with (idx := FI_retaddr); eauto with stacking.
- split. auto.
- split. eexact A.
- split. red; intros. unfold return_regs.
- generalize (register_classification r) (int_callee_save_not_destroyed r) (float_callee_save_not_destroyed r); intros.
- destruct (in_dec mreg_eq r destroyed_at_call).
- rewrite C; auto.
- apply B. intuition.
- split. apply agree_callee_save_return_regs.
- auto.
+ /\ m1' |= minjection j m1 ** P.
+Proof.
+ intros until fb; intros SEP AGR AGL INJ FREE.
+ (* Can free *)
+ exploit free_parallel_rule.
+ rewrite <- sep_assoc. eapply mconj_proj2. eexact SEP.
+ eexact FREE.
+ eexact INJ.
+ auto. rewrite Z.max_comm; reflexivity.
+ intros (m1' & FREE' & SEP').
+ (* Reloading the callee-save registers *)
+ exploit restore_callee_save_correct.
+ eexact SEP.
+ instantiate (1 := rs).
+ red; intros. destruct AGL. rewrite <- agree_unused_reg0 by auto. apply AGR.
+ intros (rs' & LOAD_CS & CS & NCS).
+ (* Reloading the back link and return address *)
+ unfold frame_contents in SEP; apply mconj_proj1 in SEP.
+ unfold frame_contents_1 in SEP; rewrite ! sep_assoc in SEP.
+ exploit (hasvalue_get_stack Tint). eapply sep_pick3; eexact SEP. intros LOAD_LINK.
+ exploit (hasvalue_get_stack Tint). eapply sep_pick4; eexact SEP. intros LOAD_RETADDR.
+ clear SEP.
+ (* Conclusions *)
+ rewrite unfold_transf_function; simpl.
+ exists rs', m1'.
+ split. assumption.
+ split. assumption.
+ split. assumption.
+ split. eassumption.
+ split. red; unfold return_regs; intros.
+ destruct (is_callee_save r) eqn:C.
+ apply CS; auto.
+ rewrite NCS by auto. apply AGR.
+ split. red; unfold return_regs; intros.
+ destruct l; auto. rewrite H; auto.
+ assumption.
Qed.
End FRAME_PROPERTIES.
-(** * Call stack invariant *)
+(** * Call stack invariants *)
-Inductive match_globalenvs (j: meminj) (bound: block) : Prop :=
- | match_globalenvs_intro
- (DOMAIN: forall b, Plt b bound -> j b = Some(b, 0))
- (IMAGE: forall b1 b2 delta, j b1 = Some(b2, delta) -> Plt b2 bound -> b1 = b2)
- (SYMBOLS: forall id b, Genv.find_symbol ge id = Some b -> Plt b bound)
- (FUNCTIONS: forall b fd, Genv.find_funct_ptr ge b = Some fd -> Plt b bound)
- (VARINFOS: forall b gv, Genv.find_var_info ge b = Some gv -> Plt b bound).
+(** This is the memory assertion that captures the contents of the stack frames
+ mentioned in the call stacks. *)
+
+Fixpoint stack_contents (j: meminj) (cs: list Linear.stackframe) (cs': list Mach.stackframe) : massert :=
+ match cs, cs' with
+ | nil, nil => pure True
+ | Linear.Stackframe f _ ls c :: cs, Mach.Stackframe fb (Vptr sp' _) ra c' :: cs' =>
+ frame_contents f j sp' ls (parent_locset cs) (parent_sp cs') (parent_ra cs')
+ ** stack_contents j cs cs'
+ | _, _ => pure False
+ end.
-Inductive match_stacks (j: meminj) (m m': mem):
- list Linear.stackframe -> list stackframe -> signature -> block -> block -> Prop :=
- | match_stacks_empty: forall sg hi bound bound',
- Ple hi bound -> Ple hi bound' -> match_globalenvs j hi ->
+(** [match_stacks] captures additional properties (not related to memory)
+ of the Linear and Mach call stacks. *)
+
+Inductive match_stacks (j: meminj):
+ list Linear.stackframe -> list stackframe -> signature -> Prop :=
+ | match_stacks_empty: forall sg,
tailcall_possible sg ->
- match_stacks j m m' nil nil sg bound bound'
- | match_stacks_cons: forall f sp ls c cs fb sp' ra c' cs' sg bound bound' trf
+ match_stacks j nil nil sg
+ | match_stacks_cons: forall f sp ls c cs fb sp' ra c' cs' sg trf
(TAIL: is_tail c (Linear.fn_code f))
(FINDF: Genv.find_funct_ptr tge fb = Some (Internal trf))
(TRF: transf_function f = OK trf)
(TRC: transl_code (make_env (function_bounds f)) c = c')
+ (INJ: j sp = Some(sp', (fe_stack_data (make_env (function_bounds f)))))
(TY_RA: Val.has_type ra Tint)
- (FRM: agree_frame f j ls (parent_locset cs) m sp m' sp' (parent_sp cs') (parent_ra cs'))
+ (AGL: agree_locs f ls (parent_locset cs))
(ARGS: forall ofs ty,
In (S Outgoing ofs ty) (loc_arguments sg) ->
slot_within_bounds (function_bounds f) Outgoing ofs ty)
- (STK: match_stacks j m m' cs cs' (Linear.fn_sig f) sp sp')
- (BELOW: Plt sp bound)
- (BELOW': Plt sp' bound'),
- match_stacks j m m'
+ (STK: match_stacks j cs cs' (Linear.fn_sig f)),
+ match_stacks j
(Linear.Stackframe f (Vptr sp Int.zero) ls c :: cs)
(Stackframe fb (Vptr sp' Int.zero) ra c' :: cs')
- sg bound bound'.
+ sg.
-(** Invariance with respect to change of bounds. *)
+(** Invariance with respect to change of memory injection. *)
-Lemma match_stacks_change_bounds:
- forall j m1 m' cs cs' sg bound bound',
- match_stacks j m1 m' cs cs' sg bound bound' ->
- forall xbound xbound',
- Ple bound xbound -> Ple bound' xbound' ->
- match_stacks j m1 m' cs cs' sg xbound xbound'.
+Lemma stack_contents_change_meminj:
+ forall m j j', inject_incr j j' ->
+ forall cs cs' P,
+ m |= stack_contents j cs cs' ** P ->
+ m |= stack_contents j' cs cs' ** P.
Proof.
- induction 1; intros.
- apply match_stacks_empty with hi; auto. apply Ple_trans with bound; eauto. apply Ple_trans with bound'; eauto.
- econstructor; eauto. eapply Plt_le_trans; eauto. eapply Plt_le_trans; eauto.
+Local Opaque sepconj.
+ induction cs as [ | [] cs]; destruct cs' as [ | [] cs']; simpl; intros; auto.
+ destruct sp0; auto.
+ rewrite sep_assoc in *.
+ apply frame_contents_incr with (j := j); auto.
+ rewrite sep_swap. apply IHcs. rewrite sep_swap. assumption.
Qed.
-(** Invariance with respect to change of [m]. *)
-
-Lemma match_stacks_change_linear_mem:
- forall j m1 m2 m' cs cs' sg bound bound',
- match_stacks j m1 m' cs cs' sg bound bound' ->
- (forall b, Plt b bound -> Mem.valid_block m1 b -> Mem.valid_block m2 b) ->
- (forall b ofs p, Plt b bound -> Mem.perm m2 b ofs Max p -> Mem.perm m1 b ofs Max p) ->
- match_stacks j m2 m' cs cs' sg bound bound'.
-Proof.
- induction 1; intros.
- econstructor; eauto.
- econstructor; eauto.
- eapply agree_frame_invariant; eauto.
- apply IHmatch_stacks.
- intros. apply H0; auto. apply Plt_trans with sp; auto.
- intros. apply H1. apply Plt_trans with sp; auto. auto.
-Qed.
-
-(** Invariance with respect to change of [m']. *)
-
-Lemma match_stacks_change_mach_mem:
- forall j m m1' m2' cs cs' sg bound bound',
- match_stacks j m m1' cs cs' sg bound bound' ->
- (forall b, Plt b bound' -> Mem.valid_block m1' b -> Mem.valid_block m2' b) ->
- (forall b ofs k p, Plt b bound' -> Mem.perm m1' b ofs k p -> Mem.perm m2' b ofs k p) ->
- (forall chunk b ofs v, Plt b bound' -> Mem.load chunk m1' b ofs = Some v -> Mem.load chunk m2' b ofs = Some v) ->
- match_stacks j m m2' cs cs' sg bound bound'.
-Proof.
- induction 1; intros.
- econstructor; eauto.
- econstructor; eauto.
- eapply agree_frame_invariant; eauto.
- apply IHmatch_stacks.
- intros; apply H0; auto. apply Plt_trans with sp'; auto.
- intros; apply H1; auto. apply Plt_trans with sp'; auto.
- intros; apply H2; auto. apply Plt_trans with sp'; auto.
-Qed.
-
-(** A variant of the latter, for use with external calls *)
-
-Lemma match_stacks_change_mem_extcall:
- forall j m1 m2 m1' m2' cs cs' sg bound bound',
- match_stacks j m1 m1' cs cs' sg bound bound' ->
- (forall b, Plt b bound -> Mem.valid_block m1 b -> Mem.valid_block m2 b) ->
- (forall b ofs p, Plt b bound -> Mem.perm m2 b ofs Max p -> Mem.perm m1 b ofs Max p) ->
- (forall b, Plt b bound' -> Mem.valid_block m1' b -> Mem.valid_block m2' b) ->
- Mem.unchanged_on (loc_out_of_reach j m1) m1' m2' ->
- match_stacks j m2 m2' cs cs' sg bound bound'.
-Proof.
- induction 1; intros.
- econstructor; eauto.
- econstructor; eauto.
- eapply agree_frame_extcall_invariant; eauto.
- apply IHmatch_stacks.
- intros; apply H0; auto. apply Plt_trans with sp; auto.
- intros; apply H1. apply Plt_trans with sp; auto. auto.
- intros; apply H2; auto. apply Plt_trans with sp'; auto.
- auto.
-Qed.
-
-(** Invariance with respect to change of [j]. *)
-
Lemma match_stacks_change_meminj:
- forall j j' m m' m1 m1',
- inject_incr j j' ->
- inject_separated j j' m1 m1' ->
- forall cs cs' sg bound bound',
- match_stacks j m m' cs cs' sg bound bound' ->
- Ple bound' (Mem.nextblock m1') ->
- match_stacks j' m m' cs cs' sg bound bound'.
-Proof.
- induction 3; intros.
- apply match_stacks_empty with hi; auto.
- inv H3. constructor; auto.
- intros. red in H0. case_eq (j b1).
- intros [b' delta'] EQ. rewrite (H _ _ _ EQ) in H3. inv H3. eauto.
- intros EQ. exploit H0; eauto. intros [A B]. elim B. red.
- apply Plt_le_trans with hi. auto. apply Ple_trans with bound'; auto.
- econstructor; eauto.
- eapply agree_frame_inject_incr; eauto. red. eapply Plt_le_trans; eauto.
- apply IHmatch_stacks. apply Ple_trans with bound'; auto. apply Plt_Ple; auto.
-Qed.
-
-(** Preservation by parallel stores in Linear and Mach. *)
-
-Lemma match_stacks_parallel_stores:
- forall j m m' chunk addr addr' v v' m1 m1',
- Mem.inject j m m' ->
- Val.inject j addr addr' ->
- Mem.storev chunk m addr v = Some m1 ->
- Mem.storev chunk m' addr' v' = Some m1' ->
- forall cs cs' sg bound bound',
- match_stacks j m m' cs cs' sg bound bound' ->
- match_stacks j m1 m1' cs cs' sg bound bound'.
+ forall j j', inject_incr j j' ->
+ forall cs cs' sg,
+ match_stacks j cs cs' sg ->
+ match_stacks j' cs cs' sg.
Proof.
- intros until m1'. intros MINJ VINJ STORE1 STORE2.
- induction 1.
- econstructor; eauto.
- econstructor; eauto.
- eapply agree_frame_parallel_stores; eauto.
+ induction 2; intros.
+- constructor; auto.
+- econstructor; eauto.
Qed.
-(** Invariance by external calls. *)
-
-Lemma match_stack_change_extcall:
- forall ec args m1 res t m2 args' m1' res' t' m2' j j',
- external_call ec ge args m1 t res m2 ->
- external_call ec ge args' m1' t' res' m2' ->
- inject_incr j j' ->
- inject_separated j j' m1 m1' ->
- Mem.unchanged_on (loc_out_of_reach j m1) m1' m2' ->
- forall cs cs' sg bound bound',
- match_stacks j m1 m1' cs cs' sg bound bound' ->
- Ple bound (Mem.nextblock m1) -> Ple bound' (Mem.nextblock m1') ->
- match_stacks j' m2 m2' cs cs' sg bound bound'.
-Proof.
- intros.
- eapply match_stacks_change_meminj; eauto.
- eapply match_stacks_change_mem_extcall; eauto.
- intros; eapply external_call_valid_block; eauto.
- intros; eapply external_call_max_perm; eauto. red. eapply Plt_le_trans; eauto.
- intros; eapply external_call_valid_block; eauto.
-Qed.
-
-(** Invariance with respect to change of signature *)
+(** Invariance with respect to change of signature. *)
Lemma match_stacks_change_sig:
- forall sg1 j m m' cs cs' sg bound bound',
- match_stacks j m m' cs cs' sg bound bound' ->
+ forall sg1 j cs cs' sg,
+ match_stacks j cs cs' sg ->
tailcall_possible sg1 ->
- match_stacks j m m' cs cs' sg1 bound bound'.
+ match_stacks j cs cs' sg1.
Proof.
induction 1; intros.
econstructor; eauto.
econstructor; eauto. intros. elim (H0 _ H1).
Qed.
-(** [match_stacks] implies [match_globalenvs], which implies [meminj_preserves_globals]. *)
-
-Lemma match_stacks_globalenvs:
- forall j m m' cs cs' sg bound bound',
- match_stacks j m m' cs cs' sg bound bound' ->
- exists hi, match_globalenvs j hi.
-Proof.
- induction 1. exists hi; auto. auto.
-Qed.
-
-Lemma match_stacks_preserves_globals:
- forall j m m' cs cs' sg bound bound',
- match_stacks j m m' cs cs' sg bound bound' ->
- meminj_preserves_globals ge j.
-Proof.
- intros. exploit match_stacks_globalenvs; eauto. intros [hi MG]. inv MG.
- split. eauto. split. eauto. intros. symmetry. eauto.
-Qed.
-
(** Typing properties of [match_stacks]. *)
Lemma match_stacks_type_sp:
- forall j m m' cs cs' sg bound bound',
- match_stacks j m m' cs cs' sg bound bound' ->
+ forall j cs cs' sg,
+ match_stacks j cs cs' sg ->
Val.has_type (parent_sp cs') Tint.
Proof.
induction 1; simpl; auto.
Qed.
Lemma match_stacks_type_retaddr:
- forall j m m' cs cs' sg bound bound',
- match_stacks j m m' cs cs' sg bound bound' ->
+ forall j cs cs' sg,
+ match_stacks j cs cs' sg ->
Val.has_type (parent_ra cs') Tint.
Proof.
induction 1; simpl; auto.
@@ -2099,41 +1427,18 @@ Qed.
Section LABELS.
-Remark find_label_fold_right:
- forall (A: Type) (fn: A -> Mach.code -> Mach.code) lbl,
- (forall x k, Mach.find_label lbl (fn x k) = Mach.find_label lbl k) -> forall (args: list A) k,
- Mach.find_label lbl (List.fold_right fn k args) = Mach.find_label lbl k.
-Proof.
- induction args; simpl. auto.
- intros. rewrite H. auto.
-Qed.
-
Remark find_label_save_callee_save:
- forall fe lbl k,
- Mach.find_label lbl (save_callee_save fe k) = Mach.find_label lbl k.
+ forall lbl l ofs k,
+ Mach.find_label lbl (save_callee_save_rec l ofs k) = Mach.find_label lbl k.
Proof.
- intros. unfold save_callee_save, save_callee_save_int, save_callee_save_float, save_callee_save_regs.
- repeat rewrite find_label_fold_right. reflexivity.
- intros. unfold save_callee_save_reg.
- case (zlt (index_float_callee_save x) (fe_num_float_callee_save fe));
- intro; reflexivity.
- intros. unfold save_callee_save_reg.
- case (zlt (index_int_callee_save x) (fe_num_int_callee_save fe));
- intro; reflexivity.
+ induction l; simpl; auto.
Qed.
Remark find_label_restore_callee_save:
- forall fe lbl k,
- Mach.find_label lbl (restore_callee_save fe k) = Mach.find_label lbl k.
+ forall lbl l ofs k,
+ Mach.find_label lbl (restore_callee_save_rec l ofs k) = Mach.find_label lbl k.
Proof.
- intros. unfold restore_callee_save, restore_callee_save_int, restore_callee_save_float, restore_callee_save_regs.
- repeat rewrite find_label_fold_right. reflexivity.
- intros. unfold restore_callee_save_reg.
- case (zlt (index_float_callee_save x) (fe_num_float_callee_save fe));
- intro; reflexivity.
- intros. unfold restore_callee_save_reg.
- case (zlt (index_int_callee_save x) (fe_num_int_callee_save fe));
- intro; reflexivity.
+ induction l; simpl; auto.
Qed.
Lemma transl_code_eq:
@@ -2148,14 +1453,14 @@ Lemma find_label_transl_code:
option_map (transl_code fe) (Linear.find_label lbl c).
Proof.
induction c; simpl; intros.
- auto.
- rewrite transl_code_eq.
+- auto.
+- rewrite transl_code_eq.
destruct a; unfold transl_instr; auto.
destruct s; simpl; auto.
destruct s; simpl; auto.
- rewrite find_label_restore_callee_save. auto.
- simpl. case (peq lbl l); intro. reflexivity. auto.
- rewrite find_label_restore_callee_save. auto.
+ unfold restore_callee_save. rewrite find_label_restore_callee_save. auto.
+ simpl. destruct (peq lbl l). reflexivity. auto.
+ unfold restore_callee_save. rewrite find_label_restore_callee_save. auto.
Qed.
Lemma transl_find_label:
@@ -2166,7 +1471,7 @@ Lemma transl_find_label:
Some (transl_code (make_env (function_bounds f)) c).
Proof.
intros. rewrite (unfold_transf_function _ _ H). simpl.
- unfold transl_body. rewrite find_label_save_callee_save.
+ unfold transl_body. unfold save_callee_save. rewrite find_label_save_callee_save.
rewrite find_label_transl_code. rewrite H0. reflexivity.
Qed.
@@ -2187,38 +1492,20 @@ Qed.
(** Code tail property for translations *)
-Lemma is_tail_save_callee_save_regs:
- forall bound number mkindex ty fe csl k,
- is_tail k (save_callee_save_regs bound number mkindex ty fe csl k).
-Proof.
- induction csl; intros; simpl. auto with coqlib.
- unfold save_callee_save_reg. destruct (zlt (number a) (bound fe)).
- constructor; auto. auto.
-Qed.
-
Lemma is_tail_save_callee_save:
- forall fe k,
- is_tail k (save_callee_save fe k).
-Proof.
- intros. unfold save_callee_save, save_callee_save_int, save_callee_save_float.
- eapply is_tail_trans; apply is_tail_save_callee_save_regs.
-Qed.
-
-Lemma is_tail_restore_callee_save_regs:
- forall bound number mkindex ty fe csl k,
- is_tail k (restore_callee_save_regs bound number mkindex ty fe csl k).
+ forall l ofs k,
+ is_tail k (save_callee_save_rec l ofs k).
Proof.
- induction csl; intros; simpl. auto with coqlib.
- unfold restore_callee_save_reg. destruct (zlt (number a) (bound fe)).
- constructor; auto. auto.
+ induction l; intros; simpl. auto with coqlib.
+ constructor; auto.
Qed.
Lemma is_tail_restore_callee_save:
- forall fe k,
- is_tail k (restore_callee_save fe k).
+ forall l ofs k,
+ is_tail k (restore_callee_save_rec l ofs k).
Proof.
- intros. unfold restore_callee_save, restore_callee_save_int, restore_callee_save_float.
- eapply is_tail_trans; apply is_tail_restore_callee_save_regs.
+ induction l; intros; simpl. auto with coqlib.
+ constructor; auto.
Qed.
Lemma is_tail_transl_instr:
@@ -2228,8 +1515,8 @@ Proof.
intros. destruct i; unfold transl_instr; auto with coqlib.
destruct s; auto with coqlib.
destruct s; auto with coqlib.
- eapply is_tail_trans. 2: apply is_tail_restore_callee_save. auto with coqlib.
- eapply is_tail_trans. 2: apply is_tail_restore_callee_save. auto with coqlib.
+ unfold restore_callee_save. eapply is_tail_trans. 2: apply is_tail_restore_callee_save. auto with coqlib.
+ unfold restore_callee_save. eapply is_tail_trans. 2: apply is_tail_restore_callee_save. auto with coqlib.
Qed.
Lemma is_tail_transl_code:
@@ -2247,7 +1534,8 @@ Lemma is_tail_transf_function:
is_tail (transl_code (make_env (function_bounds f)) c) (fn_code tf).
Proof.
intros. rewrite (unfold_transf_function _ _ H). simpl.
- unfold transl_body. eapply is_tail_trans. 2: apply is_tail_save_callee_save.
+ unfold transl_body, save_callee_save.
+ eapply is_tail_trans. 2: apply is_tail_save_callee_save.
apply is_tail_transl_code; auto.
Qed.
@@ -2287,25 +1575,24 @@ Proof.
Qed.
Lemma find_function_translated:
- forall j ls rs m m' cs cs' sg bound bound' ros f,
+ forall j ls rs m ros f,
agree_regs j ls rs ->
- match_stacks j m m' cs cs' sg bound bound' ->
+ m |= globalenv_inject ge j ->
Linear.find_function ge ros ls = Some f ->
exists bf, exists tf,
find_function_ptr tge ros rs = Some bf
/\ Genv.find_funct_ptr tge bf = Some tf
/\ transf_fundef f = OK tf.
Proof.
- intros until f; intros AG MS FF.
- exploit match_stacks_globalenvs; eauto. intros [hi MG].
+ intros until f; intros AG [bound [_ []]] FF.
destruct ros; simpl in FF.
- exploit Genv.find_funct_inv; eauto. intros [b EQ]. rewrite EQ in FF.
+- exploit Genv.find_funct_inv; eauto. intros [b EQ]. rewrite EQ in FF.
rewrite Genv.find_funct_find_funct_ptr in FF.
exploit function_ptr_translated; eauto. intros [tf [A B]].
exists b; exists tf; split; auto. simpl.
generalize (AG m0). rewrite EQ. intro INJ. inv INJ.
- inv MG. rewrite DOMAIN in H2. inv H2. simpl. auto. eapply FUNCTIONS; eauto.
- destruct (Genv.find_symbol ge i) as [b|] eqn:?; try discriminate.
+ rewrite DOMAIN in H2. inv H2. simpl. auto. eapply FUNCTIONS; eauto.
+- destruct (Genv.find_symbol ge i) as [b|] eqn:?; try discriminate.
exploit function_ptr_translated; eauto. intros [tf [A B]].
exists b; exists tf; split; auto. simpl.
rewrite symbols_preserved. auto.
@@ -2316,16 +1603,17 @@ Qed.
Section EXTERNAL_ARGUMENTS.
Variable j: meminj.
-Variables m m': mem.
Variable cs: list Linear.stackframe.
Variable cs': list stackframe.
Variable sg: signature.
Variables bound bound': block.
-Hypothesis MS: match_stacks j m m' cs cs' sg bound bound'.
+Hypothesis MS: match_stacks j cs cs' sg.
Variable ls: locset.
Variable rs: regset.
Hypothesis AGR: agree_regs j ls rs.
Hypothesis AGCS: agree_callee_save ls (parent_locset cs).
+Variable m': mem.
+Hypothesis SEP: m' |= stack_contents j cs cs'.
Lemma transl_external_argument:
forall l,
@@ -2333,24 +1621,20 @@ Lemma transl_external_argument:
exists v, extcall_arg rs m' (parent_sp cs') l v /\ Val.inject j (ls l) v.
Proof.
intros.
- assert (loc_argument_acceptable l). apply loc_arguments_acceptable with sg; auto.
+ assert (loc_argument_acceptable l) by (apply loc_arguments_acceptable with sg; auto).
destruct l; red in H0.
- exists (rs r); split. constructor. auto.
- destruct sl; try contradiction.
+- exists (rs r); split. constructor. auto.
+- destruct sl; try contradiction.
inv MS.
- elim (H4 _ H).
- unfold parent_sp.
++ elim (H1 _ H).
++ simpl in SEP. unfold parent_sp.
assert (slot_valid f Outgoing pos ty = true).
- exploit loc_arguments_acceptable; eauto. intros [A B].
- unfold slot_valid. unfold proj_sumbool. rewrite zle_true by omega.
- destruct ty; auto; congruence.
- assert (slot_within_bounds (function_bounds f) Outgoing pos ty).
- eauto.
- exploit agree_outgoing; eauto. intros [v [A B]].
+ { destruct H0. unfold slot_valid, proj_sumbool.
+ rewrite zle_true by omega. rewrite pred_dec_true by auto. reflexivity. }
+ assert (slot_within_bounds (function_bounds f) Outgoing pos ty) by eauto.
+ exploit frame_get_outgoing; eauto. intros (v & A & B).
exists v; split.
- constructor.
- eapply index_contains_load_stack with (idx := FI_arg pos ty); eauto.
- red in AGCS. rewrite AGCS; auto.
+ constructor. exact A. red in AGCS. rewrite AGCS; auto.
Qed.
Lemma transl_external_arguments_rec:
@@ -2393,10 +1677,9 @@ Variables ls ls0: locset.
Variable rs: regset.
Variables sp sp': block.
Variables parent retaddr: val.
+Hypothesis INJ: j sp = Some(sp', fe.(fe_stack_data)).
Hypothesis AGR: agree_regs j ls rs.
-Hypothesis AGF: agree_frame f j ls ls0 m sp m' sp' parent retaddr.
-Hypothesis MINJ: Mem.inject j m m'.
-Hypothesis GINJ: meminj_preserves_globals ge j.
+Hypothesis SEP: m' |= frame_contents f j sp' ls ls0 parent retaddr ** minjection j m ** globalenv_inject ge j.
Lemma transl_builtin_arg_correct:
forall a v,
@@ -2407,35 +1690,33 @@ Lemma transl_builtin_arg_correct:
eval_builtin_arg ge rs (Vptr sp' Int.zero) m' (transl_builtin_arg fe a) v'
/\ Val.inject j v v'.
Proof.
-Local Opaque fe offset_of_index.
+ assert (SYMB: forall id ofs, Val.inject j (Senv.symbol_address ge id ofs) (Senv.symbol_address ge id ofs)).
+ { assert (G: meminj_preserves_globals ge j).
+ { eapply globalenv_inject_preserves_globals. eapply sep_proj2. eapply sep_proj2. eexact SEP. }
+ intros; unfold Senv.symbol_address; simpl; unfold Genv.symbol_address.
+ destruct (Genv.find_symbol ge id) eqn:FS; auto.
+ destruct G. econstructor. eauto. rewrite Int.add_zero; auto. }
+Local Opaque fe.
induction 1; simpl; intros VALID BOUNDS.
- assert (loc_valid f x = true) by auto.
destruct x as [r | [] ofs ty]; try discriminate.
+ exists (rs r); auto with barg.
- + exploit agree_locals; eauto. intros [v [A B]]. inv A.
- exists v; split; auto. constructor. simpl. rewrite Int.add_zero_l.
-Local Transparent fe.
- unfold fe, b. erewrite offset_of_index_no_overflow by eauto. exact H1.
+ + exploit frame_get_local; eauto. intros (v & A & B).
+ exists v; split; auto. constructor; auto.
- econstructor; eauto with barg.
- econstructor; eauto with barg.
- econstructor; eauto with barg.
- econstructor; eauto with barg.
-- simpl in H. exploit Mem.load_inject; eauto. eapply agree_inj; eauto.
- intros (v' & A & B). exists v'; split; auto. constructor.
- unfold Mem.loadv, Val.add. rewrite <- Int.add_assoc.
- unfold fe, b; erewrite shifted_stack_offset_no_overflow; eauto.
- eapply agree_bounds; eauto. eapply Mem.valid_access_perm. eapply Mem.load_valid_access; eauto.
-- econstructor; split; eauto with barg.
- unfold Val.add. rewrite ! Int.add_zero_l. econstructor. eapply agree_inj; eauto. auto.
-- assert (Val.inject j (Senv.symbol_address ge id ofs) (Senv.symbol_address ge id ofs)).
- { unfold Senv.symbol_address; simpl; unfold Genv.symbol_address.
- destruct (Genv.find_symbol ge id) eqn:FS; auto.
- econstructor. eapply (proj1 GINJ); eauto. rewrite Int.add_zero; auto. }
- exploit Mem.loadv_inject; eauto. intros (v' & A & B). exists v'; auto with barg.
+- set (ofs' := Int.add ofs (Int.repr (fe_stack_data fe))).
+ apply sep_proj2 in SEP. apply sep_proj1 in SEP. exploit loadv_parallel_rule; eauto.
+ instantiate (1 := Val.add (Vptr sp' Int.zero) (Vint ofs')).
+ simpl. rewrite ! Int.add_zero_l. econstructor; eauto.
+ intros (v' & A & B). exists v'; split; auto. constructor; auto.
- econstructor; split; eauto with barg.
- unfold Senv.symbol_address; simpl; unfold Genv.symbol_address.
- destruct (Genv.find_symbol ge id) eqn:FS; auto.
- econstructor. eapply (proj1 GINJ); eauto. rewrite Int.add_zero; auto.
+ unfold Val.add. rewrite ! Int.add_zero_l. econstructor; eauto.
+- apply sep_proj2 in SEP. apply sep_proj1 in SEP. exploit loadv_parallel_rule; eauto.
+ intros (v' & A & B). exists v'; auto with barg.
+- econstructor; split; eauto with barg.
- destruct IHeval_builtin_arg1 as (v1 & A1 & B1); auto using in_or_app.
destruct IHeval_builtin_arg2 as (v2 & A2 & B2); auto using in_or_app.
exists (Val.longofwords v1 v2); split; auto with barg.
@@ -2472,44 +1753,56 @@ End BUILTIN_ARGUMENTS.
>>
Matching between source and target states is defined by [match_states]
below. It implies:
+- Satisfaction of the separation logic assertions that describe the contents
+ of memory. This is a separating conjunction of facts about:
+-- the current stack frame
+-- the frames in the call stack
+-- the injection from the Linear memory state into the Mach memory state
+-- the preservation of the global environment.
- Agreement between, on the Linear side, the location sets [ls]
and [parent_locset s] of the current function and its caller,
- and on the Mach side the register set [rs] and the contents of
- the memory area corresponding to the stack frame.
+ and on the Mach side the register set [rs].
- The Linear code [c] is a suffix of the code of the
function [f] being executed.
-- Memory injection between the Linear and the Mach memory states.
- Well-typedness of [f].
*)
Inductive match_states: Linear.state -> Mach.state -> Prop :=
| match_states_intro:
forall cs f sp c ls m cs' fb sp' rs m' j tf
- (MINJ: Mem.inject j m m')
- (STACKS: match_stacks j m m' cs cs' f.(Linear.fn_sig) sp sp')
+ (STACKS: match_stacks j cs cs' f.(Linear.fn_sig))
(TRANSL: transf_function f = OK tf)
(FIND: Genv.find_funct_ptr tge fb = Some (Internal tf))
(AGREGS: agree_regs j ls rs)
- (AGFRAME: agree_frame f j ls (parent_locset cs) m sp m' sp' (parent_sp cs') (parent_ra cs'))
- (TAIL: is_tail c (Linear.fn_code f)),
+ (AGLOCS: agree_locs f ls (parent_locset cs))
+ (INJSP: j sp = Some(sp', fe_stack_data (make_env (function_bounds f))))
+ (TAIL: is_tail c (Linear.fn_code f))
+ (SEP: m' |= frame_contents f j sp' ls (parent_locset cs) (parent_sp cs') (parent_ra cs')
+ ** stack_contents j cs cs'
+ ** minjection j m
+ ** globalenv_inject ge j),
match_states (Linear.State cs f (Vptr sp Int.zero) c ls m)
- (Mach.State cs' fb (Vptr sp' Int.zero) (transl_code (make_env (function_bounds f)) c) rs m')
+ (Mach.State cs' fb (Vptr sp' Int.zero) (transl_code (make_env (function_bounds f)) c) rs m')
| match_states_call:
forall cs f ls m cs' fb rs m' j tf
- (MINJ: Mem.inject j m m')
- (STACKS: match_stacks j m m' cs cs' (Linear.funsig f) (Mem.nextblock m) (Mem.nextblock m'))
+ (STACKS: match_stacks j cs cs' (Linear.funsig f))
(TRANSL: transf_fundef f = OK tf)
(FIND: Genv.find_funct_ptr tge fb = Some tf)
(AGREGS: agree_regs j ls rs)
- (AGLOCS: agree_callee_save ls (parent_locset cs)),
+ (AGLOCS: agree_callee_save ls (parent_locset cs))
+ (SEP: m' |= stack_contents j cs cs'
+ ** minjection j m
+ ** globalenv_inject ge j),
match_states (Linear.Callstate cs f ls m)
- (Mach.Callstate cs' fb rs m')
+ (Mach.Callstate cs' fb rs m')
| match_states_return:
forall cs ls m cs' rs m' j sg
- (MINJ: Mem.inject j m m')
- (STACKS: match_stacks j m m' cs cs' sg (Mem.nextblock m) (Mem.nextblock m'))
+ (STACKS: match_stacks j cs cs' sg)
(AGREGS: agree_regs j ls rs)
- (AGLOCS: agree_callee_save ls (parent_locset cs)),
+ (AGLOCS: agree_callee_save ls (parent_locset cs))
+ (SEP: m' |= stack_contents j cs cs'
+ ** minjection j m
+ ** globalenv_inject ge j),
match_states (Linear.Returnstate cs ls m)
(Mach.Returnstate cs' rs m').
@@ -2518,13 +1811,6 @@ Theorem transf_step_correct:
forall (WTS: wt_state s1) s1' (MS: match_states s1 s1'),
exists s2', plus step tge s1' t s2' /\ match_states s2 s2'.
Proof.
-(*
- assert (USEWTF: forall f i c,
- wt_function f = true -> is_tail (i :: c) (Linear.fn_code f) ->
- wt_instr f i = true).
- intros. unfold wt_function, wt_code in H. rewrite forallb_forall in H.
- apply H. eapply is_tail_in; eauto.
-*)
induction 1; intros;
try inv MS;
try rewrite transl_code_eq;
@@ -2533,98 +1819,78 @@ Proof.
unfold transl_instr.
- (* Lgetstack *)
- destruct BOUND.
+ destruct BOUND as [BOUND1 BOUND2].
exploit wt_state_getstack; eauto. intros SV.
unfold destroyed_by_getstack; destruct sl.
+ (* Lgetstack, local *)
- exploit agree_locals; eauto. intros [v [A B]].
+ exploit frame_get_local; eauto. intros (v & A & B).
econstructor; split.
- apply plus_one. apply exec_Mgetstack.
- eapply index_contains_load_stack; eauto.
+ apply plus_one. apply exec_Mgetstack. exact A.
econstructor; eauto with coqlib.
apply agree_regs_set_reg; auto.
- apply agree_frame_set_reg; auto.
+ apply agree_locs_set_reg; auto.
+ (* Lgetstack, incoming *)
unfold slot_valid in SV. InvBooleans.
exploit incoming_slot_in_parameters; eauto. intros IN_ARGS.
inversion STACKS; clear STACKS.
- elim (H6 _ IN_ARGS).
- subst bound bound' s cs'.
- exploit agree_outgoing. eexact FRM. eapply ARGS; eauto.
- exploit loc_arguments_acceptable; eauto. intros [A B].
- unfold slot_valid, proj_sumbool. rewrite zle_true.
- destruct ty; reflexivity || congruence. omega.
- intros [v [A B]].
+ elim (H1 _ IN_ARGS).
+ subst s cs'.
+ exploit frame_get_outgoing.
+ apply sep_proj2 in SEP. simpl in SEP. rewrite sep_assoc in SEP. eexact SEP.
+ eapply ARGS; eauto.
+ eapply slot_outgoing_argument_valid; eauto.
+ intros (v & A & B).
econstructor; split.
- apply plus_one. eapply exec_Mgetparam; eauto.
+ apply plus_one. eapply exec_Mgetparam; eauto.
rewrite (unfold_transf_function _ _ TRANSL). unfold fn_link_ofs.
- eapply index_contains_load_stack with (idx := FI_link). eapply TRANSL. eapply agree_link; eauto.
- simpl parent_sp.
- change (offset_of_index (make_env (function_bounds f)) (FI_arg ofs ty))
- with (offset_of_index (make_env (function_bounds f0)) (FI_arg ofs ty)).
- eapply index_contains_load_stack with (idx := FI_arg ofs ty). eauto. eauto.
- exploit agree_incoming; eauto. intros EQ; simpl in EQ.
+ eapply frame_get_parent. eexact SEP.
econstructor; eauto with coqlib. econstructor; eauto.
- apply agree_regs_set_reg. apply agree_regs_set_reg. auto. auto. congruence.
- eapply agree_frame_set_reg; eauto. eapply agree_frame_set_reg; eauto.
- apply caller_save_reg_within_bounds.
- apply temp_for_parent_frame_caller_save.
+ apply agree_regs_set_reg. apply agree_regs_set_reg. auto. auto.
+ erewrite agree_incoming by eauto. exact B.
+ apply agree_locs_set_reg; auto. apply agree_locs_undef_locs; auto.
+ (* Lgetstack, outgoing *)
- exploit agree_outgoing; eauto. intros [v [A B]].
+ exploit frame_get_outgoing; eauto. intros (v & A & B).
econstructor; split.
- apply plus_one. apply exec_Mgetstack.
- eapply index_contains_load_stack; eauto.
+ apply plus_one. apply exec_Mgetstack. exact A.
econstructor; eauto with coqlib.
apply agree_regs_set_reg; auto.
- apply agree_frame_set_reg; auto.
+ apply agree_locs_set_reg; auto.
- (* Lsetstack *)
exploit wt_state_setstack; eauto. intros (SV & SW).
- set (idx := match sl with
- | Local => FI_local ofs ty
- | Incoming => FI_link (*dummy*)
- | Outgoing => FI_arg ofs ty
- end).
- assert (index_valid f idx).
- { unfold idx; destruct sl.
- apply index_local_valid; auto.
- red; auto.
- apply index_arg_valid; auto. }
- exploit store_index_succeeds; eauto. eapply agree_perm; eauto.
- instantiate (1 := rs0 src). intros [m1' STORE].
+ set (ofs' := match sl with
+ | Local => offset_local (make_env (function_bounds f)) ofs
+ | Incoming => 0 (* dummy *)
+ | Outgoing => offset_arg ofs
+ end).
+ eapply frame_undef_regs with (rl := destroyed_by_setstack ty) in SEP.
+ assert (A: exists m'',
+ store_stack m' (Vptr sp' Int.zero) ty (Int.repr ofs') (rs0 src) = Some m''
+ /\ m'' |= frame_contents f j sp' (Locmap.set (S sl ofs ty) (rs (R src))
+ (LTL.undef_regs (destroyed_by_setstack ty) rs))
+ (parent_locset s) (parent_sp cs') (parent_ra cs')
+ ** stack_contents j s cs' ** minjection j m ** globalenv_inject ge j).
+ { unfold ofs'; destruct sl; try discriminate.
+ eapply frame_set_local; eauto.
+ eapply frame_set_outgoing; eauto. }
+ clear SEP; destruct A as (m'' & STORE & SEP).
econstructor; split.
- apply plus_one. destruct sl; simpl in SW.
- econstructor. eapply store_stack_succeeds with (idx := idx); eauto. eauto.
- discriminate.
- econstructor. eapply store_stack_succeeds with (idx := idx); eauto. auto.
- econstructor.
- eapply Mem.store_outside_inject; eauto.
- intros. exploit agree_inj_unique; eauto. intros [EQ1 EQ2]; subst b' delta.
- rewrite size_type_chunk in H2.
- exploit offset_of_index_disj_stack_data_2; eauto.
- exploit agree_bounds. eauto. apply Mem.perm_cur_max. eauto.
- omega.
- apply match_stacks_change_mach_mem with m'; auto.
- eauto with mem. eauto with mem. intros. rewrite <- H1; eapply Mem.load_store_other; eauto. left; apply Plt_ne; auto.
- eauto. eauto.
- apply agree_regs_set_slot. apply agree_regs_undef_regs; auto.
- destruct sl.
- + eapply agree_frame_set_local. eapply agree_frame_undef_locs; eauto.
- apply destroyed_by_setstack_caller_save. auto. auto. auto.
- assumption.
- + simpl in SW; discriminate.
- + eapply agree_frame_set_outgoing. eapply agree_frame_undef_locs; eauto.
- apply destroyed_by_setstack_caller_save. auto. auto. auto.
- assumption.
- + eauto with coqlib.
+ apply plus_one. destruct sl; try discriminate.
+ econstructor. eexact STORE. eauto.
+ econstructor. eexact STORE. eauto.
+ econstructor. eauto. eauto. eauto.
+ apply agree_regs_set_slot. apply agree_regs_undef_regs. auto.
+ apply agree_locs_set_slot. apply agree_locs_undef_locs. auto. apply destroyed_by_setstack_caller_save. auto.
+ eauto. eauto with coqlib. eauto.
- (* Lop *)
assert (exists v',
eval_operation ge (Vptr sp' Int.zero) (transl_op (make_env (function_bounds f)) op) rs0##args m' = Some v'
/\ Val.inject j v v').
eapply eval_operation_inject; eauto.
- eapply match_stacks_preserves_globals; eauto.
- eapply agree_inj; eauto. eapply agree_reglist; eauto.
+ eapply globalenv_inject_preserves_globals. eapply sep_proj2. eapply sep_proj2. eapply sep_proj2. eexact SEP.
+ eapply agree_reglist; eauto.
+ apply sep_proj2 in SEP. apply sep_proj2 in SEP. apply sep_proj1 in SEP. exact SEP.
destruct H0 as [v' [A B]].
econstructor; split.
apply plus_one. econstructor.
@@ -2633,56 +1899,58 @@ Proof.
econstructor; eauto with coqlib.
apply agree_regs_set_reg; auto.
rewrite transl_destroyed_by_op. apply agree_regs_undef_regs; auto.
- apply agree_frame_set_reg; auto. apply agree_frame_undef_locs; auto.
- apply destroyed_by_op_caller_save.
+ apply agree_locs_set_reg; auto. apply agree_locs_undef_locs. auto. apply destroyed_by_op_caller_save.
+ apply frame_set_reg. apply frame_undef_regs. exact SEP.
- (* Lload *)
assert (exists a',
eval_addressing ge (Vptr sp' Int.zero) (transl_addr (make_env (function_bounds f)) addr) rs0##args = Some a'
/\ Val.inject j a a').
eapply eval_addressing_inject; eauto.
- eapply match_stacks_preserves_globals; eauto.
- eapply agree_inj; eauto. eapply agree_reglist; eauto.
+ eapply globalenv_inject_preserves_globals. eapply sep_proj2. eapply sep_proj2. eapply sep_proj2. eexact SEP.
+ eapply agree_reglist; eauto.
destruct H1 as [a' [A B]].
- exploit Mem.loadv_inject; eauto. intros [v' [C D]].
+ exploit loadv_parallel_rule.
+ apply sep_proj2 in SEP. apply sep_proj2 in SEP. apply sep_proj1 in SEP. eexact SEP.
+ eauto. eauto.
+ intros [v' [C D]].
econstructor; split.
apply plus_one. econstructor.
instantiate (1 := a'). rewrite <- A. apply eval_addressing_preserved. exact symbols_preserved.
eexact C. eauto.
econstructor; eauto with coqlib.
apply agree_regs_set_reg. rewrite transl_destroyed_by_load. apply agree_regs_undef_regs; auto. auto.
- apply agree_frame_set_reg. apply agree_frame_undef_locs; auto.
- apply destroyed_by_load_caller_save. auto.
+ apply agree_locs_set_reg. apply agree_locs_undef_locs. auto. apply destroyed_by_load_caller_save. auto.
- (* Lstore *)
assert (exists a',
eval_addressing ge (Vptr sp' Int.zero) (transl_addr (make_env (function_bounds f)) addr) rs0##args = Some a'
/\ Val.inject j a a').
eapply eval_addressing_inject; eauto.
- eapply match_stacks_preserves_globals; eauto.
- eapply agree_inj; eauto. eapply agree_reglist; eauto.
+ eapply globalenv_inject_preserves_globals. eapply sep_proj2. eapply sep_proj2. eapply sep_proj2. eexact SEP.
+ eapply agree_reglist; eauto.
destruct H1 as [a' [A B]].
- exploit Mem.storev_mapped_inject; eauto. intros [m1' [C D]].
+ rewrite sep_swap3 in SEP.
+ exploit storev_parallel_rule. eexact SEP. eauto. eauto. apply AGREGS.
+ clear SEP; intros (m1' & C & SEP).
+ rewrite sep_swap3 in SEP.
econstructor; split.
apply plus_one. econstructor.
instantiate (1 := a'). rewrite <- A. apply eval_addressing_preserved. exact symbols_preserved.
eexact C. eauto.
- econstructor. eauto.
- eapply match_stacks_parallel_stores. eexact MINJ. eexact B. eauto. eauto. auto.
- eauto. eauto.
- rewrite transl_destroyed_by_store.
- apply agree_regs_undef_regs; auto.
- apply agree_frame_undef_locs; auto.
- eapply agree_frame_parallel_stores; eauto.
- apply destroyed_by_store_caller_save.
- eauto with coqlib.
+ econstructor. eauto. eauto. eauto.
+ rewrite transl_destroyed_by_store. apply agree_regs_undef_regs; auto.
+ apply agree_locs_undef_locs. auto. apply destroyed_by_store_caller_save.
+ auto. eauto with coqlib.
+ eapply frame_undef_regs; eauto.
- (* Lcall *)
- exploit find_function_translated; eauto. intros [bf [tf' [A [B C]]]].
+ exploit find_function_translated; eauto.
+ eapply sep_proj2. eapply sep_proj2. eapply sep_proj2. eexact SEP.
+ intros [bf [tf' [A [B C]]]].
exploit is_tail_transf_function; eauto. intros IST.
rewrite transl_code_eq in IST. simpl in IST.
- exploit return_address_offset_exists. eexact IST.
- intros [ra D].
+ exploit return_address_offset_exists. eexact IST. intros [ra D].
econstructor; split.
apply plus_one. econstructor; eauto.
econstructor; eauto.
@@ -2691,54 +1959,45 @@ Proof.
intros; red.
apply Zle_trans with (size_arguments (Linear.funsig f')); auto.
apply loc_arguments_bounded; auto.
- eapply agree_valid_linear; eauto.
- eapply agree_valid_mach; eauto.
simpl; red; auto.
+ simpl. rewrite sep_assoc. exact SEP.
- (* Ltailcall *)
+ rewrite (sep_swap (stack_contents j s cs')) in SEP.
exploit function_epilogue_correct; eauto.
- intros [rs1 [m1' [P [Q [R [S [T [U V]]]]]]]].
- exploit find_function_translated; eauto. intros [bf [tf' [A [B C]]]].
+ clear SEP. intros (rs1 & m1' & P & Q & R & S & T & U & SEP).
+ rewrite sep_swap in SEP.
+ exploit find_function_translated; eauto.
+ eapply sep_proj2. eapply sep_proj2. eexact SEP.
+ intros [bf [tf' [A [B C]]]].
econstructor; split.
eapply plus_right. eexact S. econstructor; eauto. traceEq.
econstructor; eauto.
apply match_stacks_change_sig with (Linear.fn_sig f); auto.
- apply match_stacks_change_bounds with stk sp'.
- apply match_stacks_change_linear_mem with m.
- apply match_stacks_change_mach_mem with m'0.
- auto.
- eauto with mem. intros. eapply Mem.perm_free_1; eauto. left; apply Plt_ne; auto.
- intros. rewrite <- H1. eapply Mem.load_free; eauto. left; apply Plt_ne; auto.
- eauto with mem. intros. eapply Mem.perm_free_3; eauto.
- apply Plt_Ple. change (Mem.valid_block m' stk). eapply Mem.valid_block_free_1; eauto. eapply agree_valid_linear; eauto.
- apply Plt_Ple. change (Mem.valid_block m1' sp'). eapply Mem.valid_block_free_1; eauto. eapply agree_valid_mach; eauto.
apply zero_size_arguments_tailcall_possible. eapply wt_state_tailcall; eauto.
- (* Lbuiltin *)
destruct BOUND as [BND1 BND2].
- exploit transl_builtin_args_correct; eauto.
- eapply match_stacks_preserves_globals; eauto.
- rewrite <- forallb_forall. eapply wt_state_builtin; eauto.
+ exploit transl_builtin_args_correct.
+ eauto. eauto. rewrite sep_swap in SEP; apply sep_proj2 in SEP; eexact SEP.
+ eauto. rewrite <- forallb_forall. eapply wt_state_builtin; eauto.
+ exact BND2.
intros [vargs' [P Q]].
- exploit external_call_mem_inject; eauto.
- eapply match_stacks_preserves_globals; eauto.
- intros [j' [res' [m1' [A [B [C [D [E [F G]]]]]]]]].
+ rewrite <- sep_assoc, sep_comm, sep_assoc in SEP.
+ exploit external_call_parallel_rule; eauto.
+ clear SEP; intros (j' & res' & m1' & EC & RES & SEP & INCR & ISEP).
+ rewrite <- sep_assoc, sep_comm, sep_assoc in SEP.
econstructor; split.
apply plus_one. econstructor; eauto.
eapply eval_builtin_args_preserved with (ge1 := ge); eauto. exact symbols_preserved.
eapply external_call_symbols_preserved; eauto. apply senv_preserved.
- econstructor; eauto with coqlib.
- eapply match_stack_change_extcall; eauto.
- apply Plt_Ple. change (Mem.valid_block m sp0). eapply agree_valid_linear; eauto.
- apply Plt_Ple. change (Mem.valid_block m'0 sp'). eapply agree_valid_mach; eauto.
+ eapply match_states_intro with (j := j'); eauto with coqlib.
+ eapply match_stacks_change_meminj; eauto.
apply agree_regs_set_res; auto. apply agree_regs_undef_regs; auto. eapply agree_regs_inject_incr; eauto.
- eapply agree_frame_inject_incr; eauto.
- apply agree_frame_set_res; auto. apply agree_frame_undef_regs; auto.
- apply agree_frame_extcall_invariant with m m'0; auto.
- eapply external_call_valid_block; eauto.
- intros. eapply external_call_max_perm; eauto. eapply agree_valid_linear; eauto.
- eapply external_call_valid_block; eauto.
- eapply agree_valid_mach; eauto.
+ apply agree_locs_set_res; auto. apply agree_locs_undef_regs; auto.
+ apply frame_set_res. apply frame_undef_regs. apply frame_contents_incr with j; auto.
+ rewrite sep_swap2. apply stack_contents_change_meminj with j; auto. rewrite sep_swap2.
+ exact SEP.
- (* Llabel *)
econstructor; split.
@@ -2755,21 +2014,24 @@ Proof.
- (* Lcond, true *)
econstructor; split.
apply plus_one. eapply exec_Mcond_true; eauto.
- eapply eval_condition_inject; eauto. eapply agree_reglist; eauto.
+ eapply eval_condition_inject with (m1 := m). eapply agree_reglist; eauto. apply sep_pick3 in SEP; exact SEP. auto.
eapply transl_find_label; eauto.
- econstructor. eauto. eauto. eauto. eauto.
+ econstructor. eauto. eauto. eauto.
apply agree_regs_undef_regs; auto.
- apply agree_frame_undef_locs; auto. apply destroyed_by_cond_caller_save.
+ apply agree_locs_undef_locs. auto. apply destroyed_by_cond_caller_save.
+ auto.
eapply find_label_tail; eauto.
+ apply frame_undef_regs; auto.
- (* Lcond, false *)
econstructor; split.
apply plus_one. eapply exec_Mcond_false; eauto.
- eapply eval_condition_inject; eauto. eapply agree_reglist; eauto.
- econstructor. eauto. eauto. eauto. eauto.
+ eapply eval_condition_inject with (m1 := m). eapply agree_reglist; eauto. apply sep_pick3 in SEP; exact SEP. auto.
+ econstructor. eauto. eauto. eauto.
apply agree_regs_undef_regs; auto.
- apply agree_frame_undef_locs; auto. apply destroyed_by_cond_caller_save.
- eauto with coqlib.
+ apply agree_locs_undef_locs. auto. apply destroyed_by_cond_caller_save.
+ auto. eauto with coqlib.
+ apply frame_undef_regs; auto.
- (* Ljumptable *)
assert (rs0 arg = Vint n).
@@ -2777,78 +2039,67 @@ Proof.
econstructor; split.
apply plus_one; eapply exec_Mjumptable; eauto.
apply transl_find_label; eauto.
- econstructor. eauto. eauto. eauto. eauto.
+ econstructor. eauto. eauto. eauto.
apply agree_regs_undef_regs; auto.
- apply agree_frame_undef_locs; auto. apply destroyed_by_jumptable_caller_save.
- eapply find_label_tail; eauto.
+ apply agree_locs_undef_locs. auto. apply destroyed_by_jumptable_caller_save.
+ auto. eapply find_label_tail; eauto.
+ apply frame_undef_regs; auto.
- (* Lreturn *)
+ rewrite (sep_swap (stack_contents j s cs')) in SEP.
exploit function_epilogue_correct; eauto.
- intros [rs1 [m1' [P [Q [R [S [T [U V]]]]]]]].
+ intros (rs' & m1' & A & B & C & D & E & F & G).
econstructor; split.
- eapply plus_right. eexact S. econstructor; eauto.
- traceEq.
+ eapply plus_right. eexact D. econstructor; eauto. traceEq.
econstructor; eauto.
- apply match_stacks_change_bounds with stk sp'.
- apply match_stacks_change_linear_mem with m.
- apply match_stacks_change_mach_mem with m'0.
- eauto.
- eauto with mem. intros. eapply Mem.perm_free_1; eauto. left; apply Plt_ne; auto.
- intros. rewrite <- H1. eapply Mem.load_free; eauto. left; apply Plt_ne; auto.
- eauto with mem. intros. eapply Mem.perm_free_3; eauto.
- apply Plt_Ple. change (Mem.valid_block m' stk). eapply Mem.valid_block_free_1; eauto. eapply agree_valid_linear; eauto.
- apply Plt_Ple. change (Mem.valid_block m1' sp'). eapply Mem.valid_block_free_1; eauto. eapply agree_valid_mach; eauto.
+ rewrite sep_swap; exact G.
- (* internal function *)
revert TRANSL. unfold transf_fundef, transf_partial_fundef.
- caseEq (transf_function f); simpl; try congruence.
- intros tfn TRANSL EQ. inversion EQ; clear EQ; subst tf.
- exploit function_prologue_correct; eauto. eapply wt_callstate_wt_regs; eauto.
+ destruct (transf_function f) as [tfn|] eqn:TRANSL; simpl; try congruence.
+ intros EQ; inversion EQ; clear EQ; subst tf.
+ rewrite sep_comm, sep_assoc in SEP.
+ exploit function_prologue_correct; eauto.
+ red; intros; eapply wt_callstate_wt_regs; eauto.
eapply match_stacks_type_sp; eauto.
eapply match_stacks_type_retaddr; eauto.
- intros [j' [rs' [m2' [sp' [m3' [m4' [m5' [A [B [C [D [E [F [G [J [K L]]]]]]]]]]]]]]]].
+ clear SEP;
+ intros (j' & rs' & m2' & sp' & m3' & m4' & m5' & A & B & C & D & E & F & SEP & J & K).
+ rewrite (sep_comm (globalenv_inject ge j')) in SEP.
+ rewrite (sep_swap (minjection j' m')) in SEP.
econstructor; split.
eapply plus_left. econstructor; eauto.
rewrite (unfold_transf_function _ _ TRANSL). unfold fn_code. unfold transl_body.
eexact D. traceEq.
- generalize (Mem.alloc_result _ _ _ _ _ H). intro SP_EQ.
- generalize (Mem.alloc_result _ _ _ _ _ A). intro SP'_EQ.
- econstructor; eauto.
- apply match_stacks_change_mach_mem with m'0.
- apply match_stacks_change_linear_mem with m.
- rewrite SP_EQ; rewrite SP'_EQ.
- eapply match_stacks_change_meminj; eauto. apply Ple_refl.
- eauto with mem. intros. exploit Mem.perm_alloc_inv. eexact H. eauto.
- rewrite dec_eq_false; auto. apply Plt_ne; auto.
- intros. eapply stores_in_frame_valid; eauto with mem.
- intros. eapply stores_in_frame_perm; eauto with mem.
- intros. rewrite <- H1. transitivity (Mem.load chunk m2' b ofs). eapply stores_in_frame_contents; eauto.
- eapply Mem.load_alloc_unchanged; eauto. red. congruence.
- auto with coqlib.
+ eapply match_states_intro with (j := j'); eauto with coqlib.
+ eapply match_stacks_change_meminj; eauto.
+ rewrite sep_swap in SEP. rewrite sep_swap. eapply stack_contents_change_meminj; eauto.
- (* external function *)
simpl in TRANSL. inversion TRANSL; subst tf.
- exploit transl_external_arguments; eauto. intros [vl [ARGS VINJ]].
- exploit external_call_mem_inject'; eauto.
- eapply match_stacks_preserves_globals; eauto.
- intros [j' [res' [m1' [A [B [C [D [E [F G]]]]]]]]].
+ exploit transl_external_arguments; eauto. apply sep_proj1 in SEP; eauto. intros [vl [ARGS VINJ]].
+ rewrite sep_comm, sep_assoc in SEP.
+ inv H0.
+ exploit external_call_parallel_rule; eauto.
+ eapply decode_longs_inject; eauto.
+ intros (j' & res' & m1' & A & B & C & D & E).
econstructor; split.
apply plus_one. eapply exec_function_external; eauto.
- eapply external_call_symbols_preserved'; eauto. apply senv_preserved.
- econstructor; eauto.
- apply match_stacks_change_bounds with (Mem.nextblock m) (Mem.nextblock m'0).
- inv H0; inv A. eapply match_stack_change_extcall; eauto. apply Ple_refl. apply Ple_refl.
- eapply external_call_nextblock'; eauto.
- eapply external_call_nextblock'; eauto.
- apply agree_regs_set_regs; auto. apply agree_regs_inject_incr with j; auto.
+ eapply external_call_symbols_preserved'. econstructor; eauto. apply senv_preserved.
+ eapply match_states_return with (j := j').
+ eapply match_stacks_change_meminj; eauto.
+ apply agree_regs_set_regs. apply agree_regs_inject_incr with j; auto. apply encode_long_inject; auto.
apply agree_callee_save_set_result; auto.
+ apply stack_contents_change_meminj with j; auto.
+ rewrite sep_comm, sep_assoc; auto.
- (* return *)
- inv STACKS. simpl in AGLOCS.
+ inv STACKS. simpl in AGLOCS. simpl in SEP. rewrite sep_assoc in SEP.
econstructor; split.
apply plus_one. apply exec_return.
econstructor; eauto.
- apply agree_frame_return with rs0; auto.
+ apply agree_locs_return with rs0; auto.
+ apply frame_contents_exten with rs0 (parent_locset s); auto.
Qed.
Lemma transf_initial_states:
@@ -2862,18 +2113,21 @@ Proof.
eapply (Genv.init_mem_transf_partial TRANSF); eauto.
rewrite (match_program_main TRANSF).
rewrite symbols_preserved. eauto.
- econstructor; eauto.
+ set (j := Mem.flat_inj (Mem.nextblock m0)).
+ eapply match_states_call with (j := j); eauto.
+ constructor. red; intros. rewrite H3, loc_arguments_main in H. contradiction.
+ red; simpl; auto.
+ red; simpl; auto.
+ simpl. rewrite sep_pure. split; auto. split;[|split].
eapply Genv.initmem_inject; eauto.
- apply match_stacks_empty with (Mem.nextblock m0). apply Ple_refl. apply Ple_refl.
- constructor.
- intros. unfold Mem.flat_inj. apply pred_dec_true; auto.
- unfold Mem.flat_inj; intros. destruct (plt b1 (Mem.nextblock m0)); congruence.
- intros. change (Mem.valid_block m0 b0). eapply Genv.find_symbol_not_fresh; eauto.
- intros. change (Mem.valid_block m0 b0). eapply Genv.find_funct_ptr_not_fresh; eauto.
- intros. change (Mem.valid_block m0 b0). eapply Genv.find_var_info_not_fresh; eauto.
- rewrite H3. red; intros. rewrite loc_arguments_main in H. contradiction.
- unfold Locmap.init. red; intros; auto.
- unfold parent_locset. red; auto.
+ simpl. exists (Mem.nextblock m0); split. apply Ple_refl.
+ unfold j, Mem.flat_inj; constructor; intros.
+ apply pred_dec_true; auto.
+ destruct (plt b1 (Mem.nextblock m0)); congruence.
+ change (Mem.valid_block m0 b0). eapply Genv.find_symbol_not_fresh; eauto.
+ change (Mem.valid_block m0 b0). eapply Genv.find_funct_ptr_not_fresh; eauto.
+ change (Mem.valid_block m0 b0). eapply Genv.find_var_info_not_fresh; eauto.
+ red; simpl; tauto.
Qed.
Lemma transf_final_states: