summaryrefslogtreecommitdiff
path: root/backend/RTLgenproof1.v
diff options
context:
space:
mode:
Diffstat (limited to 'backend/RTLgenproof1.v')
-rw-r--r--backend/RTLgenproof1.v1463
1 files changed, 1463 insertions, 0 deletions
diff --git a/backend/RTLgenproof1.v b/backend/RTLgenproof1.v
new file mode 100644
index 0000000..4a8ad43
--- /dev/null
+++ b/backend/RTLgenproof1.v
@@ -0,0 +1,1463 @@
+(** Correctness proof for RTL generation: auxiliary results. *)
+
+Require Import Coqlib.
+Require Import Maps.
+Require Import AST.
+Require Import Integers.
+Require Import Values.
+Require Import Mem.
+Require Import Globalenvs.
+Require Import Op.
+Require Import Registers.
+Require Import Cminor.
+Require Import RTL.
+Require Import RTLgen.
+
+(** * Reasoning about monadic computations *)
+
+(** The tactics below simplify hypotheses of the form [f ... = OK x s]
+ where [f] is a monadic computation. For instance, the hypothesis
+ [(do x <- a; b) s = OK y s'] will generate the additional witnesses
+ [x], [s1] and the additional hypotheses
+ [a s = OK x s1] and [b x s1 = OK y s'], reflecting the fact that
+ both monadic computations [a] and [b] succeeded.
+*)
+
+Ltac monadSimpl1 :=
+ match goal with
+ | [ |- (bind ?F ?G ?S = OK ?X ?S') -> _ ] =>
+ unfold bind at 1;
+ generalize (refl_equal (F S));
+ pattern (F S) at -1 in |- *;
+ case (F S);
+ [ intro; intro; discriminate
+ | (let s := fresh "s" in
+ (let EQ := fresh "EQ" in
+ (intro; intros s EQ;
+ try monadSimpl1))) ]
+ | [ |- (bind2 ?F ?G ?S = OK ?X ?S') -> _ ] =>
+ unfold bind2 at 1; unfold bind at 1;
+ generalize (refl_equal (F S));
+ pattern (F S) at -1 in |- *;
+ case (F S);
+ [ intro; intro; discriminate
+ | let xy := fresh "xy" in
+ (let x := fresh "x" in
+ (let y := fresh "y" in
+ (let s := fresh "s" in
+ (let EQ := fresh "EQ" in
+ (intros xy s EQ; destruct xy as [x y]; simpl;
+ try monadSimpl1))))) ]
+ | [ |- (error _ _ = OK _ _) -> _ ] =>
+ unfold error; monadSimpl1
+ | [ |- (ret _ _ = OK _ _) -> _ ] =>
+ unfold ret; monadSimpl1
+ | [ |- (Error _ = OK _ _) -> _ ] =>
+ intro; discriminate
+ | [ |- (OK _ _ = OK _ _) -> _ ] =>
+ let h := fresh "H" in
+ (intro h; injection h; intro; intro; clear h)
+ end.
+
+Ltac monadSimpl :=
+ match goal with
+ | [ |- (bind ?F ?G ?S = OK ?X ?S') -> _ ] => monadSimpl1
+ | [ |- (bind2 ?F ?G ?S = OK ?X ?S') -> _ ] => monadSimpl1
+ | [ |- (error _ _ = OK _ _) -> _ ] => monadSimpl1
+ | [ |- (ret _ _ = OK _ _) -> _ ] => monadSimpl1
+ | [ |- (Error _ = OK _ _) -> _ ] => monadSimpl1
+ | [ |- (OK _ _ = OK _ _) -> _ ] => monadSimpl1
+ | [ |- (?F _ _ _ _ _ _ _ = OK _ _) -> _ ] => unfold F; monadSimpl1
+ | [ |- (?F _ _ _ _ _ _ = OK _ _) -> _ ] => unfold F; monadSimpl1
+ | [ |- (?F _ _ _ _ _ = OK _ _) -> _ ] => unfold F; monadSimpl1
+ | [ |- (?F _ _ _ _ = OK _ _) -> _ ] => unfold F; monadSimpl1
+ | [ |- (?F _ _ _ = OK _ _) -> _ ] => unfold F; monadSimpl1
+ | [ |- (?F _ _ = OK _ _) -> _ ] => unfold F; monadSimpl1
+ | [ |- (?F _ = OK _ _) -> _ ] => unfold F; monadSimpl1
+ end.
+
+Ltac monadInv H :=
+ generalize H; monadSimpl.
+
+(** * Monotonicity properties of the state *)
+
+(** Operations over the global state satisfy a crucial monotonicity property:
+ nodes are only added to the CFG, but never removed nor their instructions
+ changed; similarly, fresh nodes and fresh registers are only consumed,
+ but never reused. This property is captured by the following predicate
+ over states, which we show is a partial order. *)
+
+Inductive state_incr: state -> state -> Prop :=
+ state_incr_intro:
+ forall (s1 s2: state),
+ Ple s1.(st_nextnode) s2.(st_nextnode) ->
+ Ple s1.(st_nextreg) s2.(st_nextreg) ->
+ (forall pc, Plt pc s1.(st_nextnode) -> s2.(st_code)!pc = s1.(st_code)!pc) ->
+ state_incr s1 s2.
+
+Lemma instr_at_incr:
+ forall s1 s2 n i,
+ s1.(st_code)!n = i -> i <> None -> state_incr s1 s2 ->
+ s2.(st_code)!n = i.
+Proof.
+ intros. inversion H1.
+ rewrite <- H. apply H4. elim (st_wf s1 n); intro.
+ assumption. elim H0. congruence.
+Qed.
+
+Lemma state_incr_refl:
+ forall s, state_incr s s.
+Proof.
+ intros. apply state_incr_intro.
+ apply Ple_refl. apply Ple_refl. intros; auto.
+Qed.
+Hint Resolve state_incr_refl: rtlg.
+
+Lemma state_incr_trans:
+ forall s1 s2 s3, state_incr s1 s2 -> state_incr s2 s3 -> state_incr s1 s3.
+Proof.
+ intros. inversion H. inversion H0. apply state_incr_intro.
+ apply Ple_trans with (st_nextnode s2); assumption.
+ apply Ple_trans with (st_nextreg s2); assumption.
+ intros. transitivity (s2.(st_code)!pc).
+ apply H8. apply Plt_Ple_trans with s1.(st_nextnode); auto.
+ apply H3; auto.
+Qed.
+Hint Resolve state_incr_trans: rtlg.
+
+Lemma state_incr_trans2:
+ forall s1 s2 s3 s4,
+ state_incr s1 s2 -> state_incr s2 s3 -> state_incr s3 s4 ->
+ state_incr s1 s4.
+Proof.
+ intros; eauto with rtlg.
+Qed.
+
+Lemma state_incr_trans3:
+ forall s1 s2 s3 s4 s5,
+ state_incr s1 s2 -> state_incr s2 s3 -> state_incr s3 s4 -> state_incr s4 s5 ->
+ state_incr s1 s5.
+Proof.
+ intros; eauto with rtlg.
+Qed.
+
+Lemma state_incr_trans4:
+ forall s1 s2 s3 s4 s5 s6,
+ state_incr s1 s2 -> state_incr s2 s3 -> state_incr s3 s4 ->
+ state_incr s4 s5 -> state_incr s5 s6 ->
+ state_incr s1 s6.
+Proof.
+ intros; eauto with rtlg.
+Qed.
+
+Lemma state_incr_trans5:
+ forall s1 s2 s3 s4 s5 s6 s7,
+ state_incr s1 s2 -> state_incr s2 s3 -> state_incr s3 s4 ->
+ state_incr s4 s5 -> state_incr s5 s6 -> state_incr s6 s7 ->
+ state_incr s1 s7.
+Proof.
+ intros; eauto 6 with rtlg.
+Qed.
+
+Lemma state_incr_trans6:
+ forall s1 s2 s3 s4 s5 s6 s7 s8,
+ state_incr s1 s2 -> state_incr s2 s3 -> state_incr s3 s4 ->
+ state_incr s4 s5 -> state_incr s5 s6 -> state_incr s6 s7 ->
+ state_incr s7 s8 -> state_incr s1 s8.
+Proof.
+ intros; eauto 7 with rtlg.
+Qed.
+
+(** The following relation between two states is a weaker version of
+ [state_incr]. It permits changing the contents at an already reserved
+ graph node, but only from [None] to [Some i]. *)
+
+Definition state_extends (s1 s2: state): Prop :=
+ forall pc,
+ s1.(st_code)!pc = None \/ s2.(st_code)!pc = s1.(st_code)!pc.
+
+Lemma state_incr_extends:
+ forall s1 s2,
+ state_incr s1 s2 -> state_extends s1 s2.
+Proof.
+ unfold state_extends; intros. inversion H.
+ case (plt pc s1.(st_nextnode)); intro.
+ right; apply H2; auto.
+ left. elim (s1.(st_wf) pc); intro.
+ elim (n H5). auto.
+Qed.
+Hint Resolve state_incr_extends.
+
+(** A crucial property of states is the following: if an RTL execution
+ is possible (does not get stuck) in the CFG of a given state [s1]
+ the same execution is possible and leads to the same results in
+ the CFG of any state [s2] that extends [s1] in the sense of the
+ [state_extends] predicate. *)
+
+Section EXEC_INSTR_EXTENDS.
+
+Variable s1 s2: state.
+Hypothesis EXT: state_extends s1 s2.
+
+Lemma exec_instr_not_halt:
+ forall ge c sp pc rs m pc' rs' m',
+ exec_instr ge c sp pc rs m pc' rs' m' -> c!pc <> None.
+Proof.
+ induction 1; rewrite H; discriminate.
+Qed.
+
+Lemma exec_instr_in_s2:
+ forall ge sp pc rs m pc' rs' m',
+ exec_instr ge s1.(st_code) sp pc rs m pc' rs' m' ->
+ s2.(st_code)!pc = s1.(st_code)!pc.
+Proof.
+ intros.
+ elim (EXT pc); intro.
+ elim (exec_instr_not_halt _ _ _ _ _ _ _ _ _ H H0).
+ assumption.
+Qed.
+
+Lemma exec_instr_extends_rec:
+ forall ge c sp pc rs m pc' rs' m',
+ exec_instr ge c sp pc rs m pc' rs' m' ->
+ forall c', c!pc = c'!pc ->
+ exec_instr ge c' sp pc rs m pc' rs' m'.
+Proof.
+ induction 1; intros.
+ apply exec_Inop. congruence.
+ apply exec_Iop with op args. congruence. auto.
+ apply exec_Iload with chunk addr args a. congruence. auto. auto.
+ apply exec_Istore with chunk addr args src a.
+ congruence. auto. auto.
+ apply exec_Icall with sig ros args f; auto. congruence.
+ apply exec_Icond_true with cond args ifnot; auto. congruence.
+ apply exec_Icond_false with cond args ifso; auto. congruence.
+Qed.
+
+Lemma exec_instr_extends:
+ forall ge sp pc rs m pc' rs' m',
+ exec_instr ge s1.(st_code) sp pc rs m pc' rs' m' ->
+ exec_instr ge s2.(st_code) sp pc rs m pc' rs' m'.
+Proof.
+ intros.
+ apply exec_instr_extends_rec with (st_code s1).
+ assumption.
+ symmetry. eapply exec_instr_in_s2. eexact H.
+Qed.
+
+Lemma exec_instrs_extends_rec:
+ forall ge c sp pc rs m pc' rs' m',
+ exec_instrs ge c sp pc rs m pc' rs' m' ->
+ c = s1.(st_code) ->
+ exec_instrs ge s2.(st_code) sp pc rs m pc' rs' m'.
+Proof.
+ induction 1; intros.
+ apply exec_refl.
+ apply exec_one. apply exec_instr_extends; auto. rewrite <- H0; auto.
+ apply exec_trans with pc2 rs2 m2; auto.
+Qed.
+
+Lemma exec_instrs_extends:
+ forall ge sp pc rs m pc' rs' m',
+ exec_instrs ge s1.(st_code) sp pc rs m pc' rs' m' ->
+ exec_instrs ge s2.(st_code) sp pc rs m pc' rs' m'.
+Proof.
+ intros.
+ apply exec_instrs_extends_rec with (st_code s1); auto.
+Qed.
+
+End EXEC_INSTR_EXTENDS.
+
+(** Since [state_incr s1 s2] implies [state_extends s1 s2], we also have
+ that any RTL execution possible in the CFG of [s1] is also possible
+ in the CFG of [s2], provided that [state_incr s1 s2].
+ In particular, any RTL execution that is possible in a partially
+ constructed CFG remains possible in the final CFG obtained at
+ the end of the translation of the current function. *)
+
+Section EXEC_INSTR_INCR.
+
+Variable s1 s2: state.
+Hypothesis INCR: state_incr s1 s2.
+
+Lemma exec_instr_incr:
+ forall ge sp pc rs m pc' rs' m',
+ exec_instr ge s1.(st_code) sp pc rs m pc' rs' m' ->
+ exec_instr ge s2.(st_code) sp pc rs m pc' rs' m'.
+Proof.
+ intros.
+ apply exec_instr_extends with s1.
+ apply state_incr_extends; auto.
+ auto.
+Qed.
+
+Lemma exec_instrs_incr:
+ forall ge sp pc rs m pc' rs' m',
+ exec_instrs ge s1.(st_code) sp pc rs m pc' rs' m' ->
+ exec_instrs ge s2.(st_code) sp pc rs m pc' rs' m'.
+Proof.
+ intros.
+ apply exec_instrs_extends with s1.
+ apply state_incr_extends; auto.
+ auto.
+Qed.
+
+End EXEC_INSTR_INCR.
+
+(** * Validity and freshness of registers *)
+
+(** An RTL pseudo-register is valid in a given state if it was created
+ earlier, that is, it is less than the next fresh register of the state.
+ Otherwise, the pseudo-register is said to be fresh. *)
+
+Definition reg_valid (r: reg) (s: state) : Prop :=
+ Plt r s.(st_nextreg).
+
+Definition reg_fresh (r: reg) (s: state) : Prop :=
+ ~(Plt r s.(st_nextreg)).
+
+Lemma valid_fresh_absurd:
+ forall r s, reg_valid r s -> reg_fresh r s -> False.
+Proof.
+ intros r s. unfold reg_valid, reg_fresh; case r; tauto.
+Qed.
+Hint Resolve valid_fresh_absurd: rtlg.
+
+Lemma valid_fresh_different:
+ forall r1 r2 s, reg_valid r1 s -> reg_fresh r2 s -> r1 <> r2.
+Proof.
+ unfold not; intros. subst r2. eauto with rtlg.
+Qed.
+Hint Resolve valid_fresh_different: rtlg.
+
+Lemma reg_valid_incr:
+ forall r s1 s2, state_incr s1 s2 -> reg_valid r s1 -> reg_valid r s2.
+Proof.
+ intros r s1 s2 INCR.
+ inversion INCR.
+ unfold reg_valid. intros; apply Plt_Ple_trans with (st_nextreg s1); auto.
+Qed.
+Hint Resolve reg_valid_incr: rtlg.
+
+Lemma reg_fresh_decr:
+ forall r s1 s2, state_incr s1 s2 -> reg_fresh r s2 -> reg_fresh r s1.
+Proof.
+ intros r s1 s2 INCR. inversion INCR.
+ unfold reg_fresh; unfold not; intros.
+ apply H4. apply Plt_Ple_trans with (st_nextreg s1); auto.
+Qed.
+Hint Resolve reg_fresh_decr: rtlg.
+
+(** * Well-formedness of compilation environments *)
+
+(** A compilation environment (mapping) is well-formed in a given state if
+ the following properties hold:
+- The registers associated with Cminor local variables and let-bound variables
+ are valid in the state.
+- Two distinct Cminor local variables are mapped to distinct pseudo-registers.
+- A Cminor local variable and a let-bound variable are mapped to
+ distinct pseudo-registers.
+*)
+
+Record map_wf (m: mapping) (s: state) : Prop :=
+ mk_map_wf {
+ map_wf_var_valid:
+ (forall id r, m.(map_vars)!id = Some r -> reg_valid r s);
+ map_wf_letvar_valid:
+ (forall r, In r m.(map_letvars) -> reg_valid r s);
+ map_wf_inj:
+ (forall id1 id2 r,
+ m.(map_vars)!id1 = Some r -> m.(map_vars)!id2 = Some r -> id1 = id2);
+ map_wf_disj:
+ (forall id r,
+ m.(map_vars)!id = Some r -> In r m.(map_letvars) -> False)
+ }.
+Hint Resolve map_wf_var_valid
+ map_wf_letvar_valid
+ map_wf_inj map_wf_disj: rtlg.
+
+Lemma map_wf_incr:
+ forall s1 s2 m,
+ state_incr s1 s2 -> map_wf m s1 -> map_wf m s2.
+Proof.
+ intros. apply mk_map_wf; intros; eauto with rtlg.
+Qed.
+Hint Resolve map_wf_incr: rtlg.
+
+(** A register is ``in'' a mapping if it is associated with a Cminor
+ local or let-bound variable. *)
+
+Definition reg_in_map (m: mapping) (r: reg) : Prop :=
+ (exists id, m.(map_vars)!id = Some r) \/ In r m.(map_letvars).
+
+Lemma reg_in_map_valid:
+ forall m s r,
+ map_wf m s -> reg_in_map m r -> reg_valid r s.
+Proof.
+ intros. elim H0.
+ intros [id EQ]. eauto with rtlg.
+ intro IN. eauto with rtlg.
+Qed.
+Hint Resolve reg_in_map_valid: rtlg.
+
+(** A register is mutated if it is associated with a Cminor local variable
+ that belongs to the given set of mutated variables. *)
+
+Definition mutated_reg (map: mapping) (mut: list ident) (r: reg) : Prop :=
+ exists id, In id mut /\ map.(map_vars)!id = Some r.
+
+Lemma mutated_reg_in_map:
+ forall map mut r, mutated_reg map mut r -> reg_in_map map r.
+Proof.
+ intros. elim H. intros id [IN EQ].
+ left. exists id; auto.
+Qed.
+Hint Resolve mutated_reg_in_map: rtlg.
+
+(** * Properties of basic operations over the state *)
+
+(** Properties of [add_instr]. *)
+
+Lemma add_instr_incr:
+ forall s1 s2 i n,
+ add_instr i s1 = OK n s2 -> state_incr s1 s2.
+Proof.
+ intros until n; monadSimpl.
+ subst s2; apply state_incr_intro; simpl.
+ apply Ple_succ.
+ apply Ple_refl.
+ intros. apply PTree.gso; apply Plt_ne; auto.
+Qed.
+Hint Resolve add_instr_incr: rtlg.
+
+Lemma add_instr_at:
+ forall s1 s2 i n,
+ add_instr i s1 = OK n s2 -> s2.(st_code)!n = Some i.
+Proof.
+ intros until n; monadSimpl.
+ subst n; subst s2; simpl. apply PTree.gss.
+Qed.
+Hint Resolve add_instr_at.
+
+(** Properties of [reserve_instr] and [update_instr]. *)
+
+Lemma reserve_instr_incr:
+ forall s1 s2 n,
+ reserve_instr s1 = OK n s2 -> state_incr s1 s2.
+Proof.
+ intros until n; monadSimpl. subst s2.
+ apply state_incr_intro; simpl.
+ apply Ple_succ.
+ apply Ple_refl.
+ auto.
+Qed.
+
+Lemma update_instr_incr:
+ forall s1 s2 s3 s4 i n t,
+ reserve_instr s1 = OK n s2 ->
+ state_incr s2 s3 ->
+ update_instr n i s3 = OK t s4 ->
+ state_incr s1 s4.
+Proof.
+ intros.
+ monadInv H.
+ generalize H1; unfold update_instr.
+ case (plt n (st_nextnode s3)); intro.
+ monadSimpl. inversion H0.
+ subst s4; apply state_incr_intro; simpl.
+ apply Plt_Ple. apply Plt_Ple_trans with (st_nextnode s2).
+ subst s2; simpl; apply Plt_succ. assumption.
+ rewrite <- H3 in H7; simpl in H7. assumption.
+ intros. rewrite PTree.gso.
+ rewrite <- H3 in H8; simpl in H8. apply H8.
+ apply Plt_trans_succ; assumption.
+ subst n; apply Plt_ne; assumption.
+ intros; discriminate.
+Qed.
+
+Lemma update_instr_extends:
+ forall s1 s2 s3 s4 i n t,
+ reserve_instr s1 = OK n s2 ->
+ state_incr s2 s3 ->
+ update_instr n i s3 = OK t s4 ->
+ state_extends s3 s4.
+Proof.
+ intros.
+ monadInv H.
+ red; intros.
+ case (peq pc n); intro.
+ subst pc. left. inversion H0. rewrite H6.
+ rewrite <- H3; simpl.
+ elim (s1.(st_wf) n); intro.
+ rewrite <- H4 in H9. elim (Plt_strict _ H9).
+ auto.
+ rewrite <- H4. rewrite <- H3; simpl. apply Plt_succ.
+ generalize H1; unfold update_instr.
+ case (plt n s3.(st_nextnode)); intro; monadSimpl.
+ right; rewrite <- H5; simpl. apply PTree.gso; auto.
+Qed.
+
+(** Properties of [new_reg]. *)
+
+Lemma new_reg_incr:
+ forall s1 s2 r, new_reg s1 = OK r s2 -> state_incr s1 s2.
+Proof.
+ intros until r. monadSimpl.
+ subst s2; apply state_incr_intro; simpl.
+ apply Ple_refl. apply Ple_succ. auto.
+Qed.
+Hint Resolve new_reg_incr: rtlg.
+
+Lemma new_reg_valid:
+ forall s1 s2 r,
+ new_reg s1 = OK r s2 -> reg_valid r s2.
+Proof.
+ intros until r. monadSimpl. subst s2; subst r.
+ unfold reg_valid; unfold reg_valid; simpl.
+ apply Plt_succ.
+Qed.
+Hint Resolve new_reg_valid: rtlg.
+
+Lemma new_reg_fresh:
+ forall s1 s2 r,
+ new_reg s1 = OK r s2 -> reg_fresh r s1.
+Proof.
+ intros until r. monadSimpl. subst s2; subst r.
+ unfold reg_fresh; simpl.
+ exact (Plt_strict _).
+Qed.
+Hint Resolve new_reg_fresh: rtlg.
+
+Lemma new_reg_not_in_map:
+ forall s1 s2 m r,
+ new_reg s1 = OK r s2 -> map_wf m s1 -> ~(reg_in_map m r).
+Proof.
+ unfold not; intros; eauto with rtlg.
+Qed.
+Hint Resolve new_reg_not_in_map: rtlg.
+
+Lemma new_reg_not_mutated:
+ forall s1 s2 m mut r,
+ new_reg s1 = OK r s2 -> map_wf m s1 -> ~(mutated_reg m mut r).
+Proof.
+ unfold not; intros.
+ generalize (mutated_reg_in_map _ _ _ H1); intro.
+ exact (new_reg_not_in_map _ _ _ _ H H0 H2).
+Qed.
+Hint Resolve new_reg_not_mutated: rtlg.
+
+(** * Properties of operations over compilation environments *)
+
+Lemma init_mapping_wf:
+ forall s, map_wf init_mapping s.
+Proof.
+ intro. unfold init_mapping; apply mk_map_wf; simpl; intros.
+ rewrite PTree.gempty in H; discriminate.
+ contradiction.
+ rewrite PTree.gempty in H; discriminate.
+ tauto.
+Qed.
+
+(** Properties of [find_var]. *)
+
+Lemma find_var_incr:
+ forall s1 s2 map name r,
+ find_var map name s1 = OK r s2 -> state_incr s1 s2.
+Proof.
+ intros until r. unfold find_var.
+ case (map_vars map)!name.
+ intro; monadSimpl. subst s2; auto with rtlg.
+ monadSimpl.
+Qed.
+Hint Resolve find_var_incr: rtlg.
+
+Lemma find_var_in_map:
+ forall s1 s2 map name r,
+ find_var map name s1 = OK r s2 -> map_wf map s1 -> reg_in_map map r.
+Proof.
+ intros until r. unfold find_var; caseEq (map.(map_vars)!name).
+ intros r0 eq. monadSimpl; intros. subst r0.
+ left. exists name; auto.
+ intro; monadSimpl.
+Qed.
+Hint Resolve find_var_in_map: rtlg.
+
+Lemma find_var_valid:
+ forall s1 s2 map name r,
+ find_var map name s1 = OK r s2 -> map_wf map s1 -> reg_valid r s1.
+Proof.
+ eauto with rtlg.
+Qed.
+Hint Resolve find_var_valid: rtlg.
+
+Lemma find_var_not_mutated:
+ forall s1 s2 map name r mut,
+ find_var map name s1 = OK r s2 ->
+ map_wf map s1 ->
+ ~(In name mut) ->
+ ~(mutated_reg map mut r).
+Proof.
+ intros until mut. unfold find_var; caseEq (map.(map_vars)!name).
+ intros r0 EQ. monadSimpl; intros; subst r0.
+ red; unfold mutated_reg; intros [id [IN EQ2]].
+ assert (name = id). eauto with rtlg.
+ subst id. contradiction.
+ intro; monadSimpl.
+Qed.
+Hint Resolve find_var_not_mutated: rtlg.
+
+(** Properties of [find_letvar]. *)
+
+Lemma find_letvar_incr:
+ forall s1 s2 map idx r,
+ find_letvar map idx s1 = OK r s2 -> state_incr s1 s2.
+Proof.
+ intros until r. unfold find_letvar.
+ case (nth_error (map_letvars map) idx).
+ intro; monadSimpl. subst s2; auto with rtlg.
+ monadSimpl.
+Qed.
+Hint Resolve find_letvar_incr: rtlg.
+
+Lemma find_letvar_in_map:
+ forall s1 s2 map idx r,
+ find_letvar map idx s1 = OK r s2 -> map_wf map s1 -> reg_in_map map r.
+Proof.
+ intros until r. unfold find_letvar.
+ caseEq (nth_error (map_letvars map) idx).
+ intros r0 EQ; monadSimpl. intros. right.
+ subst r0; apply nth_error_in with idx; auto.
+ intro; monadSimpl.
+Qed.
+Hint Resolve find_letvar_in_map: rtlg.
+
+Lemma find_letvar_valid:
+ forall s1 s2 map idx r,
+ find_letvar map idx s1 = OK r s2 -> map_wf map s1 -> reg_valid r s1.
+Proof.
+ eauto with rtlg.
+Qed.
+Hint Resolve find_letvar_valid: rtlg.
+
+Lemma find_letvar_not_mutated:
+ forall s1 s2 map idx mut r,
+ find_letvar map idx s1 = OK r s2 ->
+ map_wf map s1 ->
+ ~(mutated_reg map mut r).
+Proof.
+ intros until r. unfold find_letvar.
+ caseEq (nth_error (map_letvars map) idx).
+ intros r' NTH. monadSimpl. unfold not; unfold mutated_reg.
+ intros MWF (id, (IN, MV)). subst r'. eauto with rtlg coqlib.
+ intro; monadSimpl.
+Qed.
+Hint Resolve find_letvar_not_mutated: rtlg.
+
+(** Properties of [add_var]. *)
+
+Lemma add_var_valid:
+ forall s1 s2 map1 map2 name r,
+ add_var map1 name s1 = OK (r, map2) s2 -> reg_valid r s2.
+Proof.
+ intros until r. monadSimpl. intro. subst r0; subst s.
+ eauto with rtlg.
+Qed.
+
+Lemma add_var_incr:
+ forall s1 s2 map name rm,
+ add_var map name s1 = OK rm s2 -> state_incr s1 s2.
+Proof.
+ intros until rm; monadSimpl. subst s2. eauto with rtlg.
+Qed.
+Hint Resolve add_var_incr: rtlg.
+
+Lemma add_var_wf:
+ forall s1 s2 map name r map',
+ add_var map name s1 = OK (r,map') s2 -> map_wf map s1 -> map_wf map' s2.
+Proof.
+ intros until map'; monadSimpl; intros.
+ subst r0; subst s; subst map'; apply mk_map_wf; simpl.
+
+ intros id r'. rewrite PTree.gsspec.
+ case (peq id name); intros.
+ injection H; intros; subst r'. eauto with rtlg.
+ eauto with rtlg.
+ eauto with rtlg.
+
+ intros id1 id2 r'.
+ repeat (rewrite PTree.gsspec).
+ case (peq id1 name); case (peq id2 name); intros.
+ congruence.
+ rewrite <- H in H0. byContradiction; eauto with rtlg.
+ rewrite <- H0 in H. byContradiction; eauto with rtlg.
+ eauto with rtlg.
+
+ intros id r'. case (peq id name); intro.
+ subst id. rewrite PTree.gss. intro E; injection E; intro; subst r'.
+ intro; eauto with rtlg.
+
+ rewrite PTree.gso; auto. eauto with rtlg.
+Qed.
+Hint Resolve add_var_wf: rtlg.
+
+Lemma add_var_find:
+ forall s1 s2 map name r map',
+ add_var map name s1 = OK (r,map') s2 -> map'.(map_vars)!name = Some r.
+Proof.
+ intros until map'.
+ monadSimpl.
+ intro; subst r0.
+ subst map'; simpl in |- *.
+ apply PTree.gss.
+Qed.
+
+Lemma add_vars_incr:
+ forall names s1 s2 map r,
+ add_vars map names s1 = OK r s2 -> state_incr s1 s2.
+Proof.
+ induction names; simpl.
+ intros until r; monadSimpl; intros. subst s2; eauto with rtlg.
+ intros until r; monadSimpl; intros.
+ subst s0; eauto with rtlg.
+Qed.
+
+Lemma add_vars_valid:
+ forall namel s1 s2 map1 map2 rl,
+ add_vars map1 namel s1 = OK (rl, map2) s2 ->
+ forall r, In r rl -> reg_valid r s2.
+Proof.
+ induction namel; simpl; intros.
+ monadInv H. intro. subst rl. elim H0.
+ monadInv H. intro EQ1. subst rl; subst s0; subst y0. elim H0.
+ intro; subst r. eapply add_var_valid. eexact EQ0.
+ intro. apply reg_valid_incr with s. eauto with rtlg.
+ eauto.
+Qed.
+
+Lemma add_vars_wf:
+ forall names s1 s2 map map' rl,
+ add_vars map names s1 = OK (rl,map') s2 ->
+ map_wf map s1 -> map_wf map' s2.
+Proof.
+ induction names; simpl.
+ intros until rl; monadSimpl; intros.
+ subst s2; subst map'; assumption.
+ intros until rl; monadSimpl; intros. subst y0; subst s0.
+ eapply add_var_wf. eexact EQ0.
+ eapply IHnames. eexact EQ. auto.
+Qed.
+Hint Resolve add_vars_wf: rtlg.
+
+Lemma add_var_letenv:
+ forall map1 i s1 r map2 s2,
+ add_var map1 i s1 = OK (r, map2) s2 ->
+ map2.(map_letvars) = map1.(map_letvars).
+Proof.
+ intros until s2. monadSimpl. intro. subst map2; reflexivity.
+Qed.
+
+(** Properties of [add_letvar]. *)
+
+Lemma add_letvar_wf:
+ forall map s r,
+ map_wf map s ->
+ reg_valid r s ->
+ ~(reg_in_map map r) ->
+ map_wf (add_letvar map r) s.
+Proof.
+ intros. unfold add_letvar; apply mk_map_wf; simpl.
+ exact (map_wf_var_valid map s H).
+ intros r' [EQ| IN].
+ subst r'; assumption.
+ eapply map_wf_letvar_valid; eauto.
+ exact (map_wf_inj map s H).
+ intros. elim H3; intro.
+ subst r0. apply H1. left. exists id; auto.
+ eapply map_wf_disj; eauto.
+Qed.
+
+(** * Properties of [alloc_reg] and [alloc_regs] *)
+
+Lemma alloc_reg_incr:
+ forall a s1 s2 map mut r,
+ alloc_reg map mut a s1 = OK r s2 -> state_incr s1 s2.
+Proof.
+ intros until r. unfold alloc_reg.
+ case a; eauto with rtlg.
+ intro i; case (In_dec ident_eq i mut); eauto with rtlg.
+Qed.
+Hint Resolve alloc_reg_incr: rtlg.
+
+Lemma alloc_reg_valid:
+ forall a s1 s2 map mut r,
+ map_wf map s1 ->
+ alloc_reg map mut a s1 = OK r s2 -> reg_valid r s2.
+Proof.
+ intros until r. unfold alloc_reg.
+ case a; eauto with rtlg.
+ intro i; case (In_dec ident_eq i mut); eauto with rtlg.
+Qed.
+Hint Resolve alloc_reg_valid: rtlg.
+
+Lemma alloc_reg_fresh_or_in_map:
+ forall map mut a s r s',
+ map_wf map s ->
+ alloc_reg map mut a s = OK r s' ->
+ reg_in_map map r \/ reg_fresh r s.
+Proof.
+ intros until s'. unfold alloc_reg.
+ destruct a; try (right; eauto with rtlg; fail).
+ case (In_dec ident_eq i mut); intros.
+ right; eauto with rtlg.
+ left; eauto with rtlg.
+ intros; left; eauto with rtlg.
+Qed.
+
+Lemma add_vars_letenv:
+ forall il map1 s1 rl map2 s2,
+ add_vars map1 il s1 = OK (rl, map2) s2 ->
+ map2.(map_letvars) = map1.(map_letvars).
+Proof.
+ induction il; simpl; intros.
+ monadInv H. intro. subst map2; reflexivity.
+ monadInv H. intro EQ1. transitivity (map_letvars y).
+ subst y0. eapply add_var_letenv; eauto.
+ eauto.
+Qed.
+
+(** A register is an adequate target for holding the value of an
+ expression if
+- either the register is associated with a Cminor let-bound variable
+ or a Cminor local variable that is not modified;
+- or the register is valid and not associated with any Cminor variable. *)
+
+Inductive target_reg_ok: state -> mapping -> list ident -> expr -> reg -> Prop :=
+ | target_reg_immut_var:
+ forall s map mut id r,
+ ~(In id mut) -> map.(map_vars)!id = Some r ->
+ target_reg_ok s map mut (Evar id) r
+ | target_reg_letvar:
+ forall s map mut idx r,
+ nth_error map.(map_letvars) idx = Some r ->
+ target_reg_ok s map mut (Eletvar idx) r
+ | target_reg_other:
+ forall s map mut a r,
+ ~(reg_in_map map r) ->
+ reg_valid r s ->
+ target_reg_ok s map mut a r.
+
+Lemma target_reg_ok_incr:
+ forall s1 s2 map mut e r,
+ state_incr s1 s2 ->
+ target_reg_ok s1 map mut e r ->
+ target_reg_ok s2 map mut e r.
+Proof.
+ intros. inversion H0.
+ apply target_reg_immut_var; auto.
+ apply target_reg_letvar; auto.
+ apply target_reg_other; eauto with rtlg.
+Qed.
+Hint Resolve target_reg_ok_incr: rtlg.
+
+Lemma target_reg_valid:
+ forall s map mut e r,
+ map_wf map s ->
+ target_reg_ok s map mut e r ->
+ reg_valid r s.
+Proof.
+ intros. inversion H0; eauto with rtlg coqlib.
+Qed.
+Hint Resolve target_reg_valid: rtlg.
+
+Lemma target_reg_not_mutated:
+ forall s map mut e r,
+ map_wf map s ->
+ target_reg_ok s map mut e r ->
+ ~(mutated_reg map mut r).
+Proof.
+ unfold not; unfold mutated_reg; intros until r.
+ intros MWF TRG [id [IN MV]].
+ inversion TRG.
+ assert (id = id0); eauto with rtlg. subst id0. contradiction.
+ assert (In r (map_letvars map)). eauto with coqlib. eauto with rtlg.
+ apply H. red. left; exists id; assumption.
+Qed.
+Hint Resolve target_reg_not_mutated: rtlg.
+
+Lemma alloc_reg_target_ok:
+ forall a s1 s2 map mut r,
+ map_wf map s1 ->
+ alloc_reg map mut a s1 = OK r s2 ->
+ target_reg_ok s2 map mut a r.
+Proof.
+ intros until r; intro MWF. unfold alloc_reg.
+ case a; intros; try (eapply target_reg_other; eauto with rtlg; fail).
+ generalize H; case (In_dec ident_eq i mut); intros.
+ apply target_reg_other; eauto with rtlg.
+ apply target_reg_immut_var; auto.
+ generalize H0; unfold find_var.
+ case (map_vars map)!i.
+ intro. monadSimpl. congruence.
+ monadSimpl.
+ apply target_reg_letvar.
+ generalize H. unfold find_letvar.
+ case (nth_error (map_letvars map) n).
+ intro; monadSimpl; congruence.
+ monadSimpl.
+Qed.
+Hint Resolve alloc_reg_target_ok: rtlg.
+
+Lemma alloc_regs_incr:
+ forall al s1 s2 map mut rl,
+ alloc_regs map mut al s1 = OK rl s2 -> state_incr s1 s2.
+Proof.
+ induction al; simpl; intros.
+ monadInv H. subst s2. eauto with rtlg.
+ monadInv H. subst s2. eauto with rtlg.
+Qed.
+Hint Resolve alloc_regs_incr: rtlg.
+
+Lemma alloc_regs_valid:
+ forall al s1 s2 map mut rl,
+ map_wf map s1 ->
+ alloc_regs map mut al s1 = OK rl s2 ->
+ forall r, In r rl -> reg_valid r s2.
+Proof.
+ induction al; simpl; intros.
+ monadInv H0. subst rl. elim H1.
+ monadInv H0. subst rl; subst s0.
+ elim H1; intro.
+ subst r0. eauto with rtlg.
+ eauto with rtlg.
+Qed.
+Hint Resolve alloc_regs_valid: rtlg.
+
+Lemma alloc_regs_fresh_or_in_map:
+ forall map mut al s rl s',
+ map_wf map s ->
+ alloc_regs map mut al s = OK rl s' ->
+ forall r, In r rl -> reg_in_map map r \/ reg_fresh r s.
+Proof.
+ induction al; simpl; intros.
+ monadInv H0. subst rl. elim H1.
+ monadInv H0. subst rl. elim (in_inv H1); intro.
+ subst r.
+ assert (MWF: map_wf map s0). eauto with rtlg.
+ elim (alloc_reg_fresh_or_in_map map mut e s0 r0 s1 MWF EQ0); intro.
+ left; assumption. right; eauto with rtlg.
+ eauto with rtlg.
+Qed.
+
+Inductive target_regs_ok: state -> mapping -> list ident -> exprlist -> list reg -> Prop :=
+ | target_regs_nil:
+ forall s map mut,
+ target_regs_ok s map mut Enil nil
+ | target_regs_cons:
+ forall s map mut a r al rl,
+ reg_in_map map r \/ ~(In r rl) ->
+ target_reg_ok s map mut a r ->
+ target_regs_ok s map mut al rl ->
+ target_regs_ok s map mut (Econs a al) (r :: rl).
+
+Lemma target_regs_ok_incr:
+ forall s1 map mut al rl,
+ target_regs_ok s1 map mut al rl ->
+ forall s2,
+ state_incr s1 s2 ->
+ target_regs_ok s2 map mut al rl.
+Proof.
+ induction 1; intros.
+ apply target_regs_nil.
+ apply target_regs_cons; eauto with rtlg.
+Qed.
+Hint Resolve target_regs_ok_incr: rtlg.
+
+Lemma target_regs_valid:
+ forall s map mut al rl,
+ target_regs_ok s map mut al rl ->
+ map_wf map s ->
+ forall r, In r rl -> reg_valid r s.
+Proof.
+ induction 1; simpl; intros.
+ contradiction.
+ elim H3; intro.
+ subst r0. eauto with rtlg.
+ auto.
+Qed.
+Hint Resolve target_regs_valid: rtlg.
+
+Lemma target_regs_not_mutated:
+ forall s map mut el rl,
+ target_regs_ok s map mut el rl ->
+ map_wf map s ->
+ forall r, In r rl -> ~(mutated_reg map mut r).
+Proof.
+ induction 1; simpl; intros.
+ contradiction.
+ elim H3; intro. subst r0. eauto with rtlg.
+ auto.
+Qed.
+Hint Resolve target_regs_not_mutated: rtlg.
+
+Lemma alloc_regs_target_ok:
+ forall al s1 s2 map mut rl,
+ map_wf map s1 ->
+ alloc_regs map mut al s1 = OK rl s2 ->
+ target_regs_ok s2 map mut al rl.
+Proof.
+ induction al; simpl; intros.
+ monadInv H0. subst rl; apply target_regs_nil.
+ monadInv H0. subst s0; subst rl.
+ apply target_regs_cons; eauto 6 with rtlg.
+ assert (MWF: map_wf map s). eauto with rtlg.
+ elim (alloc_reg_fresh_or_in_map map mut e s r s2 MWF EQ0); intro.
+ left; assumption. right; red; intro; eauto with rtlg.
+Qed.
+Hint Resolve alloc_regs_target_ok: rtlg.
+
+(** The following predicate is a variant of [target_reg_ok] used
+ to characterize registers that are adequate for holding the return
+ value of a function. *)
+
+Inductive return_reg_ok: state -> mapping -> option reg -> Prop :=
+ | return_reg_ok_none:
+ forall s map,
+ return_reg_ok s map None
+ | return_reg_ok_some:
+ forall s map r,
+ ~(reg_in_map map r) -> reg_valid r s ->
+ return_reg_ok s map (Some r).
+
+Lemma return_reg_ok_incr:
+ forall s1 s2 map or,
+ state_incr s1 s2 ->
+ return_reg_ok s1 map or ->
+ return_reg_ok s2 map or.
+Proof.
+ intros. inversion H0; constructor.
+ assumption. eauto with rtlg.
+Qed.
+Hint Resolve return_reg_ok_incr: rtlg.
+
+Lemma new_reg_return_ok:
+ forall s1 r s2 map sig,
+ new_reg s1 = OK r s2 ->
+ map_wf map s1 ->
+ return_reg_ok s2 map (ret_reg sig r).
+Proof.
+ intros. unfold ret_reg. destruct (sig_res sig); constructor.
+ eauto with rtlg. eauto with rtlg.
+Qed.
+
+(** * Correspondence between Cminor environments and RTL register sets *)
+
+(** An RTL register environment matches a Cminor local environment and
+ let-environment if the value of every local or let-bound variable in
+ the Cminor environments is identical to the value of the
+ corresponding pseudo-register in the RTL register environment. *)
+
+Record match_env
+ (map: mapping) (e: Cminor.env) (le: Cminor.letenv) (rs: regset) : Prop :=
+ mk_match_env {
+ me_vars:
+ (forall id v,
+ e!id = Some v -> exists r, map.(map_vars)!id = Some r /\ rs#r = v);
+ me_letvars:
+ rs##(map.(map_letvars)) = le
+ }.
+
+Lemma match_env_find_reg:
+ forall map id s1 s2 r e le rs v,
+ find_var map id s1 = OK r s2 ->
+ match_env map e le rs ->
+ e!id = Some v ->
+ rs#r = v.
+Proof.
+ intros until v.
+ unfold find_var. caseEq (map.(map_vars)!id).
+ intros r' EQ. monadSimpl. subst r'. intros.
+ generalize (me_vars _ _ _ _ H _ _ H1). intros [r' [EQ' RS]].
+ rewrite EQ' in EQ; injection EQ; intro; subst r'.
+ assumption.
+ intro; monadSimpl.
+Qed.
+Hint Resolve match_env_find_reg: rtlg.
+
+Lemma match_env_invariant:
+ forall map e le rs rs',
+ match_env map e le rs ->
+ (forall r, (reg_in_map map r) -> rs'#r = rs#r) ->
+ match_env map e le rs'.
+Proof.
+ intros. apply mk_match_env.
+ intros id v' E.
+ generalize (me_vars _ _ _ _ H _ _ E). intros (r', (M, R)).
+ exists r'. split. auto. rewrite <- R. apply H0.
+ left. exists id. auto.
+ transitivity rs ## (map_letvars map).
+ apply list_map_exten. intros.
+ symmetry. apply H0. right. auto.
+ exact (me_letvars _ _ _ _ H).
+Qed.
+
+(** Matching between environments is preserved when an unmapped register
+ (not corresponding to any Cminor variable) is assigned in the RTL
+ execution. *)
+
+Lemma match_env_update_temp:
+ forall map e le rs r v,
+ match_env map e le rs ->
+ ~(reg_in_map map r) ->
+ match_env map e le (rs#r <- v).
+Proof.
+ intros. apply match_env_invariant with rs; auto.
+ intros. case (Reg.eq r r0); intro.
+ subst r0; contradiction.
+ apply Regmap.gso; auto.
+Qed.
+Hint Resolve match_env_update_temp: rtlg.
+
+(** Matching between environments is preserved by simultaneous
+ assignment to a Cminor local variable (in the Cminor environments)
+ and to the corresponding RTL pseudo-register (in the RTL register
+ environment). *)
+
+Lemma match_env_update_var:
+ forall map e le rs rs' id r v s s',
+ map_wf map s ->
+ find_var map id s = OK r s' ->
+ match_env map e le rs ->
+ rs'#r = v ->
+ (forall x, x <> r -> rs'#x = rs#x) ->
+ match_env map (PTree.set id v e) le rs'.
+Proof.
+ intros until s'; intro MWF.
+ unfold find_var in |- *. caseEq (map_vars map)!id.
+ intros. monadInv H0. subst r0. apply mk_match_env.
+ intros id' v' E. case (peq id' id); intros.
+ subst id'. rewrite PTree.gss in E. injection E; intro; subst v'.
+ exists r. split. auto. auto.
+ rewrite PTree.gso in E; auto.
+ elim (me_vars _ _ _ _ H1 _ _ E). intros r' (M, R).
+ exists r'. split. assumption. rewrite <- R; apply H3; auto.
+ red in |- *; intro. subst r'. apply n. eauto with rtlg.
+ transitivity rs ## (map_letvars map).
+ apply list_map_exten. intros. symmetry. apply H3.
+ red in |- *; intro. subst x. eauto with rtlg.
+ exact (me_letvars _ _ _ _ H1).
+ intro; monadSimpl.
+Qed.
+
+Lemma match_env_letvar:
+ forall map e le rs r v,
+ match_env map e le rs ->
+ rs#r = v ->
+ match_env (add_letvar map r) e (v :: le) rs.
+Proof.
+ intros. unfold add_letvar in |- *; apply mk_match_env; simpl in |- *.
+ exact (me_vars _ _ _ _ H).
+ rewrite H0. rewrite (me_letvars _ _ _ _ H). auto.
+Qed.
+
+Lemma match_env_exten:
+ forall map e le rs1 rs2,
+ (forall r, rs2#r = rs1#r) ->
+ match_env map e le rs1 ->
+ match_env map e le rs2.
+Proof.
+ intros. apply mk_match_env.
+ intros. generalize (me_vars _ _ _ _ H0 _ _ H1). intros (r, (M1, M2)).
+ exists r. split. assumption. subst v. apply H.
+ transitivity rs1 ## (map_letvars map).
+ apply list_map_exten. intros. symmetry in |- *. apply H.
+ exact (me_letvars _ _ _ _ H0).
+Qed.
+
+Lemma match_env_empty:
+ forall map,
+ map.(map_letvars) = nil ->
+ match_env map (PTree.empty val) nil (Regmap.init Vundef).
+Proof.
+ intros. apply mk_match_env.
+ intros. rewrite PTree.gempty in H0. discriminate.
+ rewrite H. reflexivity.
+Qed.
+
+(** The assignment of function arguments to local variables (on the Cminor
+ side) and pseudo-registers (on the RTL side) preserves matching
+ between environments. *)
+
+Lemma match_set_params_init_regs:
+ forall il rl s1 map2 s2 vl,
+ add_vars init_mapping il s1 = OK (rl, map2) s2 ->
+ match_env map2 (set_params vl il) nil (init_regs vl rl)
+ /\ (forall r, reg_fresh r s2 -> (init_regs vl rl)#r = Vundef).
+Proof.
+ induction il; simpl in |- *; intros.
+
+ monadInv H. intro; subst rl; simpl in |- *.
+ split. apply match_env_empty. subst map2; auto.
+ intros. apply Regmap.gi.
+
+ monadInv H. intro EQ1; subst s0; subst y0; subst rl. clear H.
+ monadInv EQ0. intro EQ2. subst x0; subst s0. simpl.
+
+ assert (LV : map_letvars map2 = nil).
+ transitivity (map_letvars y).
+ eapply add_var_letenv; eauto.
+ transitivity (map_letvars init_mapping).
+ eapply add_vars_letenv; eauto.
+ reflexivity.
+
+ destruct vl.
+ (* vl = nil *)
+ generalize (IHil _ _ _ _ nil EQ). intros [ME UNDEF]. split.
+ constructor. intros id v. subst map2. simpl.
+ repeat rewrite PTree.gsspec; case (peq id a); intros.
+ exists r; split. auto. rewrite Regmap.gi. congruence.
+ destruct (me_vars _ _ _ _ ME id v H) as (r', (MV, IR)).
+ exists r'. split. auto.
+ replace (init_regs nil x) with (Regmap.init Vundef) in IR. auto.
+ destruct x; reflexivity.
+ rewrite LV; reflexivity.
+ intros. apply Regmap.gi.
+ (* vl = v :: vl *)
+ generalize (IHil _ _ _ _ vl EQ). intros [ME UNDEF]. split.
+ constructor. intros id v1. subst map2. simpl.
+ repeat rewrite PTree.gsspec; case (peq id a); intros.
+ exists r; split. auto. rewrite Regmap.gss. congruence.
+ destruct (me_vars _ _ _ _ ME id v1 H) as (r', (MV, IR)).
+ exists r'. split. auto. rewrite Regmap.gso. auto.
+ apply valid_fresh_different with s.
+ assert (MWF : map_wf y s).
+ eapply add_vars_wf; eauto. apply init_mapping_wf.
+ eauto with rtlg. eauto with rtlg.
+ rewrite LV; reflexivity.
+ intros. rewrite Regmap.gso. apply UNDEF. eauto with rtlg.
+ apply sym_not_equal. eauto with rtlg.
+Qed.
+
+Lemma match_set_locals:
+ forall map1 s1,
+ map_wf map1 s1 ->
+ forall il rl map2 s2 e le rs,
+ match_env map1 e le rs ->
+ (forall r, reg_fresh r s1 -> rs#r = Vundef) ->
+ add_vars map1 il s1 = OK (rl, map2) s2 ->
+ match_env map2 (set_locals il e) le rs.
+Proof.
+ induction il; simpl in *; intros.
+
+ monadInv H2. intros; subst map2; auto.
+
+ monadInv H2. intros. subst s0; subst y0.
+ assert (match_env y (set_locals il e) le rs).
+ eapply IHil; eauto.
+ monadInv EQ0. intro. subst s0; subst x0. rewrite <- H7.
+ constructor.
+ intros id v. simpl. repeat rewrite PTree.gsspec.
+ case (peq id a); intros.
+ exists r. split. auto. injection H5; intro; subst v.
+ apply H1. apply reg_fresh_decr with s.
+ eapply add_vars_incr; eauto.
+ eauto with rtlg.
+ eapply me_vars; eauto.
+ simpl. eapply me_letvars; eauto.
+Qed.
+
+Lemma match_init_env_init_reg:
+ forall params s0 rparams map1 s1 vars rvars map2 s2 vparams,
+ add_vars init_mapping params s0 = OK (rparams, map1) s1 ->
+ add_vars map1 vars s1 = OK (rvars, map2) s2 ->
+ match_env map2 (set_locals vars (set_params vparams params))
+ nil (init_regs vparams rparams).
+Proof.
+ intros.
+ generalize (match_set_params_init_regs _ _ _ _ _ vparams H).
+ intros [A B].
+ eapply match_set_locals; eauto.
+ eapply add_vars_wf; eauto. apply init_mapping_wf.
+Qed.
+
+(** * Monotonicity properties of the state for the translation functions *)
+
+(** We show that the translation functions modify the state monotonically
+ (in the sense of the [state_incr] relation). *)
+
+Lemma add_move_incr:
+ forall r1 r2 nd s ns s',
+ add_move r1 r2 nd s = OK ns s' ->
+ state_incr s s'.
+Proof.
+ intros until s'. unfold add_move.
+ case (Reg.eq r1 r2); intro.
+ monadSimpl. subst s'; auto with rtlg.
+ intro; eauto with rtlg.
+Qed.
+Hint Resolve add_move_incr: rtlg.
+
+Scheme expr_ind3 := Induction for expr Sort Prop
+ with condexpr_ind3 := Induction for condexpr Sort Prop
+ with exprlist_ind3 := Induction for exprlist Sort Prop.
+
+Lemma expr_condexpr_exprlist_ind:
+forall (P : expr -> Prop) (P0 : condexpr -> Prop)
+ (P1 : exprlist -> Prop),
+ (forall i : ident, P (Evar i)) ->
+ (forall (i : ident) (e : expr), P e -> P (Eassign i e)) ->
+ (forall (o : operation) (e : exprlist), P1 e -> P (Eop o e)) ->
+ (forall (m : memory_chunk) (a : addressing) (e : exprlist),
+ P1 e -> P (Eload m a e)) ->
+ (forall (m : memory_chunk) (a : addressing) (e : exprlist),
+ P1 e -> forall e0 : expr, P e0 -> P (Estore m a e e0)) ->
+ (forall (s : signature) (e : expr),
+ P e -> forall e0 : exprlist, P1 e0 -> P (Ecall s e e0)) ->
+ (forall c : condexpr,
+ P0 c ->
+ forall e : expr,
+ P e -> forall e0 : expr, P e0 -> P (Econdition c e e0)) ->
+ (forall e : expr, P e -> forall e0 : expr, P e0 -> P (Elet e e0)) ->
+ (forall n : nat, P (Eletvar n)) ->
+ P0 CEtrue ->
+ P0 CEfalse ->
+ (forall (c : condition) (e : exprlist), P1 e -> P0 (CEcond c e)) ->
+ (forall c : condexpr,
+ P0 c ->
+ forall c0 : condexpr,
+ P0 c0 -> forall c1 : condexpr, P0 c1 -> P0 (CEcondition c c0 c1)) ->
+ P1 Enil ->
+ (forall e : expr,
+ P e -> forall e0 : exprlist, P1 e0 -> P1 (Econs e e0)) ->
+ (forall e : expr, P e) /\
+ (forall ce : condexpr, P0 ce) /\
+ (forall el : exprlist, P1 el).
+Proof.
+ intros. split. apply (expr_ind3 P P0 P1); assumption.
+ split. apply (condexpr_ind3 P P0 P1); assumption.
+ apply (exprlist_ind3 P P0 P1); assumption.
+Qed.
+
+Definition transl_expr_incr_pred (a: expr) : Prop :=
+ forall map mut rd nd s ns s',
+ transl_expr map mut a rd nd s = OK ns s' -> state_incr s s'.
+Definition transl_condition_incr_pred (c: condexpr) : Prop :=
+ forall map mut ntrue nfalse s ns s',
+ transl_condition map mut c ntrue nfalse s = OK ns s' -> state_incr s s'.
+Definition transl_exprlist_incr_pred (al: exprlist) : Prop :=
+ forall map mut rl nd s ns s',
+ transl_exprlist map mut al rl nd s = OK ns s' -> state_incr s s'.
+
+Lemma transl_expr_condition_exprlist_incr:
+ (forall a, transl_expr_incr_pred a) /\
+ (forall c, transl_condition_incr_pred c) /\
+ (forall al, transl_exprlist_incr_pred al).
+Proof.
+ apply expr_condexpr_exprlist_ind;
+ unfold transl_expr_incr_pred,
+ transl_condition_incr_pred,
+ transl_exprlist_incr_pred;
+ simpl; intros;
+ try (monadInv H); try (monadInv H0);
+ try (monadInv H1); try (monadInv H2);
+ eauto 6 with rtlg.
+
+ intro EQ2.
+ apply state_incr_trans3 with s0 s1 s2; eauto with rtlg.
+
+ intro EQ4.
+ apply state_incr_trans4 with s1 s2 s3 s4; eauto with rtlg.
+
+ subst s'; auto with rtlg.
+ subst s'; auto with rtlg.
+ destruct rl; monadInv H. subst s'; auto with rtlg.
+ destruct rl; monadInv H1. eauto with rtlg.
+Qed.
+
+Lemma transl_expr_incr:
+ forall a map mut rd nd s ns s',
+ transl_expr map mut a rd nd s = OK ns s' -> state_incr s s'.
+Proof (proj1 transl_expr_condition_exprlist_incr).
+
+Lemma transl_condition_incr:
+ forall a map mut ntrue nfalse s ns s',
+ transl_condition map mut a ntrue nfalse s = OK ns s' -> state_incr s s'.
+Proof (proj1 (proj2 transl_expr_condition_exprlist_incr)).
+
+Lemma transl_exprlist_incr:
+ forall al map mut rl nd s ns s',
+ transl_exprlist map mut al rl nd s = OK ns s' -> state_incr s s'.
+Proof (proj2 (proj2 transl_expr_condition_exprlist_incr)).
+
+Hint Resolve transl_expr_incr transl_condition_incr transl_exprlist_incr: rtlg.
+
+Scheme stmt_ind2 := Induction for stmt Sort Prop
+ with stmtlist_ind2 := Induction for stmtlist Sort Prop.
+
+Lemma stmt_stmtlist_ind:
+forall (P : stmt -> Prop) (P0 : stmtlist -> Prop),
+ (forall e : expr, P (Sexpr e)) ->
+ (forall (c : condexpr) (s : stmtlist),
+ P0 s -> forall s0 : stmtlist, P0 s0 -> P (Sifthenelse c s s0)) ->
+ (forall s : stmtlist, P0 s -> P (Sloop s)) ->
+ (forall s : stmtlist, P0 s -> P (Sblock s)) ->
+ (forall n : nat, P (Sexit n)) ->
+ (forall o : option expr, P (Sreturn o)) ->
+ P0 Snil ->
+ (forall s : stmt,
+ P s -> forall s0 : stmtlist, P0 s0 -> P0 (Scons s s0)) ->
+ (forall s : stmt, P s) /\
+ (forall sl : stmtlist, P0 sl).
+Proof.
+ intros. split. apply (stmt_ind2 P P0); assumption.
+ apply (stmtlist_ind2 P P0); assumption.
+Qed.
+
+Definition transl_stmt_incr_pred (a: stmt) : Prop :=
+ forall map nd nexits nret rret s ns s',
+ transl_stmt map a nd nexits nret rret s = OK ns s' ->
+ state_incr s s'.
+Definition transl_stmtlist_incr_pred (al: stmtlist) : Prop :=
+ forall map nd nexits nret rret s ns s',
+ transl_stmtlist map al nd nexits nret rret s = OK ns s' ->
+ state_incr s s'.
+
+Lemma transl_stmt_stmtlist_incr:
+ (forall a, transl_stmt_incr_pred a) /\
+ (forall al, transl_stmtlist_incr_pred al).
+Proof.
+ apply stmt_stmtlist_ind;
+ unfold transl_stmt_incr_pred,
+ transl_stmtlist_incr_pred;
+ simpl; intros;
+ try (monadInv H); try (monadInv H0);
+ try (monadInv H1); try (monadInv H2);
+ eauto 6 with rtlg.
+
+ generalize H1. case (more_likely c s s0); monadSimpl; eauto 6 with rtlg.
+
+ subst s'. apply update_instr_incr with s1 s2 (Inop n0) n u;
+ eauto with rtlg.
+
+ generalize H; destruct (nth_error nexits n); monadSimpl.
+ subst s'; auto with rtlg.
+
+ generalize H. destruct o; destruct rret; try monadSimpl.
+ eauto with rtlg.
+ subst s'; auto with rtlg.
+ subst s'; auto with rtlg.
+Qed.
+
+Lemma transl_stmt_incr:
+ forall a map nd nexits nret rret s ns s',
+ transl_stmt map a nd nexits nret rret s = OK ns s' ->
+ state_incr s s'.
+Proof (proj1 transl_stmt_stmtlist_incr).
+
+Lemma transl_stmtlist_incr:
+ forall al map nd nexits nret rret s ns s',
+ transl_stmtlist map al nd nexits nret rret s = OK ns s' ->
+ state_incr s s'.
+Proof (proj2 transl_stmt_stmtlist_incr).
+
+Hint Resolve transl_stmt_incr transl_stmtlist_incr: rtlg.
+