Module asmgen_proof1



Correctness proof for x86-64 generation: auxiliary results.

Require Import Coqlib.
Require Import AST Errors Integers Floats Values Memory Globalenvs.
Require Import Op Locations Conventions Mach Asm.
Require Import Asmgen Asmgenproof0.

Require Import Blockset Footprint InteractionSemantics MemOpFP Op_fp
        Mach_local ASM_local asmgen asmgen_proof0 Asmgenproof1.

Local Open Scope error_monad_scope.

Local Notation footprint := FP.t.
Local Notation empfp := FP.emp.

Correspondence between Mach registers and x86 registers


Useful properties of the PC register.

Useful simplification tactic

Correctness of x86-64 constructor functions


TODO: strenghening correctness with footprint
Section CONSTRUCTORS.

Variable ge: genv.
Variable fn: function.

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 ge fn c rs1 m empfp k rs2 m
  /\ rs2#rd = rs1#rs
  /\ forall r, data_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. auto.
  split. Simplifs. intros; Simplifs.
 movsd *)  econstructor. split. apply exec_straight_one. simpl. eauto. auto. auto.
  split. Simplifs. intros; Simplifs.
Qed.

Properties of division

Smart constructor for shrx

Lemma mk_shrximm_correct:
  forall n k c (rs1: regset) v m,
  mk_shrximm n k = OK c ->
  Val.shrx (rs1#RAX) (Vint n) = Some v ->
  exists rs2,
     exec_straight ge fn c rs1 m empfp k rs2 m
  /\ rs2#RAX = v
  /\ forall r, data_preg r = true -> r <> RAX -> r <> RCX -> rs2#r = rs1#r.
Proof.
  unfold mk_shrximm; intros. inv H.
  exploit Val.shrx_shr; eauto. intros [x [y [A [B C]]]].
  inversion B; clear B; subst y; subst v; clear H0.
  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 m)).
  set (rs3 := nextinstr (rs2#RCX <- (Vint x'))).
  set (rs4 := nextinstr (if Int.lt x Int.zero then rs3#RAX <- (Vint x') else rs3)).
  set (rs5 := nextinstr_nf (rs4#RAX <- (Val.shr rs4#RAX (Vint n)))).
  assert (rs3#RAX = Vint x). unfold rs3. Simplifs.
  assert (rs3#RCX = Vint x'). unfold rs3. Simplifs.
  exists rs5. split.
  apply exec_straight_step with empfp rs2 m empfp. simpl. rewrite A. simpl. rewrite Int.and_idem. auto.
 fp *) simpl. clear. destruct (rs1 RAX); simpl; auto. auto.
  apply exec_straight_step with empfp rs3 m empfp. simpl.
  change (rs2 RAX) with (rs1 RAX). rewrite A. simpl.
  rewrite Int.repr_unsigned. rewrite Int.add_zero_l. auto. simpl; auto. auto.
  apply exec_straight_step with empfp rs4 m empfp. simpl.
  rewrite Int.lt_sub_overflow. unfold rs4. destruct (Int.lt x Int.zero); simpl; auto.
  unfold rs4. auto. destruct (Int.lt x Int.zero); simpl; auto.
  apply exec_straight_one. auto. auto. auto.
  apply FP.fp_union_emp.
  apply FP.fp_union_emp.
  apply FP.fp_union_emp.
  split. unfold rs5. Simplifs. unfold rs4. rewrite nextinstr_inv; auto with asmgen.
  destruct (Int.lt x Int.zero). rewrite Pregmap.gss. rewrite A; auto. rewrite A; rewrite H; auto.
  intros. unfold rs5. Simplifs. unfold rs4. Simplifs.
  transitivity (rs3#r). destruct (Int.lt x Int.zero). Simplifs. auto.
  unfold rs3. Simplifs. unfold rs2. Simplifs.
  unfold compare_ints. Simplifs.
Qed.

Smart constructor for shrxl

Lemma mk_shrxlimm_correct:
  forall n k c (rs1: regset) v m,
  mk_shrxlimm n k = OK c ->
  Val.shrxl (rs1#RAX) (Vint n) = Some v ->
  exists rs2,
     exec_straight ge fn c rs1 m empfp k rs2 m
  /\ rs2#RAX = v
  /\ forall r, data_preg r = true -> r <> RAX -> r <> RDX -> rs2#r = rs1#r.
Proof.
  unfold mk_shrxlimm; intros. exploit Val.shrxl_shrl_2; eauto. intros EQ.
  destruct (Int.eq n Int.zero); inv H.
- econstructor; split. apply exec_straight_one. simpl; reflexivity. auto. auto.
  split. Simplifs. intros; Simplifs.
- set (v1 := Val.shrl (rs1 RAX) (Vint (Int.repr 63))) in *.
  set (v2 := Val.shrlu v1 (Vint (Int.sub (Int.repr 64) n))) in *.
  set (v3 := Val.addl (rs1 RAX) v2) in *.
  set (v4 := Val.shrl v3 (Vint n)) in *.
  set (rs2 := nextinstr_nf (rs1#RDX <- v1)).
  set (rs3 := nextinstr_nf (rs2#RDX <- v2)).
  set (rs4 := nextinstr (rs3#RAX <- v3)).
  set (rs5 := nextinstr_nf (rs4#RAX <- v4)).
  assert (X: forall v1 v2,
             Val.addl v1 (Val.addl v2 (Vlong Int64.zero)) = Val.addl v1 v2).
  { intros. unfold Val.addl; destruct Archi.ptr64 eqn:SF, v0; auto; destruct v5; auto.
    rewrite Int64.add_zero; auto.
    rewrite Ptrofs.add_zero; auto.
    rewrite Int64.add_zero; auto.
    rewrite Int64.add_zero; auto. }
  exists rs5; split.
  replace empfp with (FP.union (FP.union empfp empfp) (FP.union empfp empfp)) by (repeat rewrite FP.fp_union_emp; auto).
  eapply exec_straight_trans with (rs2 := rs3).
  eapply exec_straight_two with (rs2 := rs2); reflexivity.
  eapply exec_straight_two with (rs2 := rs4).
  simpl. rewrite X. reflexivity. auto. reflexivity. auto. reflexivity. reflexivity.
  split. unfold rs5; Simplifs.
  intros. unfold rs5; Simplifs. unfold rs4; Simplifs. unfold rs3; Simplifs. unfold rs2; Simplifs.
Qed.

Smart constructor for integer conversions

Lemma mk_intconv_correct:
  forall mk sem rd rs k c rs1 m fp,
    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) ->
    (fp = if Archi.ptr64 || low_ireg rs
         then exec_instr_fp ge fn (mk rd rs) rs1 m
         else exec_instr_fp ge fn (mk rd RAX) (nextinstr rs1 # RAX <- (rs1 rs)) m) ->
    exists rs2,
      exec_straight ge fn c rs1 m fp k rs2 m
      /\ rs2#rd = sem rs1#rs
      /\ forall r, data_preg r = true -> r <> rd -> r <> RAX -> rs2#r = rs1#r.
Proof.
  unfold mk_intconv; intros. destruct (Archi.ptr64 || low_ireg rs); monadInv H.
  econstructor. split. apply exec_straight_one. rewrite H0. eauto. auto. simpl. auto.
  split. Simplifs. intros. Simplifs.
  econstructor. split.
  erewrite <- (FP.emp_union_fp (exec_instr_fp ge fn (mk rd RAX) _ m)).
  eapply exec_straight_two.
  simpl. eauto. auto. apply H0. auto. auto. auto.
  split. Simplifs. intros. Simplifs.
Qed.

Smart constructor for small stores

Lemma addressing_mentions_correct:
  forall a r (rs1 rs2: regset),
  (forall (r': ireg), r' <> r -> rs1 r' = rs2 r') ->
  addressing_mentions a r = false ->
  eval_addrmode32 ge a rs1 = eval_addrmode32 ge a rs2.
Proof.
  intros until rs2; intro AG. unfold addressing_mentions, eval_addrmode32.
  destruct a. intros. destruct (orb_false_elim _ _ H). unfold proj_sumbool in *.
  decEq. destruct base; auto. apply AG. destruct (ireg_eq r i); congruence.
  decEq. destruct ofs as [[r' sc] | ]; auto. rewrite AG; auto. destruct (ireg_eq r r'); congruence.
Qed.

Lemma mk_storebyte_correct:
  forall addr r k c rs1 m1 m2,
  mk_storebyte addr r k = OK c ->
  Mem.storev Mint8unsigned m1 (eval_addrmode ge addr rs1) (rs1 r) = Some m2 ->
  exists rs2,
    exec_straight ge fn c rs1 m1 (storev_fp Mint8unsigned (eval_addrmode ge addr rs1)) k rs2 m2
    /\ forall r, data_preg r = true -> preg_notin r (if Archi.ptr64 then nil else AX :: CX :: nil) -> rs2#r = rs1#r.
Proof.
  unfold mk_storebyte; intros.
  destruct (Archi.ptr64 || low_ireg r) eqn:E.
 low reg *)  monadInv H. econstructor; split. apply exec_straight_one.
  simpl. unfold exec_store. rewrite H0. eauto. auto. auto.
  intros; Simplifs.
 high reg *)  InvBooleans. rewrite H1; simpl. destruct (addressing_mentions addr RAX) eqn:E; monadInv H.
 RAX is mentioned. *)  assert (r <> RCX). { red; intros; subst r; discriminate H2. }
  set (rs2 := nextinstr (rs1#RCX <- (eval_addrmode32 ge addr rs1))).
  set (rs3 := nextinstr (rs2#RAX <- (rs1 r))).
  econstructor; split. do 2 rewrite <- (FP.emp_union_fp (storev_fp Mint8unsigned (eval_addrmode ge addr rs1))).
  apply exec_straight_three with rs2 m1 rs3 m1.
  simpl. auto. auto.
  simpl. replace (rs2 r) with (rs1 r). auto. symmetry. unfold rs2; Simplifs. auto.
  simpl. unfold exec_store. unfold eval_addrmode; rewrite H1; simpl. rewrite Int.add_zero.
  change (rs3 RAX) with (rs1 r).
  change (rs3 RCX) with (eval_addrmode32 ge addr rs1).
  replace (Val.add (eval_addrmode32 ge addr rs1) (Vint Int.zero))
     with (eval_addrmode ge addr rs1).
  rewrite H0. eauto.
  unfold eval_addrmode in *; rewrite H1 in *.
  destruct (eval_addrmode32 ge addr rs1); simpl in H0; try discriminate H0.
  simpl. rewrite H1. rewrite Ptrofs.add_zero; auto.
  simpl. unfold exec_store_fp. unfold eval_addrmode in *; rewrite H1 in *.
  destruct (eval_addrmode32 ge addr rs1); simpl in H0; try discriminate H0.
  simpl. rewrite H1. rewrite Ptrofs.add_zero; auto.
  auto. auto. auto.
  intros. destruct H4. Simplifs. unfold rs3; Simplifs. unfold rs2; Simplifs.
 RAX is not mentioned *)  set (rs2 := nextinstr (rs1#RAX <- (rs1 r))).
  econstructor; split. rewrite <- (FP.emp_union_fp (storev_fp Mint8unsigned (eval_addrmode ge addr rs1))).
  apply exec_straight_two with rs2 m1.
  simpl. auto. auto.
  simpl. unfold exec_store. unfold eval_addrmode in *; rewrite H1 in *.
  rewrite (addressing_mentions_correct addr RAX rs2 rs1); auto.
  change (rs2 RAX) with (rs1 r). rewrite H0. eauto.
  intros. unfold rs2; Simplifs.
  simpl. unfold exec_store_fp. unfold eval_addrmode in *; rewrite H1 in *.
  rewrite (addressing_mentions_correct addr RAX rs2 rs1); auto.
  intros. unfold rs2; Simplifs.
  auto. auto.
  intros. destruct H3. simpl. Simplifs. unfold rs2; Simplifs.
Qed.

Accessing slots in the stack frame

Remark eval_addrmode_indexed:
  forall (base: ireg) ofs (rs: regset),
  match rs#base with Vptr _ _ => True | _ => False end ->
  eval_addrmode ge (Addrmode (Some base) None (inl _ (Ptrofs.unsigned ofs))) rs = Val.offset_ptr rs#base ofs.
Proof.
  intros. destruct (rs#base) eqn:BASE; try contradiction.
  intros; unfold eval_addrmode; destruct Archi.ptr64 eqn:SF; simpl; rewrite BASE; simpl; rewrite SF; simpl.
- apply f_equal. apply f_equal. rewrite Int64.add_zero_l. rewrite <- (Ptrofs.repr_unsigned ofs) at 2. auto with ptrofs.
- apply f_equal. apply f_equal. rewrite Int.add_zero_l. rewrite <- (Ptrofs.repr_unsigned ofs) at 2. auto with ptrofs.
Qed.

Ltac loadind_correct_solve :=
  match goal with
  | H: Error _ = OK _ |- _ => discriminate H
  | H: OK _ = OK _ |- _ => inv H
  | H: match ?x with _ => _ end = OK _ |- _ => destruct x eqn:?; loadind_correct_solve
  | _ => idtac
  end.

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.offset_ptr rs#base ofs) = Some v ->
  exists rs',
     exec_straight ge fn c rs m (loadv_fp (chunk_of_type ty) (Val.offset_ptr rs#base ofs)) k rs' m
  /\ rs'#(preg_of dst) = v
  /\ forall r, data_preg r = true -> r <> preg_of dst -> rs'#r = rs#r.
Proof.
  unfold loadind; intros.
  set (addr := Addrmode (Some base) None (inl (ident * ptrofs) (Ptrofs.unsigned ofs))) in *.
  assert (eval_addrmode ge addr rs = Val.offset_ptr rs#base ofs).
  { apply eval_addrmode_indexed. destruct (rs base); auto || discriminate. }
  rewrite <- H1 in H0 |- * .
  exists (nextinstr_nf (rs#(preg_of dst) <- v)); split.
- loadind_correct_solve; apply exec_straight_one; auto; simpl in *; unfold exec_load; rewrite ?Heqb, ?H0; auto.
- intuition Simplifs.
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.offset_ptr rs#base ofs) (rs#(preg_of src)) = Some m' ->
  exists rs',
     exec_straight ge fn c rs m (storev_fp (chunk_of_type ty) (Val.offset_ptr rs#base ofs)) k rs' m'
  /\ forall r, data_preg r = true -> preg_notin r (destroyed_by_setstack ty) -> rs'#r = rs#r.
Proof.
  unfold storeind; intros.
  set (addr := Addrmode (Some base) None (inl (ident * ptrofs) (Ptrofs.unsigned ofs))) in *.
  assert (eval_addrmode ge addr rs = Val.offset_ptr rs#base ofs).
  { apply eval_addrmode_indexed. destruct (rs base); auto || discriminate. }
  loadind_correct_solve; try unfold exec_instr_fp; rewrite <- H1 in H0 |- * ; simpl in H0;
  (econstructor; split;
   [apply exec_straight_one; [simpl; unfold exec_store; rewrite ?Heqb, H0;eauto|auto|auto]
   |simpl; intros; unfold undef_regs; repeat Simplifs]).
  unfold exec_instr_fp. rewrite Heqb. simpl. auto.
Qed.

Translation of addressing modes

Lemma transl_addressing_mode_32_correct:
  forall addr args am (rs: regset) v,
  transl_addressing addr args = OK am ->
  eval_addressing32 ge (rs RSP) addr (List.map rs (List.map preg_of args)) = Some v ->
  Val.lessdef v (eval_addrmode32 ge am rs).
Proof.
  assert (A: forall id ofs, Archi.ptr64 = false ->
          Val.add (Vint Int.zero) (Genv.symbol_address ge id ofs) = Genv.symbol_address ge id ofs).
  { intros. unfold Val.add; rewrite H. unfold Genv.symbol_address.
    destruct (Genv.find_symbol ge id); auto. rewrite Ptrofs.add_zero; auto. }
  assert (C: forall v i,
    Val.lessdef (Val.mul v (Vint (Int.repr i)))
               (if zeq i 1 then v else Val.mul v (Vint (Int.repr i)))).
  { intros. destruct (zeq i 1); subst; auto.
    destruct v; simpl; auto. rewrite Int.mul_one; auto. }
  unfold transl_addressing; intros.
  destruct addr; repeat (destruct args; try discriminate H); simpl in H0; FuncInv;
  monadInv H; try (erewrite ! ireg_of_eq by eauto); unfold eval_addrmode32.
- simpl; rewrite Int.add_zero_l; auto.
- rewrite Val.add_assoc. apply Val.add_lessdef; auto.
- rewrite Val.add_permut. apply Val.add_lessdef; auto. simpl; rewrite Int.add_zero_l; auto.
- apply Val.add_lessdef; auto. apply Val.add_lessdef; auto.
- rewrite ! A by auto. auto.
- rewrite Val.add_commut. rewrite A by auto. auto.
- rewrite Val.add_permut. rewrite Val.add_commut. apply Val.add_lessdef; auto. rewrite A; auto.
- simpl. unfold Val.add; rewrite Heqb.
  destruct (rs RSP); simpl; auto.
  rewrite Int.add_zero_l. apply Val.lessdef_same; f_equal; f_equal.
  symmetry. transitivity (Ptrofs.repr (Ptrofs.signed i)). auto with ptrofs. auto with ints.
Qed.

Lemma transl_addressing_mode_64_correct:
  forall addr args am (rs: regset) v,
  transl_addressing addr args = OK am ->
  eval_addressing64 ge (rs RSP) addr (List.map rs (List.map preg_of args)) = Some v ->
  Val.lessdef v (eval_addrmode64 ge am rs).
Proof.
  assert (A: forall id ofs, Archi.ptr64 = true ->
          Val.addl (Vlong Int64.zero) (Genv.symbol_address ge id ofs) = Genv.symbol_address ge id ofs).
  { intros. unfold Val.addl; rewrite H. unfold Genv.symbol_address.
    destruct (Genv.find_symbol ge id); auto. rewrite Ptrofs.add_zero; auto. }
  assert (C: forall v i,
    Val.lessdef (Val.mull v (Vlong (Int64.repr i)))
               (if zeq i 1 then v else Val.mull v (Vlong (Int64.repr i)))).
  { intros. destruct (zeq i 1); subst; auto.
    destruct v; simpl; auto. rewrite Int64.mul_one; auto. }
  unfold transl_addressing; intros.
  destruct addr; repeat (destruct args; try discriminate H); simpl in H0; FuncInv;
  monadInv H; try (erewrite ! ireg_of_eq by eauto); unfold eval_addrmode64.
- simpl; rewrite Int64.add_zero_l; auto.
- rewrite Val.addl_assoc. apply Val.addl_lessdef; auto.
- rewrite Val.addl_permut. apply Val.addl_lessdef; auto. simpl; rewrite Int64.add_zero_l; auto.
- apply Val.addl_lessdef; auto. apply Val.addl_lessdef; auto.
- rewrite ! A by auto. auto.
- unfold Val.addl; rewrite Heqb. destruct (rs RSP); auto. simpl.
  rewrite Int64.add_zero_l. apply Val.lessdef_same; f_equal; f_equal.
  symmetry. transitivity (Ptrofs.repr (Ptrofs.signed i)). auto with ptrofs. auto with ints.
Qed.

Lemma transl_addressing_mode_correct:
  forall addr args am (rs: regset) v,
  transl_addressing addr args = OK am ->
  eval_addressing ge (rs RSP) addr (List.map rs (List.map preg_of args)) = Some v ->
  Val.lessdef v (eval_addrmode ge am rs).
Proof.
  unfold eval_addressing, eval_addrmode; intros. destruct Archi.ptr64.
  eapply transl_addressing_mode_64_correct; eauto.
  eapply transl_addressing_mode_32_correct; eauto.
Qed.

Lemma normalize_addrmode_32_correct:
  forall am rs, eval_addrmode32 ge (normalize_addrmode_32 am) rs = eval_addrmode32 ge am rs.
Proof.
  intros; destruct am as [base ofs [n|r]]; simpl; auto. rewrite Int.repr_signed. auto.
Qed.

Lemma normalize_addrmode_64_correct:
  forall am rs,
  eval_addrmode64 ge am rs =
  match normalize_addrmode_64 am with
  | (am', None) => eval_addrmode64 ge am' rs
  | (am', Some delta) => Val.addl (eval_addrmode64 ge am' rs) (Vlong delta)
  end.
Proof.
  intros; destruct am as [base ofs [n|r]]; simpl; auto.
  destruct (zeq (Int.signed (Int.repr n)) n); simpl; auto.
  rewrite ! Val.addl_assoc. apply f_equal. apply f_equal. simpl. rewrite Int64.add_zero_l; auto.
Qed.

Processor conditions and comparisons

TODO: move to Footprint.v
Lemma loc_union_2:
  forall ls, Locs.union ls ls = ls.
Proof.
  clear; intros. Locs.unfolds.
  apply Axioms.functional_extensionality; intro.
  apply Axioms.functional_extensionality; intro.
  destruct ls; auto.
Qed.
Lemma fp_union_2:
  forall fp, FP.union fp fp = fp.
Proof.
  clear. intros [c r w f]. unfold FP.union.
  f_equal; simpl; apply loc_union_2.
Qed.

Ltac SimplifFP :=
  match goal with
  | H: match ?x with _ => _ end = Some _ |- _ => destruct x eqn:C; try inv C; try discriminate
  | H: ?x = Some _ |- context[?x] => destruct x eqn:C; try inv C; try discriminate
  | |- match ?x with _ => _ end = _ => destruct x eqn:C; try inv C; try discriminate
  | |- context[FP.union ?fp empfp] => rewrite FP.fp_union_emp; auto
  | |- context[FP.union ?fp ?fp] => rewrite fp_union_2; auto
  end.

Ltac SimplifFPs := repeat SimplifFP.

Lemma transl_cond_correct:
  forall cond args k c rs m,
  transl_cond cond args k = OK c ->
  exists rs' fp,
    match eval_condition cond (map rs (map preg_of args)) m with
     | None => True
     | Some b =>
       exec_straight ge fn c rs m fp k rs' m /\
       eval_extcond (testcond_for_condition cond) rs' = Some b /\
       eval_condition_fp cond (map rs (map preg_of args)) m = Some fp /\
       forall r, data_preg r = true -> rs'#r = rs r
     end.
Proof.
  unfold transl_cond; intros.
  destruct cond; repeat (destruct args; try discriminate); monadInv H.
- (* comp *)
  simpl. rewrite (ireg_of_eq _ _ EQ). rewrite (ireg_of_eq _ _ EQ1).
  destruct (Val.cmp_bool c0 (rs x) (rs x0)) eqn:?.
  econstructor. eexists. split.
  apply exec_straight_one. simpl. erewrite cmp_bool_check_compare_ints; eauto.
  destruct check_vundef eqn:?; eauto. exfalso; destruct (rs x), (rs x0); simpl in *; discriminate.
  eauto. eauto.
  split. eapply testcond_for_signed_comparison_32_correct; eauto.
  split.
 fp *) simpl. unfold compare_ints_fp. destruct (rs x), (rs x0); try discriminate; simpl. f_equal.
  intros. unfold compare_ints. Simplifs.
  repeat econstructor.
- (* compu *)
  simpl. rewrite (ireg_of_eq _ _ EQ). rewrite (ireg_of_eq _ _ EQ1).
  destruct (Val.cmpu_bool (Mem.valid_pointer m) c0 (rs x) (rs x0)) eqn:?; [|repeat econstructor].
  econstructor. eexists. split.
  apply exec_straight_one. simpl. erewrite cmpu_bool_check_compare_ints; eauto.
  destruct check_vundef eqn:?; eauto. exfalso; destruct (rs x), (rs x0); simpl in *; discriminate.
  eauto. eauto.
  split. eapply testcond_for_unsigned_comparison_32_correct; eauto.
  split.
 fp *)  { simpl. unfold compare_ints_fp.
    destruct (rs x), (rs x0); try discriminate; simpl in *; try (f_equal; fail);
      SimplifFPs; repeat rewrite FP.fp_union_emp; auto. }
  intros. unfold compare_ints. Simplifs.
- (* compimm *)
  simpl. rewrite (ireg_of_eq _ _ EQ). destruct (Int.eq_dec n Int.zero).
  destruct (rs x) eqn: VAL; simpl; auto; try (repeat econstructor; fail). subst.
  econstructor; eexists; split. apply exec_straight_one. simpl.
  rewrite VAL. simpl. eauto. eauto. eauto.
  split. rewrite Int.and_idem. eapply testcond_for_signed_comparison_32_correct; eauto.
  split.
 fp *) simpl. unfold compare_ints_fp. rewrite VAL. simpl. f_equal.
  intros. unfold compare_ints. Simplifs.

  destruct (Val.cmp_bool c0 (rs x) (Vint n)) eqn:?; [|repeat econstructor].
  econstructor; eexists; split. apply exec_straight_one. simpl.
  erewrite cmp_bool_check_compare_ints; eauto.
  destruct check_vundef eqn:?; eauto. exfalso; destruct (rs x); simpl in *; discriminate.
  eauto. eauto.
  split. eapply testcond_for_signed_comparison_32_correct; eauto.
  split.
 fp *) simpl. unfold compare_ints_fp. destruct (rs x); try discriminate; simpl in *; SimplifFPs.
  intros. unfold compare_ints. Simplifs.
- (* compuimm *)
  simpl. rewrite (ireg_of_eq _ _ EQ).
  destruct (Val.cmpu_bool (Mem.valid_pointer m) c0 (rs x) (Vint n)) eqn:?; [|repeat econstructor].
  econstructor. eexists. split. apply exec_straight_one. simpl.
  erewrite cmpu_bool_check_compare_ints; eauto.
  destruct check_vundef eqn:?; eauto. exfalso; destruct (rs x); simpl in *; discriminate.
  eauto. eauto.
  split. eapply testcond_for_unsigned_comparison_32_correct; eauto.
  split.
 fp *) simpl. unfold compare_ints_fp. destruct (rs x); try discriminate; simpl in *; SimplifFPs.
  intros. unfold compare_ints. Simplifs.
- (* compl *)
  simpl. rewrite (ireg_of_eq _ _ EQ). rewrite (ireg_of_eq _ _ EQ1).
  destruct (Val.cmpl_bool c0 (rs x) (rs x0)) eqn:?; [|repeat econstructor].
  econstructor. eexists; split. apply exec_straight_one. simpl.
  destruct check_vundef eqn:?; eauto. exfalso; destruct (rs x), (rs x0); simpl in *; discriminate.
  eauto. eauto.
  split. eapply testcond_for_signed_comparison_64_correct; eauto.
  split.
 fp *) simpl. unfold compare_longs_fp. destruct (rs x), (rs x0); try discriminate; simpl in *; SimplifFPs.
  intros. unfold compare_longs. Simplifs.
- (* complu *)
  simpl. rewrite (ireg_of_eq _ _ EQ). rewrite (ireg_of_eq _ _ EQ1).
  destruct (Val.cmplu_bool (Mem.valid_pointer m) c0 (rs x) (rs x0)) eqn:?; [|repeat econstructor].
  econstructor. eexists; split. apply exec_straight_one. simpl.
  destruct check_vundef eqn:?; eauto. exfalso; destruct (rs x), (rs x0); simpl in *; discriminate.
  eauto. eauto.
  split. eapply testcond_for_unsigned_comparison_64_correct; eauto.
  split.
 fp *) simpl. unfold compare_longs_fp. destruct (rs x), (rs x0); try discriminate; simpl in *; SimplifFPs.
  intros. unfold compare_longs. Simplifs.
- (* compimm *)
  simpl. rewrite (ireg_of_eq _ _ EQ). destruct (Int64.eq_dec n Int64.zero).
  destruct (rs x) eqn:VAL; simpl; try repeat constructor.
  econstructor; eexists; split. apply exec_straight_one. simpl; eauto.
  rewrite VAL. simpl. eauto. eauto. eauto.
  split. subst. rewrite Int64.and_idem. eapply testcond_for_signed_comparison_64_correct; eauto.
  split.
 fp *) simpl. unfold compare_longs_fp. destruct (rs x); try discriminate; simpl in *; SimplifFPs.
  intros. unfold compare_longs. Simplifs.
  
  destruct (rs x) eqn:VAL; simpl; try repeat constructor.
  econstructor; eexists; split. apply exec_straight_one. simpl; eauto.
  rewrite VAL. simpl. eauto. eauto. eauto.
  split. eapply testcond_for_signed_comparison_64_correct; eauto.
  split.
 fp *) simpl. unfold compare_longs_fp. destruct (rs x); try discriminate; simpl in *; SimplifFPs.
  intros. unfold compare_longs. Simplifs.
- (* compuimm *)
  simpl. rewrite (ireg_of_eq _ _ EQ).
  destruct (Val.cmplu_bool (Mem.valid_pointer m) c0 (rs x) (Vlong n)) eqn:CMP; repeat constructor.
  destruct (rs x) eqn:VAL; simpl in *; inv CMP. eauto.
  econstructor. eexists. split. apply exec_straight_one. simpl.
  rewrite VAL. simpl. eauto. eauto. auto.
  split. eapply testcond_for_unsigned_comparison_64_correct; eauto.
  split.
 fp *) simpl. unfold compare_longs_fp. destruct (rs x); try discriminate; simpl in *; SimplifFPs.
  intros. unfold compare_longs. Simplifs.
- (* compf *)
  simpl. rewrite (freg_of_eq _ _ EQ). rewrite (freg_of_eq _ _ EQ1).
  destruct (rs x) eqn:VAL; destruct (rs x0) eqn:VAL'; simpl; repeat constructor.
  exists (nextinstr (compare_floats (swap_floats c0 (rs x) (rs x0)) (swap_floats c0 (rs x0) (rs x)) rs)).
  eexists. split. apply exec_straight_one.
  destruct c0; simpl; auto. auto.
  unfold nextinstr. rewrite Pregmap.gss. rewrite compare_floats_inv; auto with asmgen.
  split. rewrite VAL, VAL'.
  repeat rewrite swap_floats_commut.
  apply testcond_for_float_comparison_correct.
  split.
 fp *) simpl. unfold floatcomp. destruct c0; simpl; auto.
  intros. Simplifs. apply compare_floats_inv; auto with asmgen.
- (* notcompf *)
  simpl. rewrite (freg_of_eq _ _ EQ). rewrite (freg_of_eq _ _ EQ1).
  exists (nextinstr (compare_floats (swap_floats c0 (rs x) (rs x0)) (swap_floats c0 (rs x0) (rs x)) rs)).
  eexists. destruct (rs x) eqn:VAL; destruct (rs x0) eqn:VAL'; simpl; auto.
  repeat rewrite swap_floats_commut.
  split. apply exec_straight_one. destruct c0; simpl; rewrite VAL, VAL'; auto.
  auto.
  unfold nextinstr. rewrite Pregmap.gss. rewrite compare_floats_inv; auto with asmgen.
  split. apply testcond_for_neg_float_comparison_correct.
  split.
 fp *) unfold floatcomp; destruct c0; simpl; auto.
  intros. Simplifs. apply compare_floats_inv; auto with asmgen.
- (* compfs *)
  simpl. rewrite (freg_of_eq _ _ EQ). rewrite (freg_of_eq _ _ EQ1).
  destruct (rs x) eqn:VAL; destruct (rs x0) eqn:VAL'; simpl; repeat constructor.
  exists (nextinstr (compare_floats32 (swap_floats c0 (rs x) (rs x0)) (swap_floats c0 (rs x0) (rs x)) rs)).
  eexists. split. repeat rewrite swap_floats_commut.
  apply exec_straight_one. destruct c0; simpl; auto. auto.
  unfold nextinstr. rewrite Pregmap.gss. rewrite compare_floats32_inv; auto with asmgen.
  split. rewrite VAL, VAL'. repeat rewrite swap_floats_commut.
  apply testcond_for_float32_comparison_correct.
  split.
 fp *) unfold floatcomp32. destruct c0; simpl; auto.
  intros. Simplifs. apply compare_floats32_inv; auto with asmgen.
- (* notcompfs *)
  simpl. rewrite (freg_of_eq _ _ EQ). rewrite (freg_of_eq _ _ EQ1).
  exists (nextinstr (compare_floats32 (swap_floats c0 (rs x) (rs x0)) (swap_floats c0 (rs x0) (rs x)) rs)).
  destruct (rs x) eqn:VAL; destruct (rs x0) eqn:VAL'; simpl; repeat constructor.
  eexists. split. apply exec_straight_one.
  destruct c0; simpl; rewrite VAL, VAL'; auto. auto.
  unfold nextinstr. rewrite Pregmap.gss. rewrite compare_floats32_inv; auto with asmgen.
  split. repeat rewrite swap_floats_commut. apply testcond_for_neg_float32_comparison_correct.
  split.
 fp *) unfold floatcomp32. destruct c0; auto.
  intros. Simplifs. apply compare_floats32_inv; auto with asmgen.
- (* maskzero *)
  simpl. rewrite (ireg_of_eq _ _ EQ).
  destruct (rs x) eqn:VAL; simpl; repeat constructor.
  econstructor. eexists. split. apply exec_straight_one.
  simpl; rewrite VAL. simpl. eauto.
  eauto. eauto.
  split. generalize (compare_ints_spec rs (Vint (Int.and i n)) Vzero m).
  intros [A B]. rewrite A. unfold Val.cmpu; simpl. destruct (Int.eq (Int.and i n) Int.zero); auto.
  split.
  simpl. unfold compare_ints_fp. rewrite VAL. simpl. SimplifFPs.
  intros. unfold compare_ints. Simplifs.
- (* masknotzero *)
  simpl. rewrite (ireg_of_eq _ _ EQ).
  destruct (rs x) eqn:VAL; simpl; repeat constructor.
  econstructor. eexists. split. apply exec_straight_one.
  simpl; rewrite VAL. simpl. eauto. auto. auto.
  simpl. unfold compare_ints_fp.
  split. generalize (compare_ints_spec rs (Vint (Int.and i n)) Vzero m).
  intros [A B]. rewrite A. unfold Val.cmpu; simpl. destruct (Int.eq (Int.and i n) Int.zero); auto.
  split. rewrite VAL. simpl. SimplifFPs.
  intros. unfold compare_ints. Simplifs.
Qed.


Lemma mk_setcc_base_correct:
  forall cond rd k rs1 m,
  exists rs2,
  exec_straight ge fn (mk_setcc_base cond rd k) rs1 m empfp k rs2 m
  /\ rs2#rd = Val.of_optbool(eval_extcond cond rs1)
  /\ forall r, data_preg r = true -> r <> RAX /\ r <> RCX -> r <> rd -> rs2#r = rs1#r.
Proof.
  intros. destruct cond; simpl in *.
- (* base *)
  econstructor; split.
  apply exec_straight_one. simpl; eauto. auto. auto.
  split. Simplifs. intros; Simplifs.
- (* or *)
  assert (Val.of_optbool
    match eval_testcond c1 rs1 with
    | Some b1 =>
        match eval_testcond c2 rs1 with
        | Some b2 => Some (b1 || b2)
        | None => None
        end
    | None => None
    end =
    Val.or (Val.of_optbool (eval_testcond c1 rs1)) (Val.of_optbool (eval_testcond c2 rs1))).
  destruct (eval_testcond c1 rs1). destruct (eval_testcond c2 rs1).
  destruct b; destruct b0; auto.
  destruct b; auto.
  auto.
  rewrite H; clear H.
  destruct (ireg_eq rd RAX).
  subst rd. econstructor; split.
  rewrite <- (FP.fp_union_emp empfp).
  rewrite <- (FP.fp_union_emp empfp) at 2.
  eapply exec_straight_three.
  simpl; eauto. auto.
  simpl. rewrite eval_testcond_nextinstr. repeat rewrite eval_testcond_set_ireg. eauto. auto.
  simpl; eauto. auto.
  auto. auto. auto.
  intuition Simplifs.
  econstructor; split.
  rewrite <- (FP.fp_union_emp empfp).
  rewrite <- (FP.fp_union_emp empfp) at 2.
  eapply exec_straight_three.
  simpl; eauto. auto.
  simpl. rewrite eval_testcond_nextinstr. repeat rewrite eval_testcond_set_ireg. eauto. auto.
  simpl. eauto. auto.
  auto. auto. auto.
  split. Simplifs. rewrite Val.or_commut. decEq; Simplifs.
  intros. destruct H0; Simplifs.
- (* and *)
  assert (Val.of_optbool
    match eval_testcond c1 rs1 with
    | Some b1 =>
        match eval_testcond c2 rs1 with
        | Some b2 => Some (b1 && b2)
        | None => None
        end
    | None => None
    end =
    Val.and (Val.of_optbool (eval_testcond c1 rs1)) (Val.of_optbool (eval_testcond c2 rs1))).
  {
    destruct (eval_testcond c1 rs1). destruct (eval_testcond c2 rs1).
    destruct b; destruct b0; auto.
    destruct b; auto.
    auto.
  }
  rewrite H; clear H.
  destruct (ireg_eq rd RAX).
  subst rd. econstructor; split.
  rewrite <- (FP.fp_union_emp empfp).
  rewrite <- (FP.fp_union_emp empfp) at 2.
  eapply exec_straight_three.
  simpl; eauto. auto.
  simpl. rewrite eval_testcond_nextinstr. repeat rewrite eval_testcond_set_ireg. eauto. auto.
  simpl; eauto. auto.
  auto. auto. auto.
  intuition Simplifs.
  econstructor; split.
  rewrite <- (FP.fp_union_emp empfp).
  rewrite <- (FP.fp_union_emp empfp) at 2.
  eapply exec_straight_three.
  simpl; eauto. auto.
  simpl. rewrite eval_testcond_nextinstr. repeat rewrite eval_testcond_set_ireg. eauto. auto.
  simpl. eauto. auto.
  auto. auto. auto.
  split. Simplifs. rewrite Val.and_commut. decEq; Simplifs.
  intros. destruct H0; Simplifs.
Qed.

Lemma mk_setcc_correct:
  forall cond rd k rs1 m,
  exists rs2,
  exec_straight ge fn (mk_setcc cond rd k) rs1 m empfp k rs2 m
  /\ rs2#rd = Val.of_optbool(eval_extcond cond rs1)
  /\ forall r, data_preg r = true -> r <> RAX /\ r <> RCX -> r <> rd -> rs2#r = rs1#r.
Proof.
  intros. unfold mk_setcc. destruct (Archi.ptr64 || low_ireg rd).
- apply mk_setcc_base_correct.
- exploit mk_setcc_base_correct. intros [rs2 [A [B C]]].
  econstructor; split. rewrite <- (FP.fp_union_emp empfp). eapply exec_straight_trans. eexact A. apply exec_straight_one.
    simpl. eauto. auto. simpl. auto.
  intuition Simplifs.
Qed.

Translation of arithmetic operations.

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: match _ with left _ => _ | right _ => assertion_failed end = OK _ |- _ ] => monadInv H; ArgsInv
  | [ H: match _ with true => _ | false => assertion_failed end = OK _ |- _ ] => monadInv H; 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 | auto ]
  | split; [ Simplifs | intros; Simplifs ]].

Lemma transl_op_correct:
  forall op args res k c (rs: regset) m v fp,
  transl_op op args res k = OK c ->
  eval_operation ge (rs#RSP) op (map rs (map preg_of args)) m = Some v ->
  eval_operation_fp ge (rs#RSP) op (map rs (map preg_of args)) m = Some fp ->
  exists rs',
     exec_straight ge fn c rs m fp k rs' m
  /\ Val.lessdef v rs'#(preg_of res)
  /\ forall r, data_preg r = true -> r <> preg_of res -> preg_notin r (destroyed_by_op op) -> rs' r = rs r.
Proof.
Transparent destroyed_by_op.
  intros until fp; intros TR EV EVFP.
  assert (SAME:
  (exists rs',
     exec_straight ge fn c rs m fp k rs' m
  /\ rs'#(preg_of res) = v
  /\ forall r, data_preg r = true -> r <> preg_of res -> preg_notin r (destroyed_by_op op) -> rs' r = rs r) ->
  exists rs',
     exec_straight ge fn c rs m fp k rs' m
  /\ Val.lessdef v rs'#(preg_of res)
  /\ forall r, data_preg r = true -> r <> preg_of res -> preg_notin r (destroyed_by_op op) -> rs' r = rs r).
  {
    intros [rs' [A [B C]]]. subst v. exists rs'; auto.
  }

  destruct op; simpl in TR; ArgsInv; simpl in EV, EVFP; try (inv EV); try (inv EVFP); try (apply SAME; TranslOp; fail).
 move *)  exploit mk_mov_correct; eauto. intros [rs2 [A [B C]]].
  apply SAME. exists rs2. eauto.
 intconst *)  apply SAME. destruct (Int.eq_dec n Int.zero). subst n. TranslOp. TranslOp.
 longconst *)  apply SAME. destruct (Int64.eq_dec n Int64.zero). subst n. TranslOp. TranslOp.
 floatconst *)  apply SAME. destruct (Float.eq_dec n Float.zero). subst n. TranslOp. TranslOp.
 singleconst *)  apply SAME. destruct (Float32.eq_dec n Float32.zero). subst n. TranslOp. TranslOp.
 cast8signed *)  apply SAME. eapply mk_intconv_correct; eauto.
  simpl. match goal with |- context[match ?x with _ => _ end] => destruct x; auto end.
 cast8unsigned *)  apply SAME. eapply mk_intconv_correct; eauto.
  simpl. match goal with |- context[match ?x with _ => _ end] => destruct x; auto end.
 mulhs *)  apply SAME. TranslOp. destruct H1. Simplifs.
 mulhu *)  apply SAME. TranslOp. destruct H1. Simplifs.
 div *)  apply SAME.
  exploit (divs_mods_exists (rs RAX) (rs RCX)). left; congruence.
  intros (nh & nl & d & q & r & A & B & C & D & E & F).
  set (rs1 := nextinstr_nf (rs#RDX <- (Vint nh))).
  econstructor; split. rewrite <- (FP.emp_union_fp fp).
  eapply exec_straight_two with (rs2 := rs1). simpl. rewrite A. reflexivity. auto.
  simpl. change (rs1 RAX) with (rs RAX); rewrite B.
  change (rs1 RCX) with (rs RCX); rewrite C.
  rewrite D. reflexivity. destruct (Val.divs); inv H1; auto. auto. auto.
  split. change (Vint q = v). congruence.
  simpl; intros. destruct H3. unfold rs1; Simplifs.
 divu *)  apply SAME.
  exploit (divu_modu_exists (rs RAX) (rs RCX)). left; congruence.
  intros (n & d & q & r & B & C & D & E & F).
  set (rs1 := nextinstr_nf (rs#RDX <- Vzero)).
  econstructor; split. rewrite <- (FP.emp_union_fp fp).
  eapply exec_straight_two with (rs2 := rs1). reflexivity. auto.
  simpl. change (rs1 RAX) with (rs RAX); rewrite B.
  change (rs1 RCX) with (rs RCX); rewrite C.
  rewrite D. reflexivity. destruct Val.divu; inv H1; auto. auto. auto.
  split. change (Vint q = v). congruence.
  simpl; intros. destruct H3. unfold rs1; Simplifs.
 mod *)  apply SAME.
  exploit (divs_mods_exists (rs RAX) (rs RCX)). right; congruence.
  intros (nh & nl & d & q & r & A & B & C & D & E & F).
  set (rs1 := nextinstr_nf (rs#RDX <- (Vint nh))).
  econstructor; split. rewrite <- (FP.emp_union_fp fp).
  eapply exec_straight_two with (rs2 := rs1). simpl. rewrite A. reflexivity. auto.
  simpl. change (rs1 RAX) with (rs RAX); rewrite B.
  change (rs1 RCX) with (rs RCX); rewrite C.
  rewrite D. reflexivity. destruct Val.mods; inv H1; auto. auto. auto.
  split. change (Vint r = v). congruence.
  simpl; intros. destruct H3. unfold rs1; Simplifs.
 modu *)  apply SAME.
  exploit (divu_modu_exists (rs RAX) (rs RCX)). right; congruence.
  intros (n & d & q & r & B & C & D & E & F).
  set (rs1 := nextinstr_nf (rs#RDX <- Vzero)).
  econstructor; split. rewrite <- (FP.emp_union_fp fp).
  eapply exec_straight_two with (rs2 := rs1). reflexivity. auto.
  simpl. change (rs1 RAX) with (rs RAX); rewrite B.
  change (rs1 RCX) with (rs RCX); rewrite C.
  rewrite D. reflexivity. destruct Val.modu; inv H1; auto. auto. auto.
  split. change (Vint r = v). congruence.
  simpl; intros. destruct H3. unfold rs1; Simplifs.
 shrximm *)  apply SAME. destruct Val.shrx in H1; inv H1. eapply mk_shrximm_correct; eauto.
 lea *)  exploit transl_addressing_mode_32_correct; eauto. intros EA.
  TranslOp. simpl. destruct eval_addressing32 in H1; inv H1; auto.
  rewrite nextinstr_inv; auto with asmgen. rewrite Pregmap.gss. rewrite normalize_addrmode_32_correct; auto.
 mullhs *)  apply SAME. TranslOp. destruct H1. Simplifs.
 mullhu *)  apply SAME. TranslOp. destruct H1. Simplifs.
 divl *)  apply SAME.
  exploit (divls_modls_exists (rs RAX) (rs RCX)). left; congruence.
  intros (nh & nl & d & q & r & A & B & C & D & E & F).
  set (rs1 := nextinstr_nf (rs#RDX <- (Vlong nh))).
  econstructor; split. rewrite <- (FP.emp_union_fp fp).
  eapply exec_straight_two with (rs2 := rs1). simpl. rewrite A. reflexivity. auto.
  simpl. change (rs1 RAX) with (rs RAX); rewrite B.
  change (rs1 RCX) with (rs RCX); rewrite C.
  rewrite D. reflexivity. destruct Val.divls; inv H1; auto. auto. auto.
  split. change (Vlong q = v). congruence.
  simpl; intros. destruct H3. unfold rs1; Simplifs.
 divlu *)  apply SAME.
  exploit (divlu_modlu_exists (rs RAX) (rs RCX)). left; congruence.
  intros (n & d & q & r & B & C & D & E & F).
  set (rs1 := nextinstr_nf (rs#RDX <- (Vlong Int64.zero))).
  econstructor; split. rewrite <- (FP.emp_union_fp fp).
  eapply exec_straight_two with (rs2 := rs1). reflexivity. auto.
  simpl. change (rs1 RAX) with (rs RAX); rewrite B.
  change (rs1 RCX) with (rs RCX); rewrite C.
  rewrite D. reflexivity. destruct Val.divlu in H1; inv H1; auto. auto. auto.
  split. change (Vlong q = v). congruence.
  simpl; intros. destruct H3. unfold rs1; Simplifs.
 modl *)  apply SAME.
  exploit (divls_modls_exists (rs RAX) (rs RCX)). right; congruence.
  intros (nh & nl & d & q & r & A & B & C & D & E & F).
  set (rs1 := nextinstr_nf (rs#RDX <- (Vlong nh))).
  econstructor; split. rewrite <- (FP.emp_union_fp fp).
  eapply exec_straight_two with (rs2 := rs1). simpl. rewrite A. reflexivity. auto.
  simpl. change (rs1 RAX) with (rs RAX); rewrite B.
  change (rs1 RCX) with (rs RCX); rewrite C.
  rewrite D. reflexivity. destruct Val.modls in H1; inv H1; auto. auto. auto.
  split. change (Vlong r = v). congruence.
  simpl; intros. destruct H3. unfold rs1; Simplifs.
 modlu *)  apply SAME.
  exploit (divlu_modlu_exists (rs RAX) (rs RCX)). right; congruence.
  intros (n & d & q & r & B & C & D & E & F).
  set (rs1 := nextinstr_nf (rs#RDX <- (Vlong Int64.zero))).
  econstructor; split. rewrite <- (FP.emp_union_fp fp).
  eapply exec_straight_two with (rs2 := rs1). reflexivity. auto.
  simpl. change (rs1 RAX) with (rs RAX); rewrite B.
  change (rs1 RCX) with (rs RCX); rewrite C.
  rewrite D. reflexivity. destruct Val.modlu in H1; inv H1; auto. auto. auto.
  split. change (Vlong r = v). congruence.
  simpl; intros. destruct H3. unfold rs1; Simplifs.
 shrxlimm *)  apply SAME. destruct Val.shrxl in H1; inv H1. eapply mk_shrxlimm_correct; eauto.
 leal *)  exploit transl_addressing_mode_64_correct; eauto. intros EA.
  generalize (normalize_addrmode_64_correct x rs). destruct (normalize_addrmode_64 x) as [am' [delta|]]; intros EV.
  econstructor; split. rewrite <- (FP.emp_union_fp fp). eapply exec_straight_two.
  simpl. reflexivity. auto. simpl. reflexivity. destruct eval_addressing64 in H1; inv H1; auto. auto. auto.
  split. rewrite nextinstr_nf_inv by auto. rewrite Pregmap.gss. rewrite nextinstr_inv by auto with asmgen.
  rewrite Pregmap.gss. rewrite <- EV; auto.
  intros; Simplifs.
  TranslOp. destruct eval_addressing64 in H1; inv H1; auto.
  rewrite nextinstr_inv; auto with asmgen. rewrite Pregmap.gss; auto. rewrite <- EV; auto.
 intoffloat *)  apply SAME. TranslOp. destruct Val.intoffloat in H1; inv H1; auto. rewrite H0; auto.
 floatofint *)  apply SAME. TranslOp. SimplifFPs; inv H1; auto. rewrite H0; auto.
 intofsingle *)  apply SAME. TranslOp. SimplifFPs; inv H1; auto. rewrite H0; auto.
 singleofint *)  apply SAME. TranslOp. SimplifFPs; inv H1; auto. rewrite H0; auto.
 longoffloat *)  apply SAME. TranslOp. SimplifFPs; inv H1; auto. rewrite H0; auto.
 floatoflong *)  apply SAME. TranslOp. SimplifFPs; inv H1; auto. rewrite H0; auto.
 longofsingle *)  apply SAME. TranslOp. SimplifFPs; inv H1; auto. rewrite H0; auto.
 singleoflong *)  apply SAME. TranslOp. SimplifFPs; inv H1; auto. rewrite H0; auto.
 condition *)  pose proof (transl_cond_correct cond args _ _ rs m EQ0); eauto.
  destruct eval_condition eqn:EVAL; try discriminate.
  destruct H as [rs' [fp' [P [Q [R R']]]]].
  simpl in *.
  destruct eval_condition_fp eqn:EVALFP; try congruence. inv H1. inv R. inv H0.
  exploit mk_setcc_correct; eauto. intros [rs3 [S [T U]]].
  destruct eval_condition in EVAL, Q; [|inv EVAL]. inv EVAL.
  exists rs3.
  split. rewrite <- (FP.fp_union_emp fp'). eapply exec_straight_trans. eexact P. eexact S.
  split. rewrite T. rewrite Q. simpl. destruct b; auto.
  intros. transitivity (rs' r); auto.
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#RSP) addr (map rs (map preg_of args)) = Some a ->
  Mem.loadv chunk m a = Some v ->
  exists rs',
     exec_straight ge fn c rs m (loadv_fp chunk a) k rs' m
  /\ rs'#(preg_of dest) = v
  /\ forall r, data_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.
  assert (EA': eval_addrmode ge x rs = a). destruct a; simpl in H1; try discriminate; inv EA; auto.
  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.offset_ptr (rs PC) Ptrofs.one).
    transitivity (Val.offset_ptr ((rs#(preg_of dest) <- v) PC) Ptrofs.one).
    auto. decEq. apply Pregmap.gso; auto with asmgen.
  exists rs2. split.
  destruct chunk; ArgsInv; apply exec_straight_one; auto.
  split. unfold rs2. rewrite nextinstr_nf_inv1. Simplifs. apply preg_of_data.
  intros. unfold rs2. Simplifs.
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#RSP) addr (map rs (map preg_of args)) = Some a ->
  Mem.storev chunk m a (rs (preg_of src)) = Some m' ->
  exists rs',
     exec_straight ge fn c rs m (storev_fp chunk a) k rs' m'
  /\ forall r, data_preg r = true -> preg_notin r (destroyed_by_store chunk addr) -> rs'#r = rs#r.
Proof.
  unfold transl_store; intros. monadInv H.
  exploit transl_addressing_mode_correct; eauto. intro EA.
  assert (EA': eval_addrmode ge x rs = a). destruct a; simpl in H1; try discriminate; inv EA; auto.
  rewrite <- EA' in H1|- * . destruct chunk; ArgsInv.
 int8signed *)  eapply mk_storebyte_correct; eauto.
  destruct (eval_addrmode ge x rs); simpl; auto. rewrite <- Mem.store_signed_unsigned_8; auto.
 int8unsigned *)  eapply mk_storebyte_correct; eauto.
 int16signed *)  econstructor; split.
  apply exec_straight_one. simpl. unfold exec_store.
  replace (Mem.storev Mint16unsigned m (eval_addrmode ge x rs) (rs x0))
     with (Mem.storev Mint16signed m (eval_addrmode ge x rs) (rs x0)).
  rewrite H1. eauto.
  destruct (eval_addrmode ge x rs); simpl; auto. rewrite Mem.store_signed_unsigned_16; auto.
  auto. auto.
  intros. Simplifs.
 int16unsigned *)  econstructor; split.
  apply exec_straight_one. simpl. unfold exec_store. rewrite H1. eauto. auto. auto.
  intros. Simplifs.
 int32 *)  econstructor; split.
  apply exec_straight_one. simpl. unfold exec_store. rewrite H1. eauto. auto. auto.
  intros. Simplifs.
 int64 *)  econstructor; split.
  apply exec_straight_one. simpl. unfold exec_store. rewrite H1. eauto. auto. auto.
  intros. Simplifs.
 float32 *)  econstructor; split.
  apply exec_straight_one. simpl. unfold exec_store. rewrite H1. eauto. auto. auto.
  intros. Transparent destroyed_by_store. simpl in H2. simpl. Simplifs.
 float64 *)  econstructor; split.
  apply exec_straight_one. simpl. unfold exec_store. rewrite H1. eauto. auto. auto.
  intros. Simplifs.
Qed.

End CONSTRUCTORS.