aboutsummaryrefslogtreecommitdiffstats
path: root/backend/RREproof.v
diff options
context:
space:
mode:
Diffstat (limited to 'backend/RREproof.v')
-rw-r--r--backend/RREproof.v630
1 files changed, 630 insertions, 0 deletions
diff --git a/backend/RREproof.v b/backend/RREproof.v
new file mode 100644
index 00000000..da959ea5
--- /dev/null
+++ b/backend/RREproof.v
@@ -0,0 +1,630 @@
+(* *********************************************************************)
+(* *)
+(* The Compcert verified compiler *)
+(* *)
+(* Xavier Leroy, INRIA Paris-Rocquencourt *)
+(* *)
+(* Copyright Institut National de Recherche en Informatique et en *)
+(* Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the INRIA Non-Commercial License Agreement. *)
+(* *)
+(* *********************************************************************)
+
+(** Correctness proof for the [RRE] pass. *)
+
+Require Import Axioms.
+Require Import Coqlib.
+Require Import Maps.
+Require Import AST.
+Require Import Values.
+Require Import Globalenvs.
+Require Import Events.
+Require Import Smallstep.
+Require Import Op.
+Require Import Locations.
+Require Import Conventions.
+Require Import Linear.
+Require Import RRE.
+
+(** * Operations over equations *)
+
+Lemma find_reg_containing_sound:
+ forall s r eqs, find_reg_containing s eqs = Some r -> In (mkeq r s) eqs.
+Proof.
+ induction eqs; simpl; intros.
+ congruence.
+ destruct (slot_eq (e_slot a) s). inv H. left; destruct a; auto. right; eauto.
+Qed.
+
+Definition equations_hold (ls: locset) (eqs: equations) : Prop :=
+ forall e, In e eqs -> ls (S (e_slot e)) = ls (R (e_reg e)).
+
+Lemma nil_hold:
+ forall ls, equations_hold ls nil.
+Proof.
+ red; intros; contradiction.
+Qed.
+
+Lemma In_kill_loc:
+ forall e l eqs,
+ In e (kill_loc l eqs) ->
+ In e eqs /\ Loc.diff (S (e_slot e)) l /\ Loc.diff (R (e_reg e)) l.
+Proof.
+ induction eqs; simpl kill_loc; simpl In; intros.
+ tauto.
+ destruct (Loc.diff_dec (S (e_slot a)) l).
+ destruct (Loc.diff_dec (R (e_reg a)) l).
+ simpl in H. intuition congruence.
+ simpl in H. intuition.
+ simpl in H. intuition.
+Qed.
+
+Lemma kill_loc_hold:
+ forall ls eqs l v,
+ equations_hold ls eqs ->
+ equations_hold (Locmap.set l v ls) (kill_loc l eqs).
+Proof.
+ intros; red; intros.
+ exploit In_kill_loc; eauto. intros [A [B C]].
+ repeat rewrite Locmap.gso; auto; apply Loc.diff_sym; auto.
+Qed.
+
+Lemma In_kill_locs:
+ forall e ll eqs,
+ In e (kill_locs ll eqs) ->
+ In e eqs /\ Loc.notin (S (e_slot e)) ll /\ Loc.notin (R (e_reg e)) ll.
+Proof.
+Opaque Loc.diff.
+ induction ll; simpl; intros.
+ tauto.
+ exploit IHll; eauto. intros [A [B C]]. exploit In_kill_loc; eauto. intros [D [E F]].
+ tauto.
+Qed.
+
+Lemma kill_locs_hold:
+ forall ll ls eqs,
+ equations_hold ls eqs ->
+ equations_hold (Locmap.undef ll ls) (kill_locs ll eqs).
+Proof.
+ intros; red; intros. exploit In_kill_locs; eauto. intros [A [B C]].
+ repeat rewrite Locmap.guo; auto.
+Qed.
+
+Lemma kill_temps_hold:
+ forall ls eqs,
+ equations_hold ls eqs ->
+ equations_hold (LTL.undef_temps ls) (kill_temps eqs).
+Proof.
+ exact (kill_locs_hold temporaries).
+Qed.
+
+Lemma kill_at_move_hold:
+ forall ls eqs,
+ equations_hold ls eqs ->
+ equations_hold (undef_setstack ls) (kill_at_move eqs).
+Proof.
+ exact (kill_locs_hold destroyed_at_move).
+Qed.
+
+Lemma kill_at_op_hold:
+ forall op ls eqs,
+ equations_hold ls eqs ->
+ equations_hold (undef_op op ls) (kill_op op eqs).
+Proof.
+ intros op.
+ destruct op; exact kill_temps_hold || exact kill_at_move_hold.
+Qed.
+
+Lemma eqs_getstack_hold:
+ forall rs r s eqs,
+ equations_hold rs eqs ->
+ equations_hold (Locmap.set (R r) (rs (S s)) rs)
+ (mkeq r s :: kill_loc (R r) eqs).
+Proof.
+Transparent Loc.diff.
+ intros; red; intros. simpl in H0; destruct H0.
+ subst e. simpl. rewrite Locmap.gss; rewrite Locmap.gso; auto. red; auto.
+ exploit In_kill_loc; eauto. intros [D [E F]].
+ repeat rewrite Locmap.gso. auto.
+ apply Loc.diff_sym; auto. apply Loc.diff_sym; auto.
+Qed.
+
+Lemma eqs_movestack_hold:
+ forall rs r s eqs,
+ equations_hold rs eqs ->
+ equations_hold (Locmap.set (R r) (rs (S s)) (undef_setstack rs))
+ (kill_at_move (mkeq r s :: kill_loc (R r) eqs)).
+Proof.
+ unfold undef_setstack, kill_at_move; intros; red; intros.
+ exploit In_kill_locs; eauto. intros [A [B C]].
+ simpl in A; destruct A.
+ subst e. rewrite Locmap.gss. rewrite Locmap.gso. apply Locmap.guo. auto.
+ simpl; auto.
+ exploit In_kill_loc; eauto. intros [D [E F]].
+ repeat rewrite Locmap.gso. repeat rewrite Locmap.guo; auto.
+ apply Loc.diff_sym; auto. apply Loc.diff_sym; auto.
+Qed.
+
+Lemma eqs_setstack_hold:
+ forall rs r s eqs,
+ equations_hold rs eqs ->
+ equations_hold (Locmap.set (S s) (rs (R r)) (undef_setstack rs))
+ (kill_at_move (mkeq r s :: kill_loc (S s) eqs)).
+Proof.
+ unfold undef_setstack, kill_at_move; intros; red; intros.
+ exploit In_kill_locs; eauto. intros [A [B C]].
+ simpl in A; destruct A.
+ subst e. rewrite Locmap.gss. rewrite Locmap.gso. rewrite Locmap.guo. auto.
+ auto. simpl. destruct s; auto.
+ exploit In_kill_loc; eauto. intros [D [E F]].
+ repeat rewrite Locmap.gso. repeat rewrite Locmap.guo; auto.
+ apply Loc.diff_sym; auto. apply Loc.diff_sym; auto.
+Qed.
+
+Lemma locmap_set_reg_same:
+ forall rs r,
+ Locmap.set (R r) (rs (R r)) rs = rs.
+Proof.
+ intros. apply extensionality; intros.
+ destruct (Loc.eq x (R r)).
+ subst x. apply Locmap.gss.
+ apply Locmap.gso. apply Loc.diff_reg_right; auto.
+Qed.
+
+(** * Agreement between values of locations *)
+
+(** Values of locations may differ between the original and transformed
+ program: after a [Lgetstack] is optimized to a [Lop Omove],
+ the values of [destroyed_at_move] temporaries differ. This
+ can only happen in parts of the code where the [safe_move_insertion]
+ function returns [true]. *)
+
+Definition agree (sm: bool) (rs rs': locset) : Prop :=
+ forall l, sm = false \/ Loc.notin l destroyed_at_move -> rs' l = rs l.
+
+Lemma agree_false:
+ forall rs rs',
+ agree false rs rs' <-> rs' = rs.
+Proof.
+ intros; split; intros.
+ apply extensionality; intros. auto.
+ subst rs'. red; auto.
+Qed.
+
+Lemma agree_slot:
+ forall sm rs rs' s,
+ agree sm rs rs' -> rs' (S s) = rs (S s).
+Proof.
+Transparent Loc.diff.
+ intros. apply H. right. simpl; destruct s; tauto.
+Qed.
+
+Lemma agree_reg:
+ forall sm rs rs' r,
+ agree sm rs rs' ->
+ sm = false \/ ~In r destroyed_at_move_regs -> rs' (R r) = rs (R r).
+Proof.
+ intros. apply H. destruct H0; auto. right.
+ simpl in H0; simpl; intuition congruence.
+Qed.
+
+Lemma agree_regs:
+ forall sm rs rs' rl,
+ agree sm rs rs' ->
+ sm = false \/ list_disjoint rl destroyed_at_move_regs -> reglist rs' rl = reglist rs rl.
+Proof.
+ induction rl; intros; simpl.
+ auto.
+ decEq. apply agree_reg with sm; auto.
+ destruct H0; auto.
+ right. eapply list_disjoint_notin; eauto with coqlib.
+ apply IHrl; auto. destruct H0; auto. right. eapply list_disjoint_cons_left; eauto.
+Qed.
+
+Lemma agree_set:
+ forall sm rs rs' l v,
+ agree sm rs rs' ->
+ agree sm (Locmap.set l v rs) (Locmap.set l v rs').
+Proof.
+ intros; red; intros.
+ unfold Locmap.set.
+ destruct (Loc.eq l l0). auto.
+ destruct (Loc.overlap l l0). auto.
+ apply H; auto.
+Qed.
+
+Lemma agree_undef_move_1:
+ forall sm rs rs',
+ agree sm rs rs' ->
+ agree true rs (undef_setstack rs').
+Proof.
+ intros. unfold undef_setstack. red; intros.
+ destruct H0. congruence. rewrite Locmap.guo; auto.
+Qed.
+
+Remark locmap_undef_equal:
+ forall x ll rs rs',
+ (forall l, Loc.notin l ll -> rs' l = rs l) ->
+ Locmap.undef ll rs' x = Locmap.undef ll rs x.
+Proof.
+ induction ll; intros; simpl.
+ apply H. simpl. auto.
+ apply IHll. intros. unfold Locmap.set.
+ destruct (Loc.eq a l). auto. destruct (Loc.overlap a l) as []_eqn. auto.
+ apply H. simpl. split; auto. apply Loc.diff_sym. apply Loc.non_overlap_diff; auto.
+Qed.
+
+Lemma agree_undef_move_2:
+ forall sm rs rs',
+ agree sm rs rs' ->
+ agree false (undef_setstack rs) (undef_setstack rs').
+Proof.
+ intros. rewrite agree_false.
+ apply extensionality; intros. unfold undef_setstack. apply locmap_undef_equal. auto.
+Qed.
+
+Lemma agree_undef_temps:
+ forall sm rs rs',
+ agree sm rs rs' ->
+ agree false (LTL.undef_temps rs) (LTL.undef_temps rs').
+Proof.
+ intros. rewrite agree_false.
+ apply extensionality; intros. unfold LTL.undef_temps. apply locmap_undef_equal.
+ intros. apply H. right. simpl in H0; simpl; tauto.
+Qed.
+
+Lemma agree_undef_op:
+ forall op sm rs rs',
+ agree sm rs rs' ->
+ agree false (undef_op op rs) (undef_op op rs').
+Proof.
+ intros op.
+ destruct op; exact agree_undef_temps || exact agree_undef_move_2.
+Qed.
+
+Lemma transl_find_label:
+ forall lbl c eqs,
+ find_label lbl (transf_code eqs c) =
+ option_map (transf_code nil) (find_label lbl c).
+Proof.
+ induction c; simpl; intros.
+ auto.
+ destruct a; simpl; auto.
+ destruct (is_incoming s); simpl; auto.
+ destruct (contains_equation s m eqs); auto.
+ destruct (find_reg_containing s eqs); simpl; auto.
+ destruct (safe_move_insertion c); simpl; auto.
+ destruct (peq lbl l); simpl; auto.
+Qed.
+
+(** * Semantic preservation *)
+
+Section PRESERVATION.
+
+Variable prog: program.
+Let tprog := transf_program prog.
+
+Let ge := Genv.globalenv prog.
+Let tge := Genv.globalenv tprog.
+
+Lemma functions_translated:
+ forall v f,
+ Genv.find_funct ge v = Some f ->
+ Genv.find_funct tge v = Some (transf_fundef f).
+Proof (@Genv.find_funct_transf _ _ _ transf_fundef prog).
+
+Lemma function_ptr_translated:
+ forall v f,
+ Genv.find_funct_ptr ge v = Some f ->
+ Genv.find_funct_ptr tge v = Some (transf_fundef f).
+Proof (@Genv.find_funct_ptr_transf _ _ _ transf_fundef prog).
+
+Lemma symbols_preserved:
+ forall id,
+ Genv.find_symbol tge id = Genv.find_symbol ge id.
+Proof (@Genv.find_symbol_transf _ _ _ transf_fundef prog).
+
+Lemma varinfo_preserved:
+ forall b, Genv.find_var_info tge b = Genv.find_var_info ge b.
+Proof (@Genv.find_var_info_transf _ _ _ transf_fundef prog).
+
+Lemma sig_preserved:
+ forall f, funsig (transf_fundef f) = funsig f.
+Proof.
+ destruct f; reflexivity.
+Qed.
+
+Lemma find_function_translated:
+ forall ros rs fd,
+ find_function ge ros rs = Some fd ->
+ find_function tge ros rs = Some (transf_fundef fd).
+Proof.
+ intros. destruct ros; simpl in *.
+ apply functions_translated; auto.
+ rewrite symbols_preserved. destruct (Genv.find_symbol ge i).
+ apply function_ptr_translated; auto.
+ congruence.
+Qed.
+
+Inductive match_frames: stackframe -> stackframe -> Prop :=
+ | match_frames_intro:
+ forall f sp rs c,
+ match_frames (Stackframe f sp rs c)
+ (Stackframe (transf_function f) sp rs (transf_code nil c)).
+
+Inductive match_states: state -> state -> Prop :=
+ | match_states_regular:
+ forall sm stk f sp c rs m stk' rs' eqs
+ (STK: list_forall2 match_frames stk stk')
+ (EQH: equations_hold rs' eqs)
+ (AG: agree sm rs rs')
+ (SAFE: sm = false \/ safe_move_insertion c = true),
+ match_states (State stk f sp c rs m)
+ (State stk' (transf_function f) sp (transf_code eqs c) rs' m)
+ | match_states_call:
+ forall stk f rs m stk'
+ (STK: list_forall2 match_frames stk stk'),
+ match_states (Callstate stk f rs m)
+ (Callstate stk' (transf_fundef f) rs m)
+ | match_states_return:
+ forall stk rs m stk'
+ (STK: list_forall2 match_frames stk stk'),
+ match_states (Returnstate stk rs m)
+ (Returnstate stk' rs m).
+
+Definition measure (S: state) : nat :=
+ match S with
+ | State s f sp c rs m => List.length c
+ | _ => 0%nat
+ end.
+
+Remark match_parent_locset:
+ forall stk stk',
+ list_forall2 match_frames stk stk' ->
+ return_regs (parent_locset stk') = return_regs (parent_locset stk).
+Proof.
+ intros. inv H; auto. inv H0; auto.
+Qed.
+
+Theorem transf_step_correct:
+ forall S1 t S2, step ge S1 t S2 ->
+ forall S1' (MS: match_states S1 S1'),
+ (exists S2', step tge S1' t S2' /\ match_states S2 S2')
+ \/ (measure S2 < measure S1 /\ t = E0 /\ match_states S2 S1')%nat.
+Proof.
+Opaque destroyed_at_move_regs.
+ induction 1; intros; inv MS; simpl.
+(** getstack *)
+ simpl in SAFE.
+ assert (SAFE': sm = false \/ ~In r destroyed_at_move_regs /\ safe_move_insertion b = true).
+ destruct (in_dec mreg_eq r destroyed_at_move_regs); simpl in SAFE; intuition congruence.
+ destruct (is_incoming sl) as []_eqn.
+ (* incoming, stays as getstack *)
+ assert (UGS: forall rs, undef_getstack sl rs = Locmap.set (R IT1) Vundef rs).
+ destruct sl; simpl in Heqb0; discriminate || auto.
+ left; econstructor; split. constructor.
+ repeat rewrite UGS.
+ apply match_states_regular with sm; auto.
+ apply kill_loc_hold. apply kill_loc_hold; auto.
+ rewrite (agree_slot _ _ _ sl AG). apply agree_set. apply agree_set. auto.
+ tauto.
+ (* not incoming *)
+ assert (UGS: forall rs, undef_getstack sl rs = rs).
+ destruct sl; simpl in Heqb0; discriminate || auto.
+ unfold contains_equation.
+ destruct (in_dec eq_equation (mkeq r sl) eqs); simpl.
+ (* eliminated *)
+ right. split. omega. split. auto. rewrite UGS.
+ exploit EQH; eauto. simpl. intro EQ.
+ assert (EQ1: rs' (S sl) = rs (S sl)) by (eapply agree_slot; eauto).
+ assert (EQ2: rs' (R r) = rs (R r)) by (eapply agree_reg; eauto; tauto).
+ rewrite <- EQ1; rewrite EQ; rewrite EQ2. rewrite locmap_set_reg_same.
+ apply match_states_regular with sm; auto. tauto.
+ (* found an equation *)
+ destruct (find_reg_containing sl eqs) as [r'|]_eqn.
+ exploit EQH. eapply find_reg_containing_sound; eauto.
+ simpl; intro EQ.
+ (* turned into a move *)
+ destruct (safe_move_insertion b) as []_eqn.
+ left; econstructor; split. constructor. simpl; eauto.
+ rewrite UGS. rewrite <- EQ.
+ apply match_states_regular with true; auto.
+ apply eqs_movestack_hold; auto.
+ rewrite (agree_slot _ _ _ sl AG). apply agree_set. eapply agree_undef_move_1; eauto.
+ (* left as a getstack *)
+ left; econstructor; split. constructor.
+ repeat rewrite UGS.
+ apply match_states_regular with sm; auto.
+ apply eqs_getstack_hold; auto.
+ rewrite (agree_slot _ _ _ sl AG). apply agree_set. auto.
+ intuition congruence.
+ (* no equation, left as a getstack *)
+ left; econstructor; split. constructor.
+ repeat rewrite UGS.
+ apply match_states_regular with sm; auto.
+ apply eqs_getstack_hold; auto.
+ rewrite (agree_slot _ _ _ sl AG). apply agree_set. auto.
+ tauto.
+
+(* setstack *)
+ left; econstructor; split. constructor.
+ apply match_states_regular with false; auto.
+ apply eqs_setstack_hold; auto.
+ rewrite (agree_reg _ _ _ r AG). apply agree_set. eapply agree_undef_move_2; eauto.
+ simpl in SAFE. destruct (in_dec mreg_eq r destroyed_at_move_regs); simpl in SAFE; intuition congruence.
+
+(* op *)
+ left; econstructor; split. constructor.
+ instantiate (1 := v). rewrite <- H.
+ rewrite (agree_regs _ _ _ args AG).
+ apply eval_operation_preserved. exact symbols_preserved.
+ simpl in SAFE. destruct (list_disjoint_dec mreg_eq args destroyed_at_move_regs); simpl in SAFE; intuition congruence.
+ apply match_states_regular with false; auto.
+ apply kill_loc_hold; apply kill_at_op_hold; auto.
+ apply agree_set. eapply agree_undef_op; eauto.
+
+(* load *)
+ left; econstructor; split.
+ econstructor. instantiate (1 := a). rewrite <- H.
+ rewrite (agree_regs _ _ _ args AG).
+ apply eval_addressing_preserved. exact symbols_preserved.
+ simpl in SAFE. destruct (list_disjoint_dec mreg_eq args destroyed_at_move_regs); simpl in SAFE; intuition congruence.
+ eauto.
+ apply match_states_regular with false; auto.
+ apply kill_loc_hold; apply kill_temps_hold; auto.
+ apply agree_set. eapply agree_undef_temps; eauto.
+
+(* store *)
+Opaque list_disjoint_dec.
+ simpl in SAFE.
+ assert (sm = false \/ ~In src destroyed_at_move_regs /\ list_disjoint args destroyed_at_move_regs).
+ destruct SAFE. auto. right.
+ destruct (list_disjoint_dec mreg_eq (src :: args) destroyed_at_move_regs); try discriminate.
+ split. eapply list_disjoint_notin; eauto with coqlib. eapply list_disjoint_cons_left; eauto.
+ left; econstructor; split.
+ econstructor. instantiate (1 := a). rewrite <- H.
+ rewrite (agree_regs _ _ _ args AG).
+ apply eval_addressing_preserved. exact symbols_preserved.
+ tauto.
+ rewrite (agree_reg _ _ _ src AG).
+ eauto.
+ tauto.
+ apply match_states_regular with false; auto.
+ apply kill_temps_hold; auto.
+ eapply agree_undef_temps; eauto.
+
+(* call *)
+ simpl in SAFE. assert (sm = false) by intuition congruence.
+ subst sm. rewrite agree_false in AG. subst rs'.
+ left; econstructor; split.
+ constructor. eapply find_function_translated; eauto.
+ symmetry; apply sig_preserved.
+ constructor. constructor; auto. constructor.
+
+(* tailcall *)
+ simpl in SAFE. assert (sm = false) by intuition congruence.
+ subst sm. rewrite agree_false in AG. subst rs'.
+ left; econstructor; split.
+ constructor. eapply find_function_translated; eauto.
+ symmetry; apply sig_preserved. eauto.
+ rewrite (match_parent_locset _ _ STK). constructor; auto.
+
+(* builtin *)
+ left; econstructor; split.
+ constructor.
+ rewrite (agree_regs _ _ _ args AG).
+ eapply external_call_symbols_preserved; eauto.
+ exact symbols_preserved. exact varinfo_preserved.
+ simpl in SAFE. destruct (list_disjoint_dec mreg_eq args destroyed_at_move_regs); simpl in SAFE; intuition congruence.
+ apply match_states_regular with false; auto.
+ apply kill_loc_hold; apply kill_temps_hold; auto.
+ apply agree_set. eapply agree_undef_temps; eauto.
+
+(* annot *)
+ simpl in SAFE. assert (sm = false) by intuition congruence.
+ subst sm. rewrite agree_false in AG. subst rs'.
+ left; econstructor; split.
+ econstructor. eapply external_call_symbols_preserved; eauto.
+ exact symbols_preserved. exact varinfo_preserved.
+ apply match_states_regular with false; auto.
+ rewrite agree_false; auto.
+
+(* label *)
+ left; econstructor; split. constructor.
+ apply match_states_regular with false; auto.
+ apply nil_hold.
+ simpl in SAFE. destruct SAFE. subst sm. auto. congruence.
+
+(* goto *)
+ generalize (transl_find_label lbl (fn_code f) nil). rewrite H. simpl. intros.
+ left; econstructor; split. constructor; eauto.
+ apply match_states_regular with false; auto.
+ apply nil_hold.
+ simpl in SAFE. destruct SAFE. subst sm. auto. congruence.
+
+(* cond true *)
+ generalize (transl_find_label lbl (fn_code f) nil). rewrite H0. simpl. intros.
+ left; econstructor; split.
+ apply exec_Lcond_true; auto.
+ rewrite (agree_regs _ _ _ args AG). auto.
+ simpl in SAFE. destruct (list_disjoint_dec mreg_eq args destroyed_at_move_regs); simpl in SAFE; intuition congruence.
+ eauto.
+ apply match_states_regular with false; auto.
+ apply nil_hold.
+ eapply agree_undef_temps; eauto.
+
+(* cond false *)
+ left; econstructor; split. apply exec_Lcond_false; auto.
+ rewrite (agree_regs _ _ _ args AG). auto.
+ simpl in SAFE. destruct (list_disjoint_dec mreg_eq args destroyed_at_move_regs); simpl in SAFE; intuition congruence.
+ apply match_states_regular with false; auto.
+ apply kill_temps_hold; auto.
+ eapply agree_undef_temps; eauto.
+
+(* jumptable *)
+ generalize (transl_find_label lbl (fn_code f) nil). rewrite H1. simpl. intros.
+ left; econstructor; split. econstructor; eauto.
+ rewrite (agree_reg _ _ _ arg AG). auto.
+ simpl in SAFE. destruct (in_dec mreg_eq arg destroyed_at_move_regs); simpl in SAFE; intuition congruence.
+ apply match_states_regular with false; auto.
+ apply nil_hold.
+ eapply agree_undef_temps; eauto.
+
+(* return *)
+ simpl in SAFE. destruct SAFE; try discriminate. subst sm. rewrite agree_false in AG. subst rs'.
+ left; econstructor; split.
+ constructor. simpl. eauto.
+ rewrite (match_parent_locset _ _ STK).
+ constructor; auto.
+
+(* internal *)
+ left; econstructor; split.
+ constructor. simpl; eauto.
+ simpl. apply match_states_regular with false; auto. apply nil_hold. rewrite agree_false; auto.
+
+(* external *)
+ left; econstructor; split.
+ econstructor. eapply external_call_symbols_preserved; eauto.
+ exact symbols_preserved. exact varinfo_preserved.
+ auto. eauto.
+ constructor; auto.
+
+(* return *)
+ inv STK. inv H1. left; econstructor; split. constructor.
+ apply match_states_regular with false; auto.
+ apply nil_hold.
+ rewrite agree_false; auto.
+Qed.
+
+Lemma transf_initial_states:
+ forall st1, initial_state prog st1 ->
+ exists st2, initial_state tprog st2 /\ match_states st1 st2.
+Proof.
+ intros. inversion H.
+ econstructor; split.
+ econstructor.
+ apply Genv.init_mem_transf; eauto.
+ rewrite symbols_preserved. eauto.
+ apply function_ptr_translated; eauto.
+ rewrite sig_preserved. auto.
+ econstructor; eauto. constructor.
+Qed.
+
+Lemma transf_final_states:
+ forall st1 st2 r,
+ match_states st1 st2 -> final_state st1 r -> final_state st2 r.
+Proof.
+ intros. inv H0. inv H. inv STK. econstructor. auto.
+Qed.
+
+Theorem transf_program_correct:
+ forward_simulation (Linear.semantics prog) (Linear.semantics tprog).
+Proof.
+ eapply forward_simulation_opt.
+ eexact symbols_preserved.
+ eexact transf_initial_states.
+ eexact transf_final_states.
+ eexact transf_step_correct.
+Qed.
+
+End PRESERVATION.