From 265fa07b34a813ba9d8249ddad82d71e6002c10d Mon Sep 17 00:00:00 2001 From: xleroy Date: Thu, 2 Sep 2010 12:42:19 +0000 Subject: Merge of the reuse-temps branch: - Reload temporaries are marked as destroyed (set to Vundef) across operations in the semantics of LTL, LTLin, Linear and Mach, allowing Asmgen to reuse them. - Added IA32 port. - Cleaned up float conversions and axiomatization of floats. git-svn-id: https://yquem.inria.fr/compcert/svn/compcert/trunk@1499 fca1b0fc-160b-0410-b1d3-a4f43f01ea2e --- ia32/Asmgenproof1.v | 1436 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1436 insertions(+) create mode 100644 ia32/Asmgenproof1.v (limited to 'ia32/Asmgenproof1.v') diff --git a/ia32/Asmgenproof1.v b/ia32/Asmgenproof1.v new file mode 100644 index 0000000..498bb4e --- /dev/null +++ b/ia32/Asmgenproof1.v @@ -0,0 +1,1436 @@ +(* *********************************************************************) +(* *) +(* 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 IA32 generation: auxiliary results. *) + +Require Import Coqlib. +Require Import Maps. +Require Import AST. +Require Import Errors. +Require Import Integers. +Require Import Floats. +Require Import Values. +Require Import Memory. +Require Import Globalenvs. +Require Import Op. +Require Import Locations. +Require Import Mach. +Require Import Machconcr. +Require Import Machtyping. +Require Import Asm. +Require Import Asmgen. +Require Import Conventions. + +Open Local Scope error_monad_scope. + +(** * Correspondence between Mach registers and IA32 registers *) + +Hint Extern 2 (_ <> _) => congruence: ppcgen. + +Lemma preg_of_injective: + forall r1 r2, preg_of r1 = preg_of r2 -> r1 = r2. +Proof. + destruct r1; destruct r2; simpl; intros; reflexivity || discriminate. +Qed. + +Lemma preg_of_not_ESP: + forall r, preg_of r <> ESP. +Proof. + destruct r; simpl; congruence. +Qed. + +Lemma preg_of_not_PC: + forall r, preg_of r <> PC. +Proof. + destruct r; simpl; congruence. +Qed. + +Hint Resolve preg_of_not_ESP preg_of_not_PC: ppcgen. + +Lemma ireg_of_eq: + forall r r', ireg_of r = OK r' -> preg_of r = IR r'. +Proof. + unfold ireg_of; intros. destruct (preg_of r); inv H; auto. +Qed. + +Lemma freg_of_eq: + forall r r', freg_of r = OK r' -> preg_of r = FR r'. +Proof. + unfold freg_of; intros. destruct (preg_of r); inv H; auto. +Qed. + +(** Agreement between Mach register sets and IA32 register sets. *) + +Record agree (ms: Mach.regset) (sp: val) (rs: Asm.regset) : Prop := mkagree { + agree_sp: rs#ESP = sp; + agree_sp_def: sp <> Vundef; + agree_mregs: forall r: mreg, Val.lessdef (ms r) (rs#(preg_of r)) +}. + +Lemma preg_val: + forall ms sp rs r, + agree ms sp rs -> Val.lessdef (ms r) rs#(preg_of r). +Proof. + intros. destruct H. auto. +Qed. + +Lemma preg_vals: + forall ms sp rs, agree ms sp rs -> + forall l, Val.lessdef_list (map ms l) (map rs (map preg_of l)). +Proof. + induction l; simpl. constructor. constructor. eapply preg_val; eauto. auto. +Qed. + +Lemma ireg_val: + forall ms sp rs r r', + agree ms sp rs -> + ireg_of r = OK r' -> + Val.lessdef (ms r) rs#r'. +Proof. + intros. rewrite <- (ireg_of_eq _ _ H0). eapply preg_val; eauto. +Qed. + +Lemma freg_val: + forall ms sp rs r r', + agree ms sp rs -> + freg_of r = OK r' -> + Val.lessdef (ms r) (rs#r'). +Proof. + intros. rewrite <- (freg_of_eq _ _ H0). eapply preg_val; eauto. +Qed. + +Lemma sp_val: + forall ms sp rs, + agree ms sp rs -> + sp = rs#ESP. +Proof. + intros. destruct H; auto. +Qed. + +Hint Resolve preg_val ireg_val freg_val sp_val: ppcgen. + +Definition important_preg (r: preg) : bool := + match r with + | PC => false + | IR _ => true + | FR _ => true + | ST0 => true + | CR _ => false + | RA => false + end. + +Lemma preg_of_important: + forall r, important_preg (preg_of r) = true. +Proof. + intros. destruct r; reflexivity. +Qed. + +Lemma important_diff: + forall r r', + important_preg r = true -> important_preg r' = false -> r <> r'. +Proof. + congruence. +Qed. +Hint Resolve important_diff: ppcgen. + +Lemma agree_exten: + forall ms sp rs rs', + agree ms sp rs -> + (forall r, important_preg r = true -> rs'#r = rs#r) -> + agree ms sp rs'. +Proof. + intros. destruct H. split. + rewrite H0; auto. auto. + intros. rewrite H0; auto. apply preg_of_important. +Qed. + +(** Preservation of register agreement under various assignments. *) + +Lemma agree_set_mreg: + forall ms sp rs r v rs', + agree ms sp rs -> + Val.lessdef v (rs'#(preg_of r)) -> + (forall r', important_preg r' = true -> r' <> preg_of r -> rs'#r' = rs#r') -> + agree (Regmap.set r v ms) sp rs'. +Proof. + intros. destruct H. split. + rewrite H1; auto. apply sym_not_equal. apply preg_of_not_ESP. + auto. + intros. unfold Regmap.set. destruct (RegEq.eq r0 r). congruence. + rewrite H1. auto. apply preg_of_important. + red; intros; elim n. eapply preg_of_injective; eauto. +Qed. + +Lemma agree_set_other: + forall ms sp rs r v, + agree ms sp rs -> + important_preg r = false -> + agree ms sp (rs#r <- v). +Proof. + intros. apply agree_exten with rs. auto. + intros. apply Pregmap.gso. congruence. +Qed. + +Lemma agree_nextinstr: + forall ms sp rs, + agree ms sp rs -> agree ms sp (nextinstr rs). +Proof. + intros. unfold nextinstr. apply agree_set_other. auto. auto. +Qed. + +Lemma agree_undef_unimportant_regs: + forall ms sp rl rs, + agree ms sp rs -> + (forall r, In r rl -> important_preg r = false) -> + agree ms sp (undef_regs rl rs). +Proof. + induction rl; simpl; intros. auto. + apply IHrl. apply agree_exten with rs; auto. + intros. apply Pregmap.gso. red; intros; subst. + assert (important_preg a = false) by auto. congruence. + intros. apply H0; auto. +Qed. + +Lemma agree_nextinstr_nf: + forall ms sp rs, + agree ms sp rs -> agree ms sp (nextinstr_nf rs). +Proof. + intros. unfold nextinstr_nf. apply agree_nextinstr. + apply agree_undef_unimportant_regs. auto. + intro. simpl. ElimOrEq; auto. +Qed. + +Definition nontemp_preg (r: preg) : bool := + match r with + | PC => false + | IR ECX => false + | IR EDX => false + | IR _ => true + | FR XMM6 => false + | FR XMM7 => false + | FR _ => true + | ST0 => false + | CR _ => false + | RA => false + end. + +Lemma nontemp_diff: + forall r r', + nontemp_preg r = true -> nontemp_preg r' = false -> r <> r'. +Proof. + congruence. +Qed. + +Hint Resolve nontemp_diff: ppcgen. + +Remark undef_regs_1: + forall l ms r, ms r = Vundef -> Mach.undef_regs l ms r = Vundef. +Proof. + induction l; simpl; intros. auto. apply IHl. unfold Regmap.set. + destruct (RegEq.eq r a); congruence. +Qed. + +Remark undef_regs_2: + forall l ms r, In r l -> Mach.undef_regs l ms r = Vundef. +Proof. + induction l; simpl; intros. contradiction. + destruct H. subst. apply undef_regs_1. apply Regmap.gss. + auto. +Qed. + +Remark undef_regs_3: + forall l ms r, ~In r l -> Mach.undef_regs l ms r = ms r. +Proof. + induction l; simpl; intros. auto. + rewrite IHl. apply Regmap.gso. intuition. intuition. +Qed. + +Lemma agree_exten_temps: + forall ms sp rs rs', + agree ms sp rs -> + (forall r, nontemp_preg r = true -> rs'#r = rs#r) -> + agree (undef_temps ms) sp rs'. +Proof. + intros. destruct H. split. + rewrite H0; auto. auto. + intros. unfold undef_temps. + destruct (In_dec mreg_eq r (int_temporaries ++ float_temporaries)). + rewrite undef_regs_2; auto. + rewrite undef_regs_3; auto. rewrite H0; auto. + simpl in n. destruct r; auto; intuition. +Qed. + +Lemma agree_set_undef_mreg: + forall ms sp rs r v rs', + agree ms sp rs -> + Val.lessdef v (rs'#(preg_of r)) -> + (forall r', nontemp_preg r' = true -> r' <> preg_of r -> rs'#r' = rs#r') -> + agree (Regmap.set r v (undef_temps ms)) sp rs'. +Proof. + intros. apply agree_set_mreg with (rs'#(preg_of r) <- (rs#(preg_of r))); auto. + eapply agree_exten_temps; eauto. + intros. unfold Pregmap.set. destruct (PregEq.eq r0 (preg_of r)). + congruence. auto. + intros. rewrite Pregmap.gso; auto. +Qed. + +(** Useful properties of the PC register. *) + +Lemma nextinstr_inv: + forall r rs, + r <> PC -> + (nextinstr rs)#r = rs#r. +Proof. + intros. unfold nextinstr. apply Pregmap.gso. red; intro; subst. auto. +Qed. + +Lemma nextinstr_inv2: + forall r rs, + nontemp_preg r = true -> + (nextinstr rs)#r = rs#r. +Proof. + intros. apply nextinstr_inv. red; intro; subst; discriminate. +Qed. + +Lemma nextinstr_set_preg: + forall rs m v, + (nextinstr (rs#(preg_of m) <- v))#PC = Val.add rs#PC Vone. +Proof. + intros. unfold nextinstr. rewrite Pregmap.gss. + rewrite Pregmap.gso. auto. apply sym_not_eq. apply preg_of_not_PC. +Qed. + +Lemma nextinstr_nf_inv: + forall r rs, + match r with PC => False | CR _ => False | _ => True end -> + (nextinstr_nf rs)#r = rs#r. +Proof. + intros. unfold nextinstr_nf. rewrite nextinstr_inv. + simpl. repeat rewrite Pregmap.gso; auto. + red; intro; subst; contradiction. + red; intro; subst; contradiction. + red; intro; subst; contradiction. + red; intro; subst; contradiction. + red; intro; subst; contradiction. +Qed. + +Lemma nextinstr_nf_inv1: + forall r rs, + important_preg r = true -> (nextinstr_nf rs)#r = rs#r. +Proof. + intros. apply nextinstr_nf_inv. unfold important_preg in H. + destruct r; auto; congruence. +Qed. + +Lemma nextinstr_nf_inv2: + forall r rs, + nontemp_preg r = true -> (nextinstr_nf rs)#r = rs#r. +Proof. + intros. apply nextinstr_nf_inv. unfold nontemp_preg in H. + destruct r; auto; congruence. +Qed. + +Lemma nextinstr_nf_set_preg: + forall rs m v, + (nextinstr_nf (rs#(preg_of m) <- v))#PC = Val.add rs#PC Vone. +Proof. + intros. unfold nextinstr_nf. + transitivity (nextinstr (rs#(preg_of m) <- v) PC). auto. + apply nextinstr_set_preg. +Qed. + +(** Connection between Mach and Asm calling conventions for external + functions. *) + +Lemma extcall_arg_match: + forall ms sp rs m m' l v, + agree ms sp rs -> + Machconcr.extcall_arg ms m sp l v -> + Mem.extends m m' -> + exists v', Asm.extcall_arg rs m' l v' /\ Val.lessdef v v'. +Proof. + intros. inv H0. + exists (rs#(preg_of r)); split. constructor. eauto with ppcgen. + unfold load_stack in H2. + exploit Mem.loadv_extends; eauto. intros [v' [A B]]. + rewrite (sp_val _ _ _ H) in A. + exists v'; split; auto. destruct ty; econstructor; eauto. +Qed. + +Lemma extcall_args_match: + forall ms sp rs m m', agree ms sp rs -> Mem.extends m m' -> + forall ll vl, + Machconcr.extcall_args ms m sp ll vl -> + exists vl', Asm.extcall_args rs m' ll vl' /\ Val.lessdef_list vl vl'. +Proof. + induction 3. + exists (@nil val); split; constructor. + exploit extcall_arg_match; eauto. intros [v1' [A B]]. + exploit IHextcall_args; eauto. intros [vl' [C D]]. + exists(v1' :: vl'); split. constructor; auto. constructor; auto. +Qed. + +Lemma extcall_arguments_match: + forall ms m sp rs sg args m', + agree ms sp rs -> + Machconcr.extcall_arguments ms m sp sg args -> + Mem.extends m m' -> + exists args', Asm.extcall_arguments rs m' sg args' /\ Val.lessdef_list args args'. +Proof. + unfold Machconcr.extcall_arguments, Asm.extcall_arguments; intros. + eapply extcall_args_match; eauto. +Qed. + +(** * Execution of straight-line code *) + +Section STRAIGHTLINE. + +Variable ge: genv. +Variable fn: code. + +(** Straight-line code is composed of processor instructions that execute + in sequence (no branches, no function calls and returns). + The following inductive predicate relates the machine states + before and after executing a straight-line sequence of instructions. + Instructions are taken from the first list instead of being fetched + from memory. *) + +Inductive exec_straight: code -> regset -> mem -> + code -> regset -> mem -> Prop := + | exec_straight_one: + forall i1 c rs1 m1 rs2 m2, + exec_instr ge fn i1 rs1 m1 = Next rs2 m2 -> + rs2#PC = Val.add rs1#PC Vone -> + exec_straight (i1 :: c) rs1 m1 c rs2 m2 + | exec_straight_step: + forall i c rs1 m1 rs2 m2 c' rs3 m3, + exec_instr ge fn i rs1 m1 = Next rs2 m2 -> + rs2#PC = Val.add rs1#PC Vone -> + exec_straight c rs2 m2 c' rs3 m3 -> + exec_straight (i :: c) rs1 m1 c' rs3 m3. + +Lemma exec_straight_trans: + forall c1 rs1 m1 c2 rs2 m2 c3 rs3 m3, + exec_straight c1 rs1 m1 c2 rs2 m2 -> + exec_straight c2 rs2 m2 c3 rs3 m3 -> + exec_straight c1 rs1 m1 c3 rs3 m3. +Proof. + induction 1; intros. + apply exec_straight_step with rs2 m2; auto. + apply exec_straight_step with rs2 m2; auto. +Qed. + +Lemma exec_straight_two: + forall i1 i2 c rs1 m1 rs2 m2 rs3 m3, + exec_instr ge fn i1 rs1 m1 = Next rs2 m2 -> + exec_instr ge fn i2 rs2 m2 = Next rs3 m3 -> + rs2#PC = Val.add rs1#PC Vone -> + rs3#PC = Val.add rs2#PC Vone -> + exec_straight (i1 :: i2 :: c) rs1 m1 c rs3 m3. +Proof. + intros. apply exec_straight_step with rs2 m2; auto. + apply exec_straight_one; auto. +Qed. + +Lemma exec_straight_three: + forall i1 i2 i3 c rs1 m1 rs2 m2 rs3 m3 rs4 m4, + exec_instr ge fn i1 rs1 m1 = Next rs2 m2 -> + exec_instr ge fn i2 rs2 m2 = Next rs3 m3 -> + exec_instr ge fn i3 rs3 m3 = Next rs4 m4 -> + rs2#PC = Val.add rs1#PC Vone -> + rs3#PC = Val.add rs2#PC Vone -> + rs4#PC = Val.add rs3#PC Vone -> + exec_straight (i1 :: i2 :: i3 :: c) rs1 m1 c rs4 m4. +Proof. + intros. apply exec_straight_step with rs2 m2; auto. + eapply exec_straight_two; eauto. +Qed. + +(** * Correctness of IA32 constructor functions *) + +(** Smart constructor for moves. *) + +Lemma mk_mov_correct: + forall rd rs k c rs1 m, + mk_mov rd rs k = OK c -> + exists rs2, + exec_straight c rs1 m k rs2 m + /\ rs2#rd = rs1#rs + /\ forall r, important_preg r = true -> r <> rd -> rs2#r = rs1#r. +Proof. + unfold mk_mov; intros. + destruct rd; try (monadInv H); destruct rs; monadInv H. +(* mov *) + econstructor. split. apply exec_straight_one. simpl. eauto. auto. + split. rewrite nextinstr_inv; auto with ppcgen. apply Pregmap.gss. + intros. rewrite nextinstr_inv; auto with ppcgen. apply Pregmap.gso. auto. +(* movd *) + econstructor. split. apply exec_straight_one. simpl. eauto. auto. + split. rewrite nextinstr_inv; auto with ppcgen. apply Pregmap.gss. + intros. rewrite nextinstr_inv; auto with ppcgen. apply Pregmap.gso. auto. +(* getfp0 *) + econstructor. split. apply exec_straight_one. simpl. eauto. auto. + split. rewrite nextinstr_inv; auto with ppcgen. apply Pregmap.gss. + intros. rewrite nextinstr_inv; auto with ppcgen. rewrite Pregmap.gso; auto. +(* setfp0 *) + econstructor. split. apply exec_straight_one. simpl. eauto. auto. + split. auto. + intros. rewrite nextinstr_inv; auto with ppcgen. apply Pregmap.gso. auto. +Qed. + +(** Smart constructor for shifts *) + +Ltac SRes := + match goal with + | [ |- nextinstr _ _ = _ ] => rewrite nextinstr_inv; [auto | auto with ppcgen] + | [ |- nextinstr_nf _ _ = _ ] => rewrite nextinstr_nf_inv; [auto | auto with ppcgen] + | [ |- Pregmap.get ?x (Pregmap.set ?x _ _) = _ ] => rewrite Pregmap.gss; auto + | [ |- Pregmap.set ?x _ _ ?x = _ ] => rewrite Pregmap.gss; auto + | [ |- Pregmap.get _ (Pregmap.set _ _ _) = _ ] => rewrite Pregmap.gso; [auto | auto with ppcgen] + | [ |- Pregmap.set _ _ _ _ = _ ] => rewrite Pregmap.gso; [auto | auto with ppcgen] + end. + +Ltac SOther := + match goal with + | [ |- nextinstr _ _ = _ ] => rewrite nextinstr_inv; [auto | auto with ppcgen] + | [ |- nextinstr_nf _ _ = _ ] => rewrite nextinstr_nf_inv2; [auto | auto with ppcgen] + | [ |- Pregmap.get ?x (Pregmap.set ?x _ _) = _ ] => rewrite Pregmap.gss; auto + | [ |- Pregmap.set ?x _ _ ?x = _ ] => rewrite Pregmap.gss; auto + | [ |- Pregmap.get _ (Pregmap.set _ _ _) = _ ] => rewrite Pregmap.gso; [auto | auto with ppcgen] + | [ |- Pregmap.set _ _ _ _ = _ ] => rewrite Pregmap.gso; [auto | auto with ppcgen] + end. + +Lemma mk_shift_correct: + forall sinstr ssem r1 r2 k c rs1 m, + mk_shift sinstr r1 r2 k = OK c -> + (forall r c rs m, + exec_instr ge c (sinstr r) rs m = Next (nextinstr_nf (rs#r <- (ssem rs#r rs#ECX))) m) -> + exists rs2, + exec_straight c rs1 m k rs2 m + /\ rs2#r1 = ssem rs1#r1 rs1#r2 + /\ forall r, nontemp_preg r = true -> r <> r1 -> rs2#r = rs1#r. +Proof. + unfold mk_shift; intros. + destruct (ireg_eq r2 ECX); monadInv H. +(* fast case *) + econstructor. split. apply exec_straight_one. apply H0. auto. + split. repeat SRes. + intros. repeat SOther. +(* general case *) + monadInv EQ. + econstructor. split. eapply exec_straight_two. simpl; eauto. apply H0. + auto. auto. + split. repeat SRes. repeat rewrite nextinstr_inv; auto with ppcgen. + rewrite Pregmap.gss. decEq. rewrite Pregmap.gso; auto. congruence. + intros. repeat SOther. +Qed. + +(** Smart constructor for division *) + + +Lemma mk_div_correct: + forall mkinstr dsem msem r1 r2 k c rs1 m, + mk_div mkinstr r1 r2 k = OK c -> + (forall r c rs m, + exec_instr ge c (mkinstr r) rs m = + Next (nextinstr_nf (rs#EAX <- (dsem rs#EAX (rs#EDX <- Vundef)#r) + #EDX <- (msem rs#EAX (rs#EDX <- Vundef)#r))) m) -> + exists rs2, + exec_straight c rs1 m k rs2 m + /\ rs2#r1 = dsem rs1#r1 rs1#r2 + /\ forall r, nontemp_preg r = true -> r <> r1 -> rs2#r = rs1#r. +Proof. + unfold mk_div; intros. + destruct (ireg_eq r1 EAX). destruct (ireg_eq r2 EDX); monadInv H. +(* r1=EAX r2=EDX *) + econstructor. split. eapply exec_straight_two. simpl; eauto. apply H0. auto. auto. + split. SRes. + intros. repeat SOther. +(* r1=EAX r2<>EDX *) + econstructor. split. eapply exec_straight_one. apply H0. auto. + split. repeat SRes. decEq. apply Pregmap.gso. congruence. + intros. repeat SOther. +(* r1 <> EAX *) + monadInv H. monadInv EQ. destruct (ireg_eq r2 EAX); monadInv EQ0. +(* r1 <> EAX, r1 <> ECX, r2 = EAX *) + set (rs2 := nextinstr (rs1#ECX <- (rs1#EAX))). + set (rs3 := nextinstr (rs2#EAX <- (rs2#r1))). + set (rs4 := nextinstr_nf (rs3#EAX <- (dsem rs3#EAX (rs3#EDX <- Vundef)#ECX) + #EDX <- (msem rs3#EAX (rs3#EDX <- Vundef)#ECX))). + set (rs5 := nextinstr (rs4#r1 <- (rs4#EAX))). + set (rs6 := nextinstr (rs5#EAX <- (rs5#ECX))). + exists rs6. split. apply exec_straight_step with rs2 m; auto. + apply exec_straight_step with rs3 m; auto. + apply exec_straight_step with rs4 m; auto. apply H0. + apply exec_straight_step with rs5 m; auto. + apply exec_straight_one; auto. + split. unfold rs6. SRes. unfold rs5. repeat SRes. + unfold rs4. repeat SRes. decEq. + unfold rs3. repeat SRes. unfold rs2. repeat SRes. + intros. unfold rs6. SOther. + unfold Pregmap.set. destruct (PregEq.eq r EAX). subst r. + unfold rs5. repeat SOther. + unfold rs5. repeat SOther. unfold rs4. repeat SOther. + unfold rs3. repeat SOther. unfold rs2. repeat SOther. +(* r1 <> EAX, r1 <> ECX, r2 <> EAX *) + set (rs2 := nextinstr (rs1#XMM7 <- (rs1#EAX))). + set (rs3 := nextinstr (rs2#ECX <- (rs2#r2))). + set (rs4 := nextinstr (rs3#EAX <- (rs3#r1))). + set (rs5 := nextinstr_nf (rs4#EAX <- (dsem rs4#EAX (rs4#EDX <- Vundef)#ECX) + #EDX <- (msem rs4#EAX (rs4#EDX <- Vundef)#ECX))). + set (rs6 := nextinstr (rs5#r2 <- (rs5#ECX))). + set (rs7 := nextinstr (rs6#r1 <- (rs6#EAX))). + set (rs8 := nextinstr (rs7#EAX <- (rs7#XMM7))). + exists rs8. split. apply exec_straight_step with rs2 m; auto. + apply exec_straight_step with rs3 m; auto. + apply exec_straight_step with rs4 m; auto. + apply exec_straight_step with rs5 m; auto. apply H0. + apply exec_straight_step with rs6 m; auto. + apply exec_straight_step with rs7 m; auto. + apply exec_straight_one; auto. + split. unfold rs8. SRes. unfold rs7. repeat SRes. + unfold rs6. repeat SRes. unfold rs5. repeat SRes. + decEq. unfold rs4. repeat SRes. unfold rs3. repeat SRes. + intros. unfold rs8. SOther. + unfold Pregmap.set. destruct (PregEq.eq r EAX). subst r. auto. + unfold rs7. repeat SOther. unfold rs6. SOther. + unfold Pregmap.set. destruct (PregEq.eq r r2). subst r. auto. + unfold rs5. repeat SOther. unfold rs4. repeat SOther. + unfold rs3. repeat SOther. unfold rs2. repeat SOther. +Qed. + +(** Smart constructor for modulus *) + +Lemma mk_mod_correct: + forall mkinstr dsem msem r1 r2 k c rs1 m, + mk_mod mkinstr r1 r2 k = OK c -> + (forall r c rs m, + exec_instr ge c (mkinstr r) rs m = + Next (nextinstr_nf (rs#EAX <- (dsem rs#EAX (rs#EDX <- Vundef)#r) + #EDX <- (msem rs#EAX (rs#EDX <- Vundef)#r))) m) -> + exists rs2, + exec_straight c rs1 m k rs2 m + /\ rs2#r1 = msem rs1#r1 rs1#r2 + /\ forall r, nontemp_preg r = true -> r <> r1 -> rs2#r = rs1#r. +Proof. + unfold mk_mod; intros. + destruct (ireg_eq r1 EAX). destruct (ireg_eq r2 EDX); monadInv H. +(* r1=EAX r2=EDX *) + econstructor. split. eapply exec_straight_three. + simpl; eauto. apply H0. simpl; eauto. auto. auto. auto. + split. SRes. + intros. repeat SOther. +(* r1=EAX r2<>EDX *) + econstructor. split. eapply exec_straight_two. apply H0. simpl; eauto. auto. auto. + split. repeat SRes. decEq. apply Pregmap.gso. congruence. + intros. repeat SOther. +(* r1 <> EAX *) + monadInv H. monadInv EQ. destruct (ireg_eq r2 EDX); monadInv EQ0. +(* r1 <> EAX, r1 <> ECX, r2 = EDX *) + set (rs2 := nextinstr (rs1#XMM7 <- (rs1#EAX))). + set (rs3 := nextinstr (rs2#ECX <- (rs2#EDX))). + set (rs4 := nextinstr (rs3#EAX <- (rs3#r1))). + set (rs5 := nextinstr_nf (rs4#EAX <- (dsem rs4#EAX (rs4#EDX <- Vundef)#ECX) + #EDX <- (msem rs4#EAX (rs4#EDX <- Vundef)#ECX))). + set (rs6 := nextinstr (rs5#r1 <- (rs5#EDX))). + set (rs7 := nextinstr (rs6#EAX <- (rs6#XMM7))). + exists rs7. split. apply exec_straight_step with rs2 m; auto. + apply exec_straight_step with rs3 m; auto. + apply exec_straight_step with rs4 m; auto. + apply exec_straight_step with rs5 m; auto. apply H0. + apply exec_straight_step with rs6 m; auto. + apply exec_straight_one; auto. + split. unfold rs7. repeat SRes. unfold rs6. repeat SRes. + unfold rs5. repeat SRes. decEq. + unfold rs4. repeat SRes. unfold rs3. repeat SRes. + intros. unfold rs7. SOther. + unfold Pregmap.set. destruct (PregEq.eq r EAX). subst r. + unfold rs6. repeat SOther. + unfold rs6. repeat SOther. + unfold rs5. repeat SOther. unfold rs4. repeat SOther. + unfold rs3. repeat SOther. unfold rs2. repeat SOther. +(* r1 <> EAX, r1 <> ECX, r2 <> EDX *) + set (rs2 := nextinstr (rs1#XMM7 <- (rs1#EAX))). + set (rs3 := nextinstr (rs2#ECX <- (rs2#r2))). + set (rs4 := nextinstr (rs3#EAX <- (rs3#r1))). + set (rs5 := nextinstr_nf (rs4#EAX <- (dsem rs4#EAX (rs4#EDX <- Vundef)#ECX) + #EDX <- (msem rs4#EAX (rs4#EDX <- Vundef)#ECX))). + set (rs6 := nextinstr (rs5#r2 <- (rs5#ECX))). + set (rs7 := nextinstr (rs6#r1 <- (rs6#EDX))). + set (rs8 := nextinstr (rs7#EAX <- (rs7#XMM7))). + exists rs8. split. apply exec_straight_step with rs2 m; auto. + apply exec_straight_step with rs3 m; auto. + apply exec_straight_step with rs4 m; auto. + apply exec_straight_step with rs5 m; auto. apply H0. + apply exec_straight_step with rs6 m; auto. + apply exec_straight_step with rs7 m; auto. + apply exec_straight_one; auto. + split. unfold rs8. SRes. unfold rs7. repeat SRes. + unfold rs6. repeat SRes. unfold rs5. repeat SRes. + decEq. unfold rs4. repeat SRes. unfold rs3. repeat SRes. + intros. unfold rs8. SOther. + unfold Pregmap.set. destruct (PregEq.eq r EAX). subst r. auto. + unfold rs7. repeat SOther. unfold rs6. SOther. + unfold Pregmap.set. destruct (PregEq.eq r r2). subst r. auto. + unfold rs5. repeat SOther. unfold rs4. repeat SOther. + unfold rs3. repeat SOther. unfold rs2. repeat SOther. +Qed. + +(** Smart constructor for [shrx] *) + +Lemma mk_shrximm_correct: + forall r1 n k c (rs1: regset) x m, + mk_shrximm r1 n k = OK c -> + rs1#r1 = Vint x -> + Int.ltu n (Int.repr 31) = true -> + exists rs2, + exec_straight c rs1 m k rs2 m + /\ rs2#r1 = Vint (Int.shrx x n) + /\ forall r, nontemp_preg r = true -> r <> r1 -> rs2#r = rs1#r. +Proof. + unfold mk_shrximm; intros. monadInv H. monadInv EQ. + rewrite Int.shrx_shr; auto. + set (tnm1 := Int.sub (Int.shl Int.one n) Int.one). + set (x' := Int.add x tnm1). + set (rs2 := nextinstr (compare_ints (Vint x) (Vint Int.zero) rs1)). + set (rs3 := nextinstr (rs2#ECX <- (Vint x'))). + set (rs4 := nextinstr (if Int.lt x Int.zero then rs3#r1 <- (Vint x') else rs3)). + set (rs5 := nextinstr_nf (rs4#r1 <- (Val.shr rs4#r1 (Vint n)))). + assert (rs3#r1 = Vint x). unfold rs3. SRes. SRes. + exists rs5. split. + apply exec_straight_step with rs2 m. simpl. rewrite H0. simpl. rewrite Int.and_idem. auto. auto. + apply exec_straight_step with rs3 m. simpl. + change (rs2 r1) with (rs1 r1). rewrite H0. simpl. + rewrite (Int.add_commut Int.zero tnm1). rewrite Int.add_zero. auto. auto. + apply exec_straight_step with rs4 m. simpl. + change (rs3 SOF) with (rs2 SOF). unfold rs2. rewrite nextinstr_inv; auto with ppcgen. + unfold compare_ints. rewrite Pregmap.gso; auto with ppcgen. rewrite Pregmap.gss. + simpl. unfold rs4. destruct (Int.lt x Int.zero); auto. + unfold rs4. destruct (Int.lt x Int.zero); auto. + apply exec_straight_one. auto. auto. + split. unfold rs5. SRes. SRes. unfold rs4. rewrite nextinstr_inv; auto with ppcgen. + assert (Int.ltu n Int.iwordsize = true). + unfold Int.ltu in *. change (Int.unsigned (Int.repr 31)) with 31 in H1. + destruct (zlt (Int.unsigned n) 31); try discriminate. + change (Int.unsigned Int.iwordsize) with 32. apply zlt_true. omega. + destruct (Int.lt x Int.zero). rewrite Pregmap.gss. unfold Val.shr. rewrite H2. auto. + rewrite H. unfold Val.shr. rewrite H2. auto. + intros. unfold rs5. repeat SOther. unfold rs4. SOther. + transitivity (rs3#r). destruct (Int.lt x Int.zero). SOther. auto. + unfold rs3. repeat SOther. unfold rs2. repeat SOther. + unfold compare_ints. repeat SOther. +Qed. + +(** Smart constructor for integer conversions *) + +Lemma mk_intconv_correct: + forall mk sem rd rs k c rs1 m, + mk_intconv mk rd rs k = OK c -> + (forall c rd rs r m, + exec_instr ge c (mk rd rs) r m = Next (nextinstr (r#rd <- (sem r#rs))) m) -> + exists rs2, + exec_straight c rs1 m k rs2 m + /\ rs2#rd = sem rs1#rs + /\ forall r, nontemp_preg r = true -> r <> rd -> rs2#r = rs1#r. +Proof. + unfold mk_intconv; intros. destruct (low_ireg rs); monadInv H. + econstructor. split. apply exec_straight_one. rewrite H0. eauto. auto. + split. repeat SRes. + intros. repeat SOther. + econstructor. split. eapply exec_straight_two. + simpl. eauto. apply H0. auto. auto. + split. repeat SRes. + intros. repeat SOther. +Qed. + +(** Smart constructor for small stores *) + +Lemma mk_smallstore_correct: + forall chunk sto addr r k c rs1 m1 m2, + mk_smallstore sto addr r k = OK c -> + Mem.storev chunk m1 (eval_addrmode ge addr rs1) (rs1 r) = Some m2 -> + (forall c r addr rs m, + exec_instr ge c (sto addr r) rs m = exec_store ge chunk m addr rs r) -> + exists rs2, + exec_straight c rs1 m1 k rs2 m2 + /\ forall r, nontemp_preg r = true -> rs2#r = rs1#r. +Proof. + unfold mk_smallstore; intros. + remember (low_ireg r) as low. destruct low; monadInv H. +(* low reg *) + econstructor; split. apply exec_straight_one. rewrite H1. + unfold exec_store. rewrite H0. eauto. auto. + intros. SOther. +(* high reg *) + assert (r <> ECX). red; intros; subst r; discriminate. + set (rs2 := nextinstr (rs1#ECX <- (eval_addrmode ge addr rs1))). + set (rs3 := nextinstr (rs2#EDX <- (rs1 r))). + econstructor; split. + apply exec_straight_three with rs2 m1 rs3 m1. + simpl. auto. + simpl. replace (rs2 r) with (rs1 r). auto. symmetry. unfold rs2. repeat SRes. + rewrite H1. unfold exec_store. simpl. rewrite Int.add_zero. + change (rs3 EDX) with (rs1 r). + change (rs3 ECX) with (eval_addrmode ge addr rs1). + replace (Val.add (eval_addrmode ge addr rs1) (Vint Int.zero)) + with (eval_addrmode ge addr rs1). + rewrite H0. eauto. + destruct (eval_addrmode ge addr rs1); simpl in H0; try discriminate. + simpl. rewrite Int.add_zero; auto. + auto. auto. auto. + intros. repeat SOther. unfold rs3. repeat SOther. unfold rs2. repeat SOther. +Qed. + +(** Accessing slots in the stack frame *) + +Lemma loadind_correct: + forall (base: ireg) ofs ty dst k (rs: regset) c m v, + loadind base ofs ty dst k = OK c -> + Mem.loadv (chunk_of_type ty) m (Val.add rs#base (Vint ofs)) = Some v -> + exists rs', + exec_straight c rs m k rs' m + /\ rs'#(preg_of dst) = v + /\ forall r, important_preg r = true -> r <> preg_of dst -> rs'#r = rs#r. +Proof. + unfold loadind; intros. + set (addr := Addrmode (Some base) None (inl (ident * int) ofs)) in *. + assert (eval_addrmode ge addr rs = Val.add rs#base (Vint ofs)). + unfold addr. simpl. rewrite Int.add_commut; rewrite Int.add_zero; auto. + destruct ty; simpl in H0. + (* int *) + monadInv H. + rewrite (ireg_of_eq _ _ EQ). econstructor. + split. apply exec_straight_one. simpl. unfold exec_load. rewrite H1. rewrite H0. + eauto. auto. + split. repeat SRes. + intros. rewrite nextinstr_nf_inv1; auto. SOther. + (* float *) + exists (nextinstr_nf (rs#(preg_of dst) <- v)). + split. destruct (preg_of dst); inv H; apply exec_straight_one; simpl; auto. + unfold exec_load. rewrite H1; rewrite H0; auto. + unfold exec_load. rewrite H1; rewrite H0; auto. + split. rewrite nextinstr_nf_inv1. SRes. apply preg_of_important. + intros. rewrite nextinstr_nf_inv1; auto. SOther. +Qed. + +Lemma storeind_correct: + forall (base: ireg) ofs ty src k (rs: regset) c m m', + storeind src base ofs ty k = OK c -> + Mem.storev (chunk_of_type ty) m (Val.add rs#base (Vint ofs)) (rs#(preg_of src)) = Some m' -> + exists rs', + exec_straight c rs m k rs' m' + /\ forall r, important_preg r = true -> rs'#r = rs#r. +Proof. + unfold storeind; intros. + set (addr := Addrmode (Some base) None (inl (ident * int) ofs)) in *. + assert (eval_addrmode ge addr rs = Val.add rs#base (Vint ofs)). + unfold addr. simpl. rewrite Int.add_commut; rewrite Int.add_zero; auto. + destruct ty; simpl in H0. + (* int *) + monadInv H. + rewrite (ireg_of_eq _ _ EQ) in H0. econstructor. + split. apply exec_straight_one. simpl. unfold exec_store. rewrite H1. rewrite H0. + eauto. auto. + intros. apply nextinstr_nf_inv1; auto. + (* float *) + destruct (preg_of src); inv H. + econstructor; split. apply exec_straight_one. + simpl. unfold exec_store. rewrite H1; rewrite H0. eauto. auto. + intros. apply nextinstr_nf_inv1; auto. + econstructor; split. apply exec_straight_one. + simpl. unfold exec_store. rewrite H1; rewrite H0. eauto. auto. + intros. apply nextinstr_nf_inv1; auto. +Qed. + +(** Translation of addressing modes *) + +Lemma transl_addressing_mode_correct: + forall addr args am (rs: regset) v, + transl_addressing addr args = OK am -> + eval_addressing ge (rs ESP) addr (List.map rs (List.map preg_of args)) = Some v -> + eval_addrmode ge am rs = v. +Proof. + assert (A: forall n, Int.add Int.zero n = n). + intros. rewrite Int.add_commut. apply Int.add_zero. + assert (B: forall n i, (if Int.eq i Int.one then Vint n else Vint (Int.mul n i)) = Vint (Int.mul n i)). + intros. generalize (Int.eq_spec i Int.one); destruct (Int.eq i Int.one); intros. + subst i. rewrite Int.mul_one. auto. auto. + unfold transl_addressing; intros. + destruct addr; repeat (destruct args; try discriminate); simpl in H0. +(* indexed *) + monadInv H. rewrite (ireg_of_eq _ _ EQ) in H0. simpl. + destruct (rs x); inv H0; simpl. rewrite A; auto. rewrite A; auto. +(* indexed2 *) + monadInv H. rewrite (ireg_of_eq _ _ EQ) in H0; rewrite (ireg_of_eq _ _ EQ1) in H0. simpl. + destruct (rs x); try discriminate; destruct (rs x0); inv H0; simpl. + rewrite Int.add_assoc; auto. + repeat rewrite Int.add_assoc. decEq. decEq. apply Int.add_commut. + rewrite Int.add_assoc; auto. +(* scaled *) + monadInv H. rewrite (ireg_of_eq _ _ EQ) in H0. simpl. + destruct (rs x); inv H0; simpl. + rewrite B. simpl. rewrite A. auto. +(* indexed2scaled *) + monadInv H. rewrite (ireg_of_eq _ _ EQ) in H0; rewrite (ireg_of_eq _ _ EQ1) in H0. simpl. + destruct (rs x); try discriminate; destruct (rs x0); inv H0; simpl. + rewrite B. simpl. auto. + rewrite B. simpl. auto. +(* global *) + inv H. simpl. unfold symbol_offset. destruct (Genv.find_symbol ge i); inv H0. + repeat rewrite Int.add_zero. auto. +(* based *) + monadInv H. rewrite (ireg_of_eq _ _ EQ) in H0. simpl. + destruct (rs x); inv H0; simpl. + unfold symbol_offset. destruct (Genv.find_symbol ge i); inv H1. + rewrite Int.add_zero; auto. +(* basedscaled *) + monadInv H. rewrite (ireg_of_eq _ _ EQ) in H0. simpl. + destruct (rs x); inv H0; simpl. + rewrite B. unfold symbol_offset. destruct (Genv.find_symbol ge i0); inv H1. + simpl. rewrite Int.add_zero. auto. +(* instack *) + inv H; simpl. unfold offset_sp in H0. + destruct (rs ESP); inv H0. simpl. rewrite A; auto. +Qed. + +(** Processor conditions and comparisons *) + +Lemma compare_ints_spec: + forall rs v1 v2, + let rs' := nextinstr (compare_ints v1 v2 rs) in + rs'#ZF = Val.cmp Ceq v1 v2 + /\ rs'#CF = Val.cmpu Clt v1 v2 + /\ rs'#SOF = Val.cmp Clt v1 v2 + /\ (forall r, nontemp_preg r = true -> rs'#r = rs#r). +Proof. + intros. unfold rs'; unfold compare_ints. + split. auto. + split. auto. + split. auto. + intros. repeat SOther. +Qed. + +Lemma int_signed_eq: + forall x y, Int.eq x y = zeq (Int.signed x) (Int.signed y). +Proof. + intros. unfold Int.eq. unfold proj_sumbool. + destruct (zeq (Int.unsigned x) (Int.unsigned y)); + destruct (zeq (Int.signed x) (Int.signed y)); auto. + elim n. unfold Int.signed. rewrite e; auto. + elim n. apply Int.eqm_small_eq; auto with ints. + eapply Int.eqm_trans. apply Int.eqm_sym. apply Int.eqm_signed_unsigned. + rewrite e. apply Int.eqm_signed_unsigned. +Qed. + +Lemma int_not_lt: + forall x y, negb (Int.lt y x) = (Int.lt x y || Int.eq x y). +Proof. + intros. unfold Int.lt. rewrite int_signed_eq. unfold proj_sumbool. + destruct (zlt (Int.signed y) (Int.signed x)). + rewrite zlt_false. rewrite zeq_false. auto. omega. omega. + destruct (zeq (Int.signed x) (Int.signed y)). + rewrite zlt_false. auto. omega. + rewrite zlt_true. auto. omega. +Qed. + +Lemma int_lt_not: + forall x y, Int.lt y x = negb (Int.lt x y) && negb (Int.eq x y). +Proof. + intros. rewrite <- negb_orb. rewrite <- int_not_lt. rewrite negb_involutive. auto. +Qed. + +Lemma int_not_ltu: + forall x y, negb (Int.ltu y x) = (Int.ltu x y || Int.eq x y). +Proof. + intros. unfold Int.ltu, Int.eq. + destruct (zlt (Int.unsigned y) (Int.unsigned x)). + rewrite zlt_false. rewrite zeq_false. auto. omega. omega. + destruct (zeq (Int.unsigned x) (Int.unsigned y)). + rewrite zlt_false. auto. omega. + rewrite zlt_true. auto. omega. +Qed. + +Lemma int_ltu_not: + forall x y, Int.ltu y x = negb (Int.ltu x y) && negb (Int.eq x y). +Proof. + intros. rewrite <- negb_orb. rewrite <- int_not_ltu. rewrite negb_involutive. auto. +Qed. + +Lemma testcond_for_signed_comparison_correct_ii: + forall c n1 n2 rs, + eval_testcond (testcond_for_signed_comparison c) + (nextinstr (compare_ints (Vint n1) (Vint n2) rs)) = + Some(Int.cmp c n1 n2). +Proof. + intros. generalize (compare_ints_spec rs (Vint n1) (Vint n2)). + set (rs' := nextinstr (compare_ints (Vint n1) (Vint n2) rs)). + intros [A [B [C D]]]. + unfold eval_testcond. rewrite A; rewrite B; rewrite C. + destruct c; simpl. + destruct (Int.eq n1 n2); auto. + destruct (Int.eq n1 n2); auto. + destruct (Int.lt n1 n2); auto. + rewrite int_not_lt. destruct (Int.lt n1 n2); destruct (Int.eq n1 n2); auto. + rewrite (int_lt_not n1 n2). destruct (Int.lt n1 n2); destruct (Int.eq n1 n2); auto. + destruct (Int.lt n1 n2); auto. +Qed. + +Lemma testcond_for_signed_comparison_correct_pi: + forall c blk n1 n2 rs b, + eval_compare_null c n2 = Some b -> + eval_testcond (testcond_for_signed_comparison c) + (nextinstr (compare_ints (Vptr blk n1) (Vint n2) rs)) = Some b. +Proof. + intros. + revert H. unfold eval_compare_null. + generalize (Int.eq_spec n2 Int.zero); destruct (Int.eq n2 Int.zero); intros; try discriminate. + subst n2. + generalize (compare_ints_spec rs (Vptr blk n1) (Vint Int.zero)). + set (rs' := nextinstr (compare_ints (Vptr blk n1) (Vint Int.zero) rs)). + intros [A [B [C D]]]. + unfold eval_testcond. rewrite A; rewrite B; rewrite C. + destruct c; simpl; try discriminate. + rewrite <- H0; auto. + rewrite <- H0; auto. +Qed. + +Lemma testcond_for_signed_comparison_correct_ip: + forall c blk n1 n2 rs b, + eval_compare_null c n1 = Some b -> + eval_testcond (testcond_for_signed_comparison c) + (nextinstr (compare_ints (Vint n1) (Vptr blk n2) rs)) = Some b. +Proof. + intros. + revert H. unfold eval_compare_null. + generalize (Int.eq_spec n1 Int.zero); destruct (Int.eq n1 Int.zero); intros; try discriminate. + subst n1. + generalize (compare_ints_spec rs (Vint Int.zero) (Vptr blk n2)). + set (rs' := nextinstr (compare_ints (Vint Int.zero) (Vptr blk n2) rs)). + intros [A [B [C D]]]. + unfold eval_testcond. rewrite A; rewrite B; rewrite C. + destruct c; simpl; try discriminate. + rewrite <- H0; auto. + rewrite <- H0; auto. +Qed. + +Lemma testcond_for_signed_comparison_correct_pp: + forall c b1 n1 b2 n2 rs b, + (if eq_block b1 b2 then Some (Int.cmp c n1 n2) else eval_compare_mismatch c) = Some b -> + eval_testcond (testcond_for_signed_comparison c) + (nextinstr (compare_ints (Vptr b1 n1) (Vptr b2 n2) rs)) = + Some b. +Proof. + intros. generalize (compare_ints_spec rs (Vptr b1 n1) (Vptr b2 n2)). + set (rs' := nextinstr (compare_ints (Vptr b1 n1) (Vptr b2 n2) rs)). + intros [A [B [C D]]]. unfold eq_block in H. + unfold eval_testcond. rewrite A; rewrite B; rewrite C. + destruct c; simpl. + destruct (zeq b1 b2). inversion H. destruct (Int.eq n1 n2); auto. + rewrite <- H; auto. + destruct (zeq b1 b2). inversion H. destruct (Int.eq n1 n2); auto. + rewrite <- H; auto. + destruct (zeq b1 b2). inversion H. destruct (Int.lt n1 n2); auto. + discriminate. + destruct (zeq b1 b2). inversion H. + rewrite int_not_lt. destruct (Int.lt n1 n2); destruct (Int.eq n1 n2); auto. + discriminate. + destruct (zeq b1 b2). inversion H. + rewrite (int_lt_not n1 n2). destruct (Int.lt n1 n2); destruct (Int.eq n1 n2); auto. + discriminate. + destruct (zeq b1 b2). inversion H. destruct (Int.lt n1 n2); auto. + discriminate. +Qed. + +Lemma testcond_for_unsigned_comparison_correct: + forall c n1 n2 rs, + eval_testcond (testcond_for_unsigned_comparison c) + (nextinstr (compare_ints (Vint n1) (Vint n2) rs)) = + Some(Int.cmpu c n1 n2). +Proof. + intros. generalize (compare_ints_spec rs (Vint n1) (Vint n2)). + set (rs' := nextinstr (compare_ints (Vint n1) (Vint n2) rs)). + intros [A [B [C D]]]. + unfold eval_testcond. rewrite A; rewrite B; rewrite C. + destruct c; simpl. + destruct (Int.eq n1 n2); auto. + destruct (Int.eq n1 n2); auto. + destruct (Int.ltu n1 n2); auto. + rewrite int_not_ltu. destruct (Int.ltu n1 n2); destruct (Int.eq n1 n2); auto. + rewrite (int_ltu_not n1 n2). destruct (Int.ltu n1 n2); destruct (Int.eq n1 n2); auto. + destruct (Int.ltu n1 n2); auto. +Qed. + +Lemma compare_floats_spec: + forall rs n1 n2, + let rs' := nextinstr (compare_floats (Vfloat n1) (Vfloat n2) rs) in + rs'#ZF = Val.of_bool (negb (Float.cmp Cne n1 n2)) + /\ rs'#CF = Val.of_bool (negb (Float.cmp Cge n1 n2)) + /\ rs'#PF = Val.of_bool (negb (Float.cmp Ceq n1 n2 || Float.cmp Clt n1 n2 || Float.cmp Cgt n1 n2)) + /\ (forall r, nontemp_preg r = true -> rs'#r = rs#r). +Proof. + intros. unfold rs'; unfold compare_floats. + split. auto. + split. auto. + split. auto. + intros. repeat SOther. +Qed. + +Definition swap_floats (c: comparison) (n1 n2: float) : float := + match c with + | Clt | Cle => n2 + | Ceq | Cne | Cgt | Cge => n1 + end. + +Lemma testcond_for_float_comparison_correct: + forall c n1 n2 rs, + eval_testcond (testcond_for_condition (Ccompf c)) + (nextinstr (compare_floats (Vfloat (swap_floats c n1 n2)) + (Vfloat (swap_floats c n2 n1)) rs)) = + Some(Float.cmp c n1 n2). +Proof. + intros. + generalize (compare_floats_spec rs (swap_floats c n1 n2) (swap_floats c n2 n1)). + set (rs' := nextinstr (compare_floats (Vfloat (swap_floats c n1 n2)) + (Vfloat (swap_floats c n2 n1)) rs)). + intros [A [B [C D]]]. + unfold eval_testcond. rewrite A; rewrite B; rewrite C. + destruct c; simpl. +(* eq *) + rewrite Float.cmp_ne_eq. + caseEq (Float.cmp Ceq n1 n2); intros. + auto. + simpl. destruct (Float.cmp Clt n1 n2 || Float.cmp Cgt n1 n2); auto. +(* ne *) + rewrite Float.cmp_ne_eq. + caseEq (Float.cmp Ceq n1 n2); intros. + auto. + simpl. destruct (Float.cmp Clt n1 n2 || Float.cmp Cgt n1 n2); auto. +(* lt *) + rewrite <- (Float.cmp_swap Cge n1 n2). + rewrite <- (Float.cmp_swap Cne n1 n2). + simpl. + rewrite Float.cmp_ne_eq. rewrite Float.cmp_le_lt_eq. + caseEq (Float.cmp Clt n1 n2); intros; simpl. + caseEq (Float.cmp Ceq n1 n2); intros; simpl. + elimtype False. eapply Float.cmp_lt_eq_false; eauto. + auto. + destruct (Float.cmp Ceq n1 n2); auto. +(* le *) + rewrite <- (Float.cmp_swap Cge n1 n2). simpl. + destruct (Float.cmp Cle n1 n2); auto. +(* gt *) + rewrite Float.cmp_ne_eq. rewrite Float.cmp_ge_gt_eq. + caseEq (Float.cmp Cgt n1 n2); intros; simpl. + caseEq (Float.cmp Ceq n1 n2); intros; simpl. + elimtype False. eapply Float.cmp_gt_eq_false; eauto. + auto. + destruct (Float.cmp Ceq n1 n2); auto. +(* ge *) + destruct (Float.cmp Cge n1 n2); auto. +Qed. + +Lemma testcond_for_neg_float_comparison_correct: + forall c n1 n2 rs, + eval_testcond (testcond_for_condition (Cnotcompf c)) + (nextinstr (compare_floats (Vfloat (swap_floats c n1 n2)) + (Vfloat (swap_floats c n2 n1)) rs)) = + Some(negb(Float.cmp c n1 n2)). +Proof. + intros. + generalize (compare_floats_spec rs (swap_floats c n1 n2) (swap_floats c n2 n1)). + set (rs' := nextinstr (compare_floats (Vfloat (swap_floats c n1 n2)) + (Vfloat (swap_floats c n2 n1)) rs)). + intros [A [B [C D]]]. + unfold eval_testcond. rewrite A; rewrite B; rewrite C. + destruct c; simpl. +(* eq *) + rewrite Float.cmp_ne_eq. + caseEq (Float.cmp Ceq n1 n2); intros. + auto. + simpl. destruct (Float.cmp Clt n1 n2 || Float.cmp Cgt n1 n2); auto. +(* ne *) + rewrite Float.cmp_ne_eq. + caseEq (Float.cmp Ceq n1 n2); intros. + auto. + simpl. destruct (Float.cmp Clt n1 n2 || Float.cmp Cgt n1 n2); auto. +(* lt *) + rewrite <- (Float.cmp_swap Cge n1 n2). + rewrite <- (Float.cmp_swap Cne n1 n2). + simpl. + rewrite Float.cmp_ne_eq. rewrite Float.cmp_le_lt_eq. + caseEq (Float.cmp Clt n1 n2); intros; simpl. + caseEq (Float.cmp Ceq n1 n2); intros; simpl. + elimtype False. eapply Float.cmp_lt_eq_false; eauto. + auto. + destruct (Float.cmp Ceq n1 n2); auto. +(* le *) + rewrite <- (Float.cmp_swap Cge n1 n2). simpl. + destruct (Float.cmp Cle n1 n2); auto. +(* gt *) + rewrite Float.cmp_ne_eq. rewrite Float.cmp_ge_gt_eq. + caseEq (Float.cmp Cgt n1 n2); intros; simpl. + caseEq (Float.cmp Ceq n1 n2); intros; simpl. + elimtype False. eapply Float.cmp_gt_eq_false; eauto. + auto. + destruct (Float.cmp Ceq n1 n2); auto. +(* ge *) + destruct (Float.cmp Cge n1 n2); auto. +Qed. + +Lemma transl_cond_correct: + forall cond args k c rs m b, + transl_cond cond args k = OK c -> + eval_condition cond (map rs (map preg_of args)) = Some b -> + exists rs', + exec_straight c rs m k rs' m + /\ eval_testcond (testcond_for_condition cond) rs' = Some b + /\ forall r, nontemp_preg r = true -> rs'#r = rs r. +Proof. + unfold transl_cond; intros. + destruct cond; repeat (destruct args; try discriminate); monadInv H. +(* comp *) + simpl map in H0. rewrite (ireg_of_eq _ _ EQ) in H0. rewrite (ireg_of_eq _ _ EQ1) in H0. + econstructor. split. apply exec_straight_one. simpl. eauto. auto. + split. simpl in H0. FuncInv. + subst b. apply testcond_for_signed_comparison_correct_ii. + apply testcond_for_signed_comparison_correct_ip; auto. + apply testcond_for_signed_comparison_correct_pi; auto. + apply testcond_for_signed_comparison_correct_pp; auto. + intros. unfold compare_ints. repeat SOther. +(* compu *) + simpl map in H0. rewrite (ireg_of_eq _ _ EQ) in H0. rewrite (ireg_of_eq _ _ EQ1) in H0. + econstructor. split. apply exec_straight_one. simpl. eauto. auto. + split. simpl in H0. FuncInv. + subst b. apply testcond_for_unsigned_comparison_correct. + intros. unfold compare_ints. repeat SOther. +(* compimm *) + simpl map in H0. rewrite (ireg_of_eq _ _ EQ) in H0. + econstructor. split. apply exec_straight_one. simpl; eauto. auto. + split. simpl in H0. FuncInv. + subst b. apply testcond_for_signed_comparison_correct_ii. + apply testcond_for_signed_comparison_correct_pi; auto. + intros. unfold compare_ints. repeat SOther. +(* compuimm *) + simpl map in H0. rewrite (ireg_of_eq _ _ EQ) in H0. + exists (nextinstr (compare_ints (rs x) (Vint i) rs)). + split. destruct (Int.eq_dec i Int.zero). + apply exec_straight_one. subst i. simpl. + simpl in H0. FuncInv. simpl. rewrite Int.and_idem. auto. auto. + apply exec_straight_one; auto. + split. simpl in H0. FuncInv. + subst b. apply testcond_for_unsigned_comparison_correct. + intros. unfold compare_ints. repeat SOther. +(* compf *) + simpl map in H0. rewrite (freg_of_eq _ _ EQ) in H0. rewrite (freg_of_eq _ _ EQ1) in H0. + remember (rs x) as v1; remember (rs x0) as v2. simpl in H0. FuncInv. + exists (nextinstr (compare_floats (Vfloat (swap_floats c0 f f0)) (Vfloat (swap_floats c0 f0 f)) rs)). + split. apply exec_straight_one. + destruct c0; unfold floatcomp, exec_instr, swap_floats; congruence. + auto. + split. subst b. apply testcond_for_float_comparison_correct. + intros. unfold compare_floats. repeat SOther. +(* notcompf *) + simpl map in H0. rewrite (freg_of_eq _ _ EQ) in H0. rewrite (freg_of_eq _ _ EQ1) in H0. + remember (rs x) as v1; remember (rs x0) as v2. simpl in H0. FuncInv. + exists (nextinstr (compare_floats (Vfloat (swap_floats c0 f f0)) (Vfloat (swap_floats c0 f0 f)) rs)). + split. apply exec_straight_one. + destruct c0; unfold floatcomp, exec_instr, swap_floats; congruence. + auto. + split. subst b. apply testcond_for_neg_float_comparison_correct. + intros. unfold compare_floats. repeat SOther. +(* maskzero *) + simpl map in H0. rewrite (ireg_of_eq _ _ EQ) in H0. + econstructor. split. apply exec_straight_one. simpl; eauto. auto. + split. simpl in H0. FuncInv. simpl. + generalize (compare_ints_spec rs (Vint (Int.and i0 i)) Vzero). + intros [A B]. rewrite A. subst b. simpl. destruct (Int.eq (Int.and i0 i) Int.zero); auto. + intros. unfold compare_ints. repeat SOther. +(* masknotzero *) + simpl map in H0. rewrite (ireg_of_eq _ _ EQ) in H0. + econstructor. split. apply exec_straight_one. simpl; eauto. auto. + split. simpl in H0. FuncInv. simpl. + generalize (compare_ints_spec rs (Vint (Int.and i0 i)) Vzero). + intros [A B]. rewrite A. subst b. simpl. destruct (Int.eq (Int.and i0 i) Int.zero); auto. + intros. unfold compare_ints. repeat SOther. +Qed. + +(** Translation of arithmetic operations. *) + +(* +Ltac TranslOpSimpl := + match goal with + | |- exists rs' : regset, + exec_straight ?c ?rs ?m ?k rs' ?m /\ + agree (Regmap.set ?res ?v ?ms) ?sp rs' => + (exists (nextinstr (rs#(ireg_of res) <- v)); + split; + [ apply exec_straight_one; + [ repeat (rewrite (ireg_val ms sp rs); auto); reflexivity + | reflexivity ] + | auto with ppcgen ]) + || + (exists (nextinstr (rs#(freg_of res) <- v)); + split; + [ apply exec_straight_one; + [ repeat (rewrite (freg_val ms sp rs); auto); reflexivity + | reflexivity ] + | auto with ppcgen ]) + end. +*) + +Ltac ArgsInv := + match goal with + | [ H: Error _ = OK _ |- _ ] => discriminate + | [ H: match ?args with nil => _ | _ :: _ => _ end = OK _ |- _ ] => destruct args; ArgsInv + | [ H: bind _ _ = OK _ |- _ ] => monadInv H; ArgsInv + | [ H: assertion _ = OK _ |- _ ] => monadInv H; subst; ArgsInv + | [ H: ireg_of _ = OK _ |- _ ] => simpl in *; rewrite (ireg_of_eq _ _ H) in *; clear H; ArgsInv + | [ H: freg_of _ = OK _ |- _ ] => simpl in *; rewrite (freg_of_eq _ _ H) in *; clear H; ArgsInv + | _ => idtac + end. + +Ltac TranslOp := + econstructor; split; + [ apply exec_straight_one; [ simpl; eauto | auto ] + | split; [ repeat SRes | intros; repeat SOther ]]. + +(* Move elsewhere *) + +Lemma transl_op_correct: + forall op args res k c (rs: regset) m v, + transl_op op args res k = OK c -> + eval_operation ge (rs#ESP) op (map rs (map preg_of args)) = Some v -> + exists rs', + exec_straight c rs m k rs' m + /\ rs'#(preg_of res) = v + /\ forall r, + match op with Omove => important_preg r = true | _ => nontemp_preg r = true end -> + r <> preg_of res -> rs' r = rs r. +Proof. + intros until v; intros TR EV. + rewrite <- (eval_operation_weaken _ _ _ _ EV). + destruct op; simpl in TR; ArgsInv; try (TranslOp; fail). +(* move *) + exploit mk_mov_correct; eauto. intros [rs2 [A [B C]]]. + exists rs2. split. eauto. split. simpl. auto. auto. +(* cast8signed *) + eapply mk_intconv_correct; eauto. +(* cast8unsigned *) + eapply mk_intconv_correct; eauto. +(* cast16signed *) + eapply mk_intconv_correct; eauto. +(* cast16unsigned *) + eapply mk_intconv_correct; eauto. +(* div *) + eapply mk_div_correct; eauto. intros. simpl. eauto. +(* divu *) + eapply mk_div_correct; eauto. intros. simpl. eauto. +(* mod *) + eapply mk_mod_correct; eauto. intros. simpl. eauto. +(* modu *) + eapply mk_mod_correct; eauto. intros. simpl. eauto. +(* shl *) + eapply mk_shift_correct; eauto. +(* shr *) + eapply mk_shift_correct; eauto. +(* shrximm *) + remember (rs x0) as v1. FuncInv. + remember (Int.ltu i (Int.repr 31)) as L. destruct L; inv EV. + simpl. replace (Int.ltu i Int.iwordsize) with true. + apply mk_shrximm_correct; auto. + unfold Int.ltu. rewrite zlt_true; auto. + generalize (Int.ltu_inv _ _ (sym_equal HeqL)). + assert (Int.unsigned (Int.repr 31) < Int.unsigned Int.iwordsize) by (compute; auto). + omega. +(* shru *) + eapply mk_shift_correct; eauto. +(* lea *) + exploit transl_addressing_mode_correct; eauto. intros EA. + rewrite (eval_addressing_weaken _ _ _ _ EV). rewrite <- EA. + TranslOp. +(* condition *) + remember (eval_condition c0 rs ## (preg_of ## args)) as ob. destruct ob; inv EV. + rewrite (eval_condition_weaken _ _ (sym_equal Heqob)). + exploit transl_cond_correct; eauto. intros [rs2 [P [Q R]]]. + exists (nextinstr (rs2#ECX <- Vundef #EDX <- Vundef #x <- v)). + split. eapply exec_straight_trans. eauto. + apply exec_straight_one. simpl. rewrite Q. destruct b; inv H0; auto. auto. + split. repeat SRes. destruct b; inv H0; auto. + intros. repeat SOther. +Qed. + +(** Translation of memory loads. *) + +Lemma transl_load_correct: + forall chunk addr args dest k c (rs: regset) m a v, + transl_load chunk addr args dest k = OK c -> + eval_addressing ge (rs#ESP) addr (map rs (map preg_of args)) = Some a -> + Mem.loadv chunk m a = Some v -> + exists rs', + exec_straight c rs m k rs' m + /\ rs'#(preg_of dest) = v + /\ forall r, nontemp_preg r = true -> r <> preg_of dest -> rs'#r = rs#r. +Proof. + unfold transl_load; intros. monadInv H. + exploit transl_addressing_mode_correct; eauto. intro EA. + set (rs2 := nextinstr_nf (rs#(preg_of dest) <- v)). + assert (exec_load ge chunk m x rs (preg_of dest) = Next rs2 m). + unfold exec_load. rewrite EA. rewrite H1. auto. + assert (rs2 PC = Val.add (rs PC) Vone). + transitivity (Val.add ((rs#(preg_of dest) <- v) PC) Vone). + auto. decEq. apply Pregmap.gso; auto with ppcgen. + exists rs2. split. + destruct chunk; ArgsInv; apply exec_straight_one; simpl; auto. + split. unfold rs2. rewrite nextinstr_nf_inv1. SRes. apply preg_of_important. + intros. unfold rs2. repeat SOther. +Qed. + +Lemma transl_store_correct: + forall chunk addr args src k c (rs: regset) m a m', + transl_store chunk addr args src k = OK c -> + eval_addressing ge (rs#ESP) addr (map rs (map preg_of args)) = Some a -> + Mem.storev chunk m a (rs (preg_of src)) = Some m' -> + exists rs', + exec_straight c rs m k rs' m' + /\ forall r, nontemp_preg r = true -> rs'#r = rs#r. +Proof. + unfold transl_store; intros. monadInv H. + exploit transl_addressing_mode_correct; eauto. intro EA. rewrite <- EA in H1. + destruct chunk; ArgsInv. +(* int8signed *) + eapply mk_smallstore_correct; eauto. + intros. simpl. unfold exec_store. + destruct (eval_addrmode ge addr0 rs0); simpl; auto. rewrite Mem.store_signed_unsigned_8; auto. +(* int8unsigned *) + eapply mk_smallstore_correct; eauto. +(* int16signed *) + eapply mk_smallstore_correct; eauto. + intros. simpl. unfold exec_store. + destruct (eval_addrmode ge addr0 rs0); simpl; auto. rewrite Mem.store_signed_unsigned_16; auto. +(* int16unsigned *) + eapply mk_smallstore_correct; eauto. +(* int32 *) + econstructor; split. + apply exec_straight_one. simpl. unfold exec_store. rewrite H1. eauto. auto. + intros. SOther. +(* float32 *) + econstructor; split. + apply exec_straight_one. simpl. unfold exec_store. rewrite H1. eauto. auto. + intros. SOther. +(* float64 *) + econstructor; split. + apply exec_straight_one. simpl. unfold exec_store. rewrite H1. eauto. auto. + intros. SOther. +Qed. + +End STRAIGHTLINE. + -- cgit v1.2.3