(* *********************************************************************)
(*                                                                     *)
(*              The Compcert verified compiler                         *)
(*                                                                     *)
(*          Xavier Leroy, INRIA Paris-Rocquencourt                     *)
(*                                                                     *)
(*  Copyright Institut National de Recherche en Informatique et en     *)
(*  Automatique.  All rights reserved.  This file is distributed       *)
(*  under the terms of the INRIA Non-Commercial License Agreement.     *)
(*                                                                     *)
(* *********************************************************************)

(** Correctness proof for the [Allocation] pass (validated translation from
  RTL to LTL). *)

Require Import FunInd.
Require Import FSets.
Require Import Coqlib Ordered Maps Errors Integers Floats.
Require Import AST Linking Lattice Kildall.
Require Import Values Memory Globalenvs Events Smallstep.
Require Archi.
Require Import Op Registers RTL Locations Conventions RTLtyping LTL.
Require Import Allocation.

Definition match_prog (p: RTL.program) (tp: LTL.program) :=
  match_program (fun _ f tf => transf_fundef f = OK tf) eq p tp.

Lemma transf_program_match:
  forall p tp, transf_program p = OK tp -> match_prog p tp.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. eapply match_transform_partial_program; eauto.
Qed.

(** * Soundness of structural checks *)

Definition expand_move (m: move) : instruction :=
  match m with
  | MV (R src) (R dst) => Lop Omove (src::nil) dst
  | MV (S sl ofs ty) (R dst) => Lgetstack sl ofs ty dst
  | MV (R src) (S sl ofs ty) => Lsetstack src sl ofs ty
  | MV (S _ _ _) (S _ _ _) => Lreturn    (**r should never happen *)
  | MVmakelong src1 src2 dst => Lop Omakelong (src1::src2::nil) dst
  | MVlowlong src dst => Lop Olowlong (src::nil) dst
  | MVhighlong src dst => Lop Ohighlong (src::nil) dst
  end.

Definition expand_moves (mv: moves) (k: bblock) : bblock :=
  List.map expand_move mv ++ k.

Definition wf_move (m: move) : Prop :=
  match m with
  | MV (S _ _ _) (S _ _ _) => False
  | _ => True
  end.

Definition wf_moves (mv: moves) : Prop :=
  List.Forall wf_move mv.

Inductive expand_block_shape: block_shape -> RTL.instruction -> LTL.bblock -> Prop :=
  | ebs_nop: forall mv s k,
      wf_moves mv ->
      expand_block_shape (BSnop mv s)
                         (Inop s)
                         (expand_moves mv (Lbranch s :: k))
  | ebs_move: forall src dst mv s k,
      wf_moves mv ->
      expand_block_shape (BSmove src dst mv s)
                         (Iop Omove (src :: nil) dst s)
                         (expand_moves mv (Lbranch s :: k))
  | ebs_makelong: forall src1 src2 dst mv s k,
      wf_moves mv ->
      Archi.splitlong = true ->
      expand_block_shape (BSmakelong src1 src2 dst mv s)
                         (Iop Omakelong (src1 :: src2 :: nil) dst s)
                         (expand_moves mv (Lbranch s :: k))
  | ebs_lowlong: forall src dst mv s k,
      wf_moves mv ->
      Archi.splitlong = true ->
      expand_block_shape (BSlowlong src dst mv s)
                         (Iop Olowlong (src :: nil) dst s)
                         (expand_moves mv (Lbranch s :: k))
  | ebs_highlong: forall src dst mv s k,
      wf_moves mv ->
      Archi.splitlong = true ->
      expand_block_shape (BShighlong src dst mv s)
                         (Iop Ohighlong (src :: nil) dst s)
                         (expand_moves mv (Lbranch s :: k))
  | ebs_op: forall op args res mv1 args' res' mv2 s k,
      wf_moves mv1 -> wf_moves mv2 ->
      expand_block_shape (BSop op args res mv1 args' res' mv2 s)
                         (Iop op args res s)
                         (expand_moves mv1
                           (Lop op args' res' :: expand_moves mv2 (Lbranch s :: k)))
  | ebs_op_dead: forall op args res mv s k,
      wf_moves mv ->
      expand_block_shape (BSopdead op args res mv s)
                         (Iop op args res s)
                         (expand_moves mv (Lbranch s :: k))
  | ebs_load: forall chunk addr args dst mv1 args' dst' mv2 s k,
      wf_moves mv1 -> wf_moves mv2 ->
      expand_block_shape (BSload chunk addr args dst mv1 args' dst' mv2 s)
                         (Iload chunk addr args dst s)
                         (expand_moves mv1
                           (Lload chunk addr args' dst' :: expand_moves mv2 (Lbranch s :: k)))
  | ebs_load2: forall addr addr2 args dst mv1 args1' dst1' mv2 args2' dst2' mv3 s k,
      wf_moves mv1 -> wf_moves mv2 -> wf_moves mv3 ->
      Archi.splitlong = true ->
      offset_addressing addr 4 = Some addr2 ->
      expand_block_shape (BSload2 addr addr2 args dst mv1 args1' dst1' mv2 args2' dst2' mv3 s)
                         (Iload Mint64 addr args dst s)
                         (expand_moves mv1
                           (Lload Mint32 addr args1' dst1' ::
                           expand_moves mv2
                             (Lload Mint32 addr2 args2' dst2' ::
                              expand_moves mv3 (Lbranch s :: k))))
  | ebs_load2_1: forall addr args dst mv1 args' dst' mv2 s k,
      wf_moves mv1 -> wf_moves mv2 ->
      Archi.splitlong = true ->
      expand_block_shape (BSload2_1 addr args dst mv1 args' dst' mv2 s)
                         (Iload Mint64 addr args dst s)
                         (expand_moves mv1
                           (Lload Mint32 addr args' dst' ::
                            expand_moves mv2 (Lbranch s :: k)))
  | ebs_load2_2: forall addr addr2 args dst mv1 args' dst' mv2 s k,
      wf_moves mv1 -> wf_moves mv2 ->
      Archi.splitlong = true ->
      offset_addressing addr 4 = Some addr2 ->
      expand_block_shape (BSload2_2 addr addr2 args dst mv1 args' dst' mv2 s)
                         (Iload Mint64 addr args dst s)
                         (expand_moves mv1
                           (Lload Mint32 addr2 args' dst' ::
                            expand_moves mv2 (Lbranch s :: k)))
  | ebs_load_dead: forall chunk addr args dst mv s k,
      wf_moves mv ->
      expand_block_shape (BSloaddead chunk addr args dst mv s)
                         (Iload chunk addr args dst s)
                         (expand_moves mv (Lbranch s :: k))
  | ebs_store: forall chunk addr args src mv1 args' src' s k,
      wf_moves mv1 ->
      expand_block_shape (BSstore chunk addr args src mv1 args' src' s)
                         (Istore chunk addr args src s)
                         (expand_moves mv1
                           (Lstore chunk addr args' src' :: Lbranch s :: k))
  | ebs_store2: forall addr addr2 args src mv1 args1' src1' mv2 args2' src2' s k,
      wf_moves mv1 -> wf_moves mv2 ->
      Archi.splitlong = true ->
      offset_addressing addr 4 = Some addr2 ->
      expand_block_shape (BSstore2 addr addr2 args src mv1 args1' src1' mv2 args2' src2' s)
                         (Istore Mint64 addr args src s)
                         (expand_moves mv1
                           (Lstore Mint32 addr args1' src1' ::
                            expand_moves mv2
                             (Lstore Mint32 addr2 args2' src2' ::
                              Lbranch s :: k)))
  | ebs_call: forall sg ros args res mv1 ros' mv2 s k,
      wf_moves mv1 -> wf_moves mv2 ->
      expand_block_shape (BScall sg ros args res mv1 ros' mv2 s)
                         (Icall sg ros args res s)
                         (expand_moves mv1
                           (Lcall sg ros' :: expand_moves mv2 (Lbranch s :: k)))
  | ebs_tailcall: forall sg ros args mv ros' k,
      wf_moves mv ->
      expand_block_shape (BStailcall sg ros args mv ros')
                         (Itailcall sg ros args)
                         (expand_moves mv (Ltailcall sg ros' :: k))
  | ebs_builtin: forall ef args res mv1 args' res' mv2 s k,
      wf_moves mv1 -> wf_moves mv2 ->
      expand_block_shape (BSbuiltin ef args res mv1 args' res' mv2 s)
                         (Ibuiltin ef args res s)
                         (expand_moves mv1
                           (Lbuiltin ef args' res' :: expand_moves mv2 (Lbranch s :: k)))
  | ebs_cond: forall cond args mv args' s1 s2 k,
      wf_moves mv ->
      expand_block_shape (BScond cond args mv args' s1 s2)
                         (Icond cond args s1 s2)
                         (expand_moves mv (Lcond cond args' s1 s2 :: k))
  | ebs_jumptable: forall arg mv arg' tbl k,
      wf_moves mv ->
      expand_block_shape (BSjumptable arg mv arg' tbl)
                         (Ijumptable arg tbl)
                         (expand_moves mv (Ljumptable arg' tbl :: k))
  | ebs_return: forall optarg mv k,
      wf_moves mv ->
      expand_block_shape (BSreturn optarg mv)
                         (Ireturn optarg)
                         (expand_moves mv (Lreturn :: k)).

Ltac MonadInv :=
  match goal with
  | [ H: match ?x with Some _ => _ | None => None end = Some _ |- _ ] =>
        destruct x as [] eqn:? ; [MonadInv|discriminate]
  | [ H: match ?x with left _ => _ | right _ => None end = Some _ |- _ ] =>
        destruct x; [MonadInv|discriminate]
  | [ H: match negb (proj_sumbool ?x) with true => _ | false => None end = Some _ |- _ ] =>
        destruct x; [discriminate|simpl in H; MonadInv]
  | [ H: match negb ?x with true => _ | false => None end = Some _ |- _ ] =>
        destruct x as [] eqn:? ; [discriminate|simpl in H; MonadInv]
  | [ H: match ?x with true => _ | false => None end = Some _ |- _ ] =>
        destruct x as [] eqn:? ; [MonadInv|discriminate]
  | [ H: match ?x with (_, _) => _ end = Some _ |- _ ] =>
        destruct x as [] eqn:? ; MonadInv
  | [ H: Some _ = Some _ |- _ ] =>
        inv H; MonadInv
  | [ H: None = Some _ |- _ ] =>
        discriminate
  | _ =>
        idtac
  end.

Remark expand_moves_cons:
  forall m accu b,
  expand_moves (rev (m :: accu)) b = expand_moves (rev accu) (expand_move m :: b).
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  unfold expand_moves; intros. simpl. rewrite map_app. rewrite app_ass. auto.
Qed.

Lemma extract_moves_sound:
  forall b mv b',
  extract_moves nil b = (mv, b') ->
  wf_moves mv /\ b = expand_moves mv b'.
Proof.
  assert (BASE:
      forall accu b,
      wf_moves accu ->
      wf_moves (List.rev accu) /\ expand_moves (List.rev accu) b = expand_moves (List.rev accu) b).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
   { intros; split; auto. unfold wf_moves in *; rewrite Forall_forall in *.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
     intros. apply H. rewrite <- in_rev in H0; auto. }

  assert (IND: forall b accu mv b',
          extract_moves accu b = (mv, b') ->
          wf_moves accu ->
          wf_moves mv /\ expand_moves (List.rev accu) b = expand_moves mv b').
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  { induction b; simpl; intros.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  - inv H. auto.
  - destruct a; try (inv H; apply BASE; auto; fail).
  + destruct (is_move_operation op args) as [arg|] eqn:E.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    exploit is_move_operation_correct; eauto. intros [A B]; subst.
    (* reg-reg move *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    exploit IHb; eauto. constructor; auto. exact I. rewrite expand_moves_cons; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    inv H; apply BASE; auto.
  + (* stack-reg move *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    exploit IHb; eauto. constructor; auto. exact I. rewrite expand_moves_cons; auto.
  + (* reg-stack move *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    exploit IHb; eauto. constructor; auto. exact I. rewrite expand_moves_cons; auto.
  }
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. exploit IND; eauto. constructor.
Qed.

Lemma extract_moves_ext_sound:
  forall b mv b',
  extract_moves_ext nil b = (mv, b') ->
  wf_moves mv /\ b = expand_moves mv b'.
Proof.
  assert (BASE:
      forall accu b,
      wf_moves accu ->
      wf_moves (List.rev accu) /\ expand_moves (List.rev accu) b = expand_moves (List.rev accu) b).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
   { intros; split; auto. unfold wf_moves in *; rewrite Forall_forall in *.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
     intros. apply H. rewrite <- in_rev in H0; auto. }

  assert (IND: forall b accu mv b',
          extract_moves_ext accu b = (mv, b') ->
          wf_moves accu ->
          wf_moves mv /\ expand_moves (List.rev accu) b = expand_moves mv b').
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  { induction b; simpl; intros.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  - inv H. auto.
  - destruct a; try (inv H; apply BASE; auto; fail).
  + destruct (classify_operation op args).
  * (* reg-reg move *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    exploit IHb; eauto. constructor; auto. exact I. rewrite expand_moves_cons; auto.
  * (* makelong *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    exploit IHb; eauto. constructor; auto. exact I. rewrite expand_moves_cons; auto.
  * (* lowlong *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    exploit IHb; eauto. constructor; auto. exact I. rewrite expand_moves_cons; auto.
  * (* highlong *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    exploit IHb; eauto. constructor; auto. exact I. rewrite expand_moves_cons; auto.
  * (* default *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    inv H; apply BASE; auto.
  + (* stack-reg move *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    exploit IHb; eauto. constructor; auto. exact I. rewrite expand_moves_cons; auto.
  + (* reg-stack move *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    exploit IHb; eauto. constructor; auto. exact I. rewrite expand_moves_cons; auto.
  }
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. exploit IND; eauto. constructor.
Qed.

Lemma check_succ_sound:
  forall s b, check_succ s b = true -> exists k, b = Lbranch s :: k.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. destruct b; simpl in H; try discriminate.
(* Goal: @ex (list instruction) (fun k : list instruction => @eq bblock (@cons instruction i b) (@cons instruction (Lbranch s) k)) *)
  destruct i; try discriminate.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  destruct (peq s s0); simpl in H; inv H. exists b; auto.
Qed.

Ltac UseParsingLemmas :=
  match goal with
  | [ H: extract_moves nil _ = (_, _) |- _ ] =>
      destruct (extract_moves_sound _ _ _ H); clear H; subst; UseParsingLemmas
  | [ H: extract_moves_ext nil _ = (_, _) |- _ ] =>
      destruct (extract_moves_ext_sound _ _ _ H); clear H; subst; UseParsingLemmas
  | [ H: check_succ _ _ = true |- _ ] =>
      try (discriminate H);
      destruct (check_succ_sound _ _ H); clear H; subst; UseParsingLemmas
  | _ => idtac
  end.

Lemma pair_instr_block_sound:
  forall i b bsh,
  pair_instr_block i b = Some bsh -> expand_block_shape bsh i b.
Proof.
  assert (OP: forall op args res s b bsh,
    pair_Iop_block op args res s b = Some bsh -> expand_block_shape bsh (Iop op args res s) b).
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
  {
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
    unfold pair_Iop_block; intros. MonadInv. destruct b0.
(* Goal: expand_block_shape bsh (Iop Ohighlong (@cons reg arg (@nil reg)) r n) b *)
    MonadInv; UseParsingLemmas.
(* Goal: expand_block_shape bsh (Iop Ohighlong (@cons reg arg (@nil reg)) r n) b *)
    destruct i; MonadInv; UseParsingLemmas.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    eapply ebs_op; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    inv H0. eapply ebs_op_dead; eauto. }

(* Goal: expand_block_shape bsh (Iop Ohighlong (@cons reg arg (@nil reg)) r n) b *)
  intros; destruct i; simpl in H; MonadInv; UseParsingLemmas.
- (* nop *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto.
- (* op *)
(* Goal: expand_block_shape bsh (Iop o l r n) b *)
  destruct (classify_operation o l).
+ (* move *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  MonadInv; UseParsingLemmas. econstructor; eauto.
+ (* makelong *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  destruct Archi.splitlong eqn:SL; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  MonadInv; UseParsingLemmas. econstructor; eauto.
+ (* lowlong *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  destruct Archi.splitlong eqn:SL; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  MonadInv; UseParsingLemmas. econstructor; eauto.
+ (* highlong *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  destruct Archi.splitlong eqn:SL; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  MonadInv; UseParsingLemmas. econstructor; eauto.
+ (* other ops *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eauto.
- (* load *)
(* Goal: expand_block_shape bsh (Iop Ohighlong (@cons reg arg (@nil reg)) r n) b *)
  destruct b0 as [ | [] b0]; MonadInv; UseParsingLemmas.
(* Goal: expand_block_shape bsh (Iop Ohighlong (@cons reg arg (@nil reg)) r n) b *)
  destruct (chunk_eq m Mint64 && Archi.splitlong) eqn:A; MonadInv; UseParsingLemmas.
(* Goal: expand_block_shape bsh (Iop Ohighlong (@cons reg arg (@nil reg)) r n) b *)
  destruct b as [ | [] b]; MonadInv; UseParsingLemmas.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  InvBooleans. subst m. eapply ebs_load2; eauto.
(* Goal: satisf (init_regs vl (@cons reg r1 rl)) ls e *)
  InvBooleans. subst m.
(* Goal: expand_block_shape bsh (Iload Mint64 a l r n) (expand_moves m0 (@cons instruction (Lload Mint32 addr args dst) (expand_moves m1 (@cons instruction (Lbranch s) b)))) *)
(* Goal: expand_block_shape (BSload chunk addr l r m0 args dst m1 n) (Iload chunk addr l r n) (expand_moves m0 (@cons instruction (Lload chunk addr args dst) (expand_moves m1 (@cons instruction (Lbranch n) x)))) *)
(* Goal: expand_block_shape (BSloaddead m a l r m0 n) (Iload m a l r n) (expand_moves m0 (@cons instruction (Lbranch s) b0)) *)
  destruct (eq_addressing a addr).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  inv H; inv H2. eapply ebs_load2_1; eauto.
(* Goal: expand_block_shape bsh (Iload Mint64 a l r n) (expand_moves m0 (@cons instruction (Lload Mint32 addr args dst) (expand_moves m1 (@cons instruction (Lbranch s) b)))) *)
(* Goal: expand_block_shape (BSload chunk addr l r m0 args dst m1 n) (Iload chunk addr l r n) (expand_moves m0 (@cons instruction (Lload chunk addr args dst) (expand_moves m1 (@cons instruction (Lbranch n) x)))) *)
(* Goal: expand_block_shape (BSloaddead m a l r m0 n) (Iload m a l r n) (expand_moves m0 (@cons instruction (Lbranch s) b0)) *)
  destruct (option_eq eq_addressing (offset_addressing a 4) (Some addr)).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  inv H; inv H2. eapply ebs_load2_2; eauto.
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls1 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls2 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
  discriminate.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply ebs_load; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  inv H. eapply ebs_load_dead; eauto.
- (* store *)
(* Goal: transf_function_spec f tf *)
  destruct b0; MonadInv. destruct i; MonadInv; UseParsingLemmas.
(* Goal: expand_block_shape bsh (Iop Ohighlong (@cons reg arg (@nil reg)) r n) b *)
  destruct (chunk_eq m Mint64 && Archi.splitlong) eqn:A; MonadInv; UseParsingLemmas.
(* Goal: expand_block_shape bsh (Iop Ohighlong (@cons reg arg (@nil reg)) r n) b *)
  destruct b as [ | [] b]; MonadInv; UseParsingLemmas.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  InvBooleans. subst m. eapply ebs_store2; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply ebs_store; eauto.
- (* call *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  destruct b0 as [|[] ]; MonadInv; UseParsingLemmas. econstructor; eauto.
- (* tailcall *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  destruct b0 as [|[] ]; MonadInv; UseParsingLemmas. econstructor; eauto.
- (* builtin *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  destruct b1 as [|[] ]; MonadInv; UseParsingLemmas. econstructor; eauto.
- (* cond *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  destruct b0 as [|[]]; MonadInv; UseParsingLemmas. econstructor; eauto.
- (* jumptable *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  destruct b0 as [|[]]; MonadInv; UseParsingLemmas. econstructor; eauto.
- (* return *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  destruct b0 as [|[]]; MonadInv; UseParsingLemmas. econstructor; eauto.
Qed.

Lemma matching_instr_block:
  forall f1 f2 pc bsh i,
  (pair_codes f1 f2)!pc = Some bsh ->
  (RTL.fn_code f1)!pc = Some i ->
  exists b, (LTL.fn_code f2)!pc = Some b /\ expand_block_shape bsh i b.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. unfold pair_codes in H. rewrite PTree.gcombine in H; auto. rewrite H0 in H.
(* Goal: @ex bblock (fun b : bblock => and (@eq (option bblock) (@PTree.get bblock pc (fn_code f2)) (@Some bblock b)) (expand_block_shape bsh i b)) *)
  destruct (LTL.fn_code f2)!pc as [b|].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exists b; split; auto. apply pair_instr_block_sound; auto.
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls1 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls2 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
  discriminate.
Qed.

(** * Properties of equations *)

Module ESF := FSetFacts.Facts(EqSet).
Module ESP := FSetProperties.Properties(EqSet).
Module ESD := FSetDecide.Decide(EqSet).

Definition sel_val (k: equation_kind) (v: val) : val :=
  match k with
  | Full => v
  | Low => Val.loword v
  | High => Val.hiword v
  end.

(** A set of equations [e] is satisfied in a RTL pseudoreg state [rs]
  and an LTL location state [ls] if, for every equation [r = l [k]] in [e],
  [sel_val k (rs#r)] (the [k] fragment of [r]'s value in the RTL code)
  is less defined than [ls l] (the value of [l] in the LTL code). *)

Definition satisf (rs: regset) (ls: locset) (e: eqs) : Prop :=
  forall q, EqSet.In q e -> Val.lessdef (sel_val (ekind q) rs#(ereg q)) (ls (eloc q)).

Lemma empty_eqs_satisf:
  forall rs ls, satisf rs ls empty_eqs.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  unfold empty_eqs; intros; red; intros. ESD.fsetdec.
Qed.

Lemma satisf_incr:
  forall rs ls (e1 e2: eqs),
  satisf rs ls e2 -> EqSet.Subset e1 e2 -> satisf rs ls e1.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  unfold satisf; intros. apply H. ESD.fsetdec.
Qed.

Lemma satisf_undef_reg:
  forall rs ls e r,
  satisf rs ls e ->
  satisf (rs#r <- Vundef) ls e.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros; red; intros. rewrite Regmap.gsspec. destruct (peq (ereg q) r); auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  destruct (ekind q); simpl; auto.
Qed.

Lemma add_equation_lessdef:
  forall rs ls q e,
  satisf rs ls (add_equation q e) -> Val.lessdef (sel_val (ekind q) rs#(ereg q)) (ls (eloc q)).
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. apply H. unfold add_equation. simpl. apply EqSet.add_1. auto.
Qed.

Lemma add_equation_satisf:
  forall rs ls q e,
  satisf rs ls (add_equation q e) -> satisf rs ls e.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. eapply satisf_incr; eauto. unfold add_equation. simpl. ESD.fsetdec.
Qed.

Lemma add_equations_satisf:
  forall rs ls rl ml e e',
  add_equations rl ml e = Some e' ->
  satisf rs ls e' -> satisf rs ls e.
Proof.
(* Goal: transf_function_spec f tf *)
  induction rl; destruct ml; simpl; intros; MonadInv.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply add_equation_satisf; eauto.
Qed.

Lemma add_equations_lessdef:
  forall rs ls rl ml e e',
  add_equations rl ml e = Some e' ->
  satisf rs ls e' ->
  Val.lessdef_list (rs##rl) (reglist ls ml).
Proof.
(* Goal: transf_function_spec f tf *)
  induction rl; destruct ml; simpl; intros; MonadInv.
(* Goal: Val.has_type_list (@nil val) (sig_args signature_main) *)
  constructor.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  constructor; eauto.
(* Goal: Val.lessdef (Regmap.get val a rs) (ls (R m)) *)
  apply add_equation_lessdef with (e := e) (q := Eq Full a (R m)).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply add_equations_satisf; eauto.
Qed.

Lemma add_equations_args_satisf:
  forall rs ls rl tyl ll e e',
  add_equations_args rl tyl ll e = Some e' ->
  satisf rs ls e' -> satisf rs ls e.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros until e'. functional induction (add_equations_args rl tyl ll e); intros.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
- inv H; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
- eapply add_equation_satisf; eauto.
- discriminate.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
- eapply add_equation_satisf. eapply add_equation_satisf. eauto.
- congruence.
Qed.

Lemma val_longofwords_eq_1:
  forall v,
  Val.has_type v Tlong -> Archi.ptr64 = false ->
  Val.longofwords (Val.hiword v) (Val.loword v) = v.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. red in H. destruct v; try contradiction.
- reflexivity.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
- simpl. rewrite Int64.ofwords_recompose. auto.
- congruence.
Qed.

Lemma val_longofwords_eq_2:
  forall v,
  Val.has_type v Tlong -> Archi.splitlong = true ->
  Val.longofwords (Val.hiword v) (Val.loword v) = v.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. apply Archi.splitlong_ptr32 in H0. apply val_longofwords_eq_1; assumption.
Qed.

Lemma add_equations_args_lessdef:
  forall rs ls rl tyl ll e e',
  add_equations_args rl tyl ll e = Some e' ->
  satisf rs ls e' ->
  Val.has_type_list (rs##rl) tyl ->
  Val.lessdef_list (rs##rl) (map (fun p => Locmap.getpair p ls) ll).
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros until e'. functional induction (add_equations_args rl tyl ll e); simpl; intros.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
- inv H; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
- destruct H1. constructor; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply add_equation_lessdef with (q := Eq Full r1 l1). eapply add_equations_args_satisf; eauto.
- discriminate.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
- destruct H1. constructor; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite <- (val_longofwords_eq_1 (rs#r1)) by auto. apply Val.longofwords_lessdef.
  eapply add_equation_lessdef with (q := Eq High r1 l1).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply add_equation_satisf. eapply add_equations_args_satisf; eauto.
  eapply add_equation_lessdef with (q := Eq Low r1 l2).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply add_equations_args_satisf; eauto.
- discriminate.
Qed.

Lemma add_equation_ros_satisf:
  forall rs ls ros mos e e',
  add_equation_ros ros mos e = Some e' ->
  satisf rs ls e' -> satisf rs ls e.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  unfold add_equation_ros; intros. destruct ros; destruct mos; MonadInv.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply add_equation_satisf; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  auto.
Qed.

Lemma remove_equation_satisf:
  forall rs ls q e,
  satisf rs ls e -> satisf rs ls (remove_equation q e).
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. eapply satisf_incr; eauto. unfold remove_equation; simpl. ESD.fsetdec.
Qed.

Lemma remove_equation_res_satisf:
  forall rs ls r l e e',
  remove_equations_res r l e = Some e' ->
  satisf rs ls e -> satisf rs ls e'.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. functional inversion H.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  apply remove_equation_satisf; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  apply remove_equation_satisf. apply remove_equation_satisf; auto.
Qed.

Remark select_reg_l_monotone:
  forall r q1 q2,
  OrderedEquation.eq q1 q2 \/ OrderedEquation.lt q1 q2 ->
  select_reg_l r q1 = true -> select_reg_l r q2 = true.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  unfold select_reg_l; intros. destruct H.
(* Goal: @eq signature (funsig tf) signature_main *)
(* Goal: match_states (RTL.Callstate (@nil RTL.stackframe) f (@nil val) m0) (Callstate (@nil stackframe) tf (Locmap.init Vundef) m0) *)
  red in H. congruence.
  rewrite Pos.leb_le in *. red in H. destruct H as [A | [A B]].
(* Goal: Pos.le (ereg q2) r *)
(* Goal: Pos.le (ereg q2) r *)
  red in A. zify; omega.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite <- A; auto.
Qed.

Remark select_reg_h_monotone:
  forall r q1 q2,
  OrderedEquation.eq q1 q2 \/ OrderedEquation.lt q2 q1 ->
  select_reg_h r q1 = true -> select_reg_h r q2 = true.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  unfold select_reg_h; intros. destruct H.
(* Goal: @eq signature (funsig tf) signature_main *)
(* Goal: match_states (RTL.Callstate (@nil RTL.stackframe) f (@nil val) m0) (Callstate (@nil stackframe) tf (Locmap.init Vundef) m0) *)
  red in H. congruence.
  rewrite Pos.leb_le in *. red in H. destruct H as [A | [A B]].
(* Goal: Pos.le (ereg q2) r *)
(* Goal: Pos.le (ereg q2) r *)
  red in A. zify; omega.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite A; auto.
Qed.

Remark select_reg_charact:
  forall r q, select_reg_l r q = true /\ select_reg_h r q = true <-> ereg q = r.
Proof.
(* Goal: forall (r : reg) (q : equation), iff (and (@eq bool (select_reg_l r q) true) (@eq bool (select_reg_h r q) true)) (@eq reg (ereg q) r) *)
  unfold select_reg_l, select_reg_h; intros; split.
(* Goal: Pos.le (ereg q2) r *)
(* Goal: Pos.le (ereg q2) r *)
  rewrite ! Pos.leb_le. unfold reg; zify; omega.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. rewrite H. rewrite ! Pos.leb_refl; auto.
Qed.

Lemma reg_unconstrained_sound:
  forall r e q,
  reg_unconstrained r e = true ->
  EqSet.In q e ->
  ereg q <> r.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  unfold reg_unconstrained; intros. red; intros.
(* Goal: or (and (@eq equation_kind (ekind q) High) (@eq loc (eloc q) l1)) (and (@eq equation_kind (ekind q) Low) (@eq loc (eloc q) l2)) *)
(* Goal: forall (x1 x2 : equation) (_ : @eq OrderedEquation.t x1 x2), @eq bool match ekind x1 with | Full => false | Low => @proj_sumbool (@eq loc l2 (eloc x1)) (not (@eq loc l2 (eloc x1))) (Loc.eq l2 (eloc x1)) | High => @proj_sumbool (@eq loc l1 (eloc x1)) (not (@eq loc l1 (eloc x1))) (Loc.eq l1 (eloc x1)) end match ekind x2 with | Full => false | Low => @proj_sumbool (@eq loc l2 (eloc x2)) (not (@eq loc l2 (eloc x2))) (Loc.eq l2 (eloc x2)) | High => @proj_sumbool (@eq loc l1 (eloc x2)) (not (@eq loc l1 (eloc x2))) (Loc.eq l1 (eloc x2)) end *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation.t x1 x2) (or (Plt (ereg x1) (ereg x2)) (and (@eq reg (ereg x1) (ereg x2)) (or (OrderedLoc.lt (eloc x1) (eloc x2)) (and (@eq loc (eloc x1) (eloc x2)) (OrderedEqKind.lt (ekind x1) (ekind x2))))))) (_ : @eq bool (select_reg_l r x1) true), @eq bool (select_reg_l r x2) true *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation.t x1 x2) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_reg_h r x1) true), @eq bool (select_reg_h r x2) true *)
  apply select_reg_charact in H1.
(* Goal: False *)
  assert (EqSet.mem_between (select_reg_l r) (select_reg_h r) e = true).
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
  {
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    apply EqSet.mem_between_2 with q; auto.
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation.t x1 x2) (or (Plt (ereg x1) (ereg x2)) (and (@eq reg (ereg x1) (ereg x2)) (or (OrderedLoc.lt (eloc x1) (eloc x2)) (and (@eq loc (eloc x1) (eloc x2)) (OrderedEqKind.lt (ekind x1) (ekind x2))))))) (_ : @eq bool (select_reg_l r x1) true), @eq bool (select_reg_l r x2) true *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation.t x1 x2) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_reg_h r x1) true), @eq bool (select_reg_h r x2) true *)
    exact (select_reg_l_monotone r).
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation.t x1 x2) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_reg_h r x1) true), @eq bool (select_reg_h r x2) true *)
    exact (select_reg_h_monotone r).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    tauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    tauto.
  }
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls1 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls2 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
  rewrite H2 in H; discriminate.
Qed.

Lemma reg_unconstrained_satisf:
  forall r e rs ls v,
  reg_unconstrained r e = true ->
  satisf rs ls e ->
  satisf (rs#r <- v) ls e.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  red; intros. rewrite PMap.gso. auto. eapply reg_unconstrained_sound; eauto.
Qed.

Remark select_loc_l_monotone:
  forall l q1 q2,
  OrderedEquation'.eq q1 q2 \/ OrderedEquation'.lt q1 q2 ->
  select_loc_l l q1 = true -> select_loc_l l q2 = true.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  unfold select_loc_l; intros. set (lb := OrderedLoc.diff_low_bound l) in *.
(* Goal: @eq bool (Pos.leb (ereg q2) r) true *)
  destruct H.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  red in H. subst q2; auto.
  assert (eloc q1 = eloc q2 \/ OrderedLoc.lt (eloc q1) (eloc q2)).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    red in H. tauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  destruct H1. rewrite <- H1; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  destruct (OrderedLoc.compare (eloc q2) lb); auto.
  assert (OrderedLoc.lt (eloc q1) lb) by (eapply OrderedLoc.lt_trans; eauto).
  destruct (OrderedLoc.compare (eloc q1) lb).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eelim OrderedLoc.lt_not_eq; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eelim OrderedLoc.lt_not_eq. eapply OrderedLoc.lt_trans. eexact l1. eexact H2. red; auto.
Qed.

Remark select_loc_h_monotone:
  forall l q1 q2,
  OrderedEquation'.eq q1 q2 \/ OrderedEquation'.lt q2 q1 ->
  select_loc_h l q1 = true -> select_loc_h l q2 = true.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  unfold select_loc_h; intros. set (lb := OrderedLoc.diff_high_bound l) in *.
(* Goal: @eq bool (Pos.leb (ereg q2) r) true *)
  destruct H.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  red in H. subst q2; auto.
  assert (eloc q2 = eloc q1 \/ OrderedLoc.lt (eloc q2) (eloc q1)).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    red in H. tauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  destruct H1. rewrite H1; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  destruct (OrderedLoc.compare (eloc q2) lb); auto.
  assert (OrderedLoc.lt lb (eloc q1)) by (eapply OrderedLoc.lt_trans; eauto).
  destruct (OrderedLoc.compare (eloc q1) lb).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eelim OrderedLoc.lt_not_eq. eapply OrderedLoc.lt_trans. eexact l1. eexact H2. red; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eelim OrderedLoc.lt_not_eq. eexact H2. apply OrderedLoc.eq_sym; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  auto.
Qed.

Remark select_loc_charact:
  forall l q,
  select_loc_l l q = false \/ select_loc_h l q = false <-> Loc.diff l (eloc q).
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  unfold select_loc_l, select_loc_h; intros; split; intros.
  apply OrderedLoc.outside_interval_diff.
(* Goal: @eq bool (Pos.leb (ereg q2) r) true *)
  destruct H.
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls1 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls2 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
  left. destruct (OrderedLoc.compare (eloc q) (OrderedLoc.diff_low_bound l)); assumption || discriminate.
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls1 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls2 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
  right. destruct (OrderedLoc.compare (eloc q) (OrderedLoc.diff_high_bound l)); assumption || discriminate.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit OrderedLoc.diff_outside_interval. eauto.
  intros [A | A].
(* Goal: or (and (@eq (prod reg equation_kind) (@pair reg equation_kind (ereg q) (ekind q)) (@pair reg equation_kind r1 k1)) (EqSet.In (Eq k2 r2 (eloc q)) (eqs1 (subst_reg_kind r1 k1 r2 k2 e0)))) (EqSet.In q (eqs1 (subst_reg_kind r1 k1 r2 k2 e0))) *)
(* Goal: or (and (@eq (prod reg equation_kind) (@pair reg equation_kind (ereg q) (ekind q)) (@pair reg equation_kind r1 k1)) (EqSet.In (Eq k2 r2 (eloc q)) (eqs1 (subst_reg_kind r1 k1 r2 k2 e0)))) (EqSet.In q (eqs1 (subst_reg_kind r1 k1 r2 k2 e0))) *)
(* Goal: or (and (@eq (prod reg equation_kind) (@pair reg equation_kind (ereg q) (ekind q)) (@pair reg equation_kind r1 k1)) (EqSet.In (Eq k2 r2 (eloc q)) (eqs1 (subst_reg_kind r1 k1 r2 k2 e0)))) (EqSet.In q (eqs1 (subst_reg_kind r1 k1 r2 k2 e0))) *)
  left. destruct (OrderedLoc.compare (eloc q) (OrderedLoc.diff_low_bound l)).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eelim OrderedLoc.lt_not_eq; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eelim OrderedLoc.lt_not_eq. eapply OrderedLoc.lt_trans; eauto. red; auto.
(* Goal: or (@eq bool (subtype (env (ereg q)) Tlong) true) (Loc.diff l (eloc q)) *)
(* Goal: forall (x1 x2 : equation) (_ : @eq OrderedEquation'.t x1 x2), @eq bool (subtype (env (ereg x1)) Tlong) (subtype (env (ereg x2)) Tlong) *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x1) (eloc x2)) (and (@eq loc (eloc x1) (eloc x2)) (or (Plt (ereg x1) (ereg x2)) (and (@eq reg (ereg x1) (ereg x2)) (OrderedEqKind.lt (ekind x1) (ekind x2))))))) (_ : @eq bool (select_loc_l l x1) true), @eq bool (select_loc_l l x2) true *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_loc_h l x1) true), @eq bool (select_loc_h l x2) true *)
  right. destruct (OrderedLoc.compare (eloc q) (OrderedLoc.diff_high_bound l)).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eelim OrderedLoc.lt_not_eq. eapply OrderedLoc.lt_trans; eauto. red; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eelim OrderedLoc.lt_not_eq; eauto. apply OrderedLoc.eq_sym; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  auto.
Qed.

Lemma loc_unconstrained_sound:
  forall l e q,
  loc_unconstrained l e = true ->
  EqSet.In q e ->
  Loc.diff l (eloc q).
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  unfold loc_unconstrained; intros.
  destruct (select_loc_l l q) eqn:SL.
  destruct (select_loc_h l q) eqn:SH.
  assert (EqSet2.mem_between (select_loc_l l) (select_loc_h l) (eqs2 e) = true).
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
  {
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    apply EqSet2.mem_between_2 with q; auto.
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x1) (eloc x2)) (and (@eq loc (eloc x1) (eloc x2)) (or (Plt (ereg x1) (ereg x2)) (and (@eq reg (ereg x1) (ereg x2)) (OrderedEqKind.lt (ekind x1) (ekind x2))))))) (_ : @eq bool (select_loc_l l x1) true), @eq bool (select_loc_l l x2) true *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_loc_h l x1) true), @eq bool (select_loc_h l x2) true *)
    exact (select_loc_l_monotone l).
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_loc_h l x1) true), @eq bool (select_loc_h l x2) true *)
    exact (select_loc_h_monotone l).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    apply eqs_same. auto.
  }
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls1 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls2 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
  rewrite H1 in H; discriminate.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  apply select_loc_charact; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  apply select_loc_charact; auto.
Qed.

Lemma loc_unconstrained_satisf:
  forall rs ls k r mr e v,
  let l := R mr in
  satisf rs ls (remove_equation (Eq k r l) e) ->
  loc_unconstrained (R mr) (remove_equation (Eq k r l) e) = true ->
  Val.lessdef (sel_val k rs#r) v ->
  satisf rs (Locmap.set l v ls) e.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros; red; intros.
(* Goal: Val.lessdef (sel_val (ekind q) (Regmap.get val (ereg q) (Regmap.set val r v rs))) (Locmap.set l v' ls (eloc q)) *)
  destruct (OrderedEquation.eq_dec q (Eq k r l)).
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  subst q; simpl. unfold l; rewrite Locmap.gss. auto.
(* Goal: Val.lessdef (sel_val (ekind q) (Regmap.get val (ereg q) rs)) (Locmap.set l v ls (eloc q)) *)
  assert (EqSet.In q (remove_equation (Eq k r l) e)).
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
    simpl. ESD.fsetdec.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite Locmap.gso. apply H; auto. eapply loc_unconstrained_sound; eauto.
Qed.

Lemma reg_loc_unconstrained_sound:
  forall r l e q,
  reg_loc_unconstrained r l e = true ->
  EqSet.In q e ->
  ereg q <> r /\ Loc.diff l (eloc q).
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. destruct (andb_prop _ _ H).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  split. eapply reg_unconstrained_sound; eauto. eapply loc_unconstrained_sound; eauto.
Qed.

Lemma parallel_assignment_satisf:
  forall k r mr e rs ls v v',
  let l := R mr in
  Val.lessdef (sel_val k v) v' ->
  reg_loc_unconstrained r (R mr) (remove_equation (Eq k r l) e) = true ->
  satisf rs ls (remove_equation (Eq k r l) e) ->
  satisf (rs#r <- v) (Locmap.set l v' ls) e.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros; red; intros.
(* Goal: Val.lessdef (sel_val (ekind q) (Regmap.get val (ereg q) (Regmap.set val r v rs))) (Locmap.set l v' ls (eloc q)) *)
  destruct (OrderedEquation.eq_dec q (Eq k r l)).
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  subst q; simpl. unfold l; rewrite Regmap.gss; rewrite Locmap.gss; auto.
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
  assert (EqSet.In q (remove_equation {| ekind := k; ereg := r; eloc := l |} e)).
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
    simpl. ESD.fsetdec.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit reg_loc_unconstrained_sound; eauto. intros [A B].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite Regmap.gso; auto. rewrite Locmap.gso; auto.
Qed.

Lemma parallel_assignment_satisf_2:
  forall rs ls res res' e e' v v',
  remove_equations_res res res' e = Some e' ->
  satisf rs ls e' ->
  reg_unconstrained res e' = true ->
  forallb (fun l => loc_unconstrained l e') (map R (regs_of_rpair res')) = true ->
  Val.lessdef v v' ->
  satisf (rs#res <- v) (Locmap.setpair res' v' ls) e.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. functional inversion H.
- (* One location *)
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  subst. simpl in H2. InvBooleans. simpl.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  apply parallel_assignment_satisf with Full; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  unfold reg_loc_unconstrained. rewrite H1, H4. auto.
- (* Two 32-bit halves *)
(* Goal: satisf (Regmap.set val res v rs) (Locmap.setpair (@Twolong mreg mr1 mr2) v' ls) e *)
  subst.
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
  set (e' := remove_equation {| ekind := Low; ereg := res; eloc := R mr2 |}
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
          (remove_equation {| ekind := High; ereg := res; eloc := R mr1 |} e)) in *.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  simpl in H2. InvBooleans. simpl.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  red; intros.
(* Goal: Val.lessdef (sel_val (ekind q) (Regmap.get val (ereg q) (Regmap.set val res v rs))) (Locmap.set (R mr2) (Val.loword v') (Locmap.set (R mr1) (Val.hiword v') ls) (eloc q)) *)
  destruct (OrderedEquation.eq_dec q (Eq Low res (R mr2))).
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  subst q; simpl. rewrite Regmap.gss. rewrite Locmap.gss.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  apply Val.loword_lessdef; auto.
(* Goal: Val.lessdef (sel_val (ekind q) (Regmap.get val (ereg q) (Regmap.set val res v rs))) (Locmap.set (R mr2) (Val.loword v') (Locmap.set (R mr1) (Val.hiword v') ls) (eloc q)) *)
  destruct (OrderedEquation.eq_dec q (Eq High res (R mr1))).
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  subst q; simpl. rewrite Regmap.gss. rewrite Locmap.gso by auto. rewrite Locmap.gss.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  apply Val.hiword_lessdef; auto.
(* Goal: EqSet.In (Eq k2 r2 (eloc q)) (EqSet.add (Eq k2 r2 (eloc q)) (EqSet.remove q (eqs1 a))) *)
(* Goal: EqSet.In (Eq k2 r2 (eloc q)) (eqs1 a) *)
  assert (EqSet.In q e'). unfold e', remove_equation; simpl; ESD.fsetdec.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite Regmap.gso. rewrite ! Locmap.gso. auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply loc_unconstrained_sound; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply loc_unconstrained_sound; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply reg_unconstrained_sound; eauto.
Qed.

Remark in_elements_between_1:
  forall r1 s q,
  EqSet.In q (EqSet.elements_between (select_reg_l r1) (select_reg_h r1) s) <-> EqSet.In q s /\ ereg q = r1.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. rewrite EqSet.elements_between_iff, select_reg_charact. tauto.
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation.t x1 x2) (or (Plt (ereg x1) (ereg x2)) (and (@eq reg (ereg x1) (ereg x2)) (or (OrderedLoc.lt (eloc x1) (eloc x2)) (and (@eq loc (eloc x1) (eloc x2)) (OrderedEqKind.lt (ekind x1) (ekind x2))))))) (_ : @eq bool (select_reg_l r1 x1) true), @eq bool (select_reg_l r1 x2) true *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation.t x1 x2) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_reg_h r1 x1) true), @eq bool (select_reg_h r1 x2) true *)
  exact (select_reg_l_monotone r1). exact (select_reg_h_monotone r1).
Qed.

Lemma in_subst_reg:
  forall r1 r2 q (e: eqs),
  EqSet.In q e ->
  ereg q = r1 /\ EqSet.In (Eq (ekind q) r2 (eloc q)) (subst_reg r1 r2 e)
  \/ ereg q <> r1 /\ EqSet.In q (subst_reg r1 r2 e).
Proof.
(* Goal: forall (r1 r2 : reg) (q : EqSet.elt) (e : eqs) (_ : EqSet.In q (eqs1 e)), or (and (@eq reg (ereg q) r1) (EqSet.In (Eq (ekind q) r2 (eloc q)) (eqs1 (subst_reg r1 r2 e)))) (and (not (@eq reg (ereg q) r1)) (EqSet.In q (eqs1 (subst_reg r1 r2 e)))) *)
  intros r1 r2 q e0 IN0. unfold subst_reg.
(* Goal: or (and (@eq reg (ereg q) r1) (EqSet.In (Eq (ekind q) r2 (eloc q)) (eqs1 (@EqSet.fold eqs (fun (q : EqSet.elt) (e : eqs) => add_equation (Eq (ekind q) r2 (eloc q)) (remove_equation q e)) (EqSet.elements_between (select_reg_l r1) (select_reg_h r1) (eqs1 e0)) e0)))) (and (not (@eq reg (ereg q) r1)) (EqSet.In q (eqs1 (@EqSet.fold eqs (fun (q : EqSet.elt) (e : eqs) => add_equation (Eq (ekind q) r2 (eloc q)) (remove_equation q e)) (EqSet.elements_between (select_reg_l r1) (select_reg_h r1) (eqs1 e0)) e0)))) *)
  set (f := fun (q: EqSet.elt) e => add_equation (Eq (ekind q) r2 (eloc q)) (remove_equation q e)).
(* Goal: or (and (@eq (prod reg equation_kind) (@pair reg equation_kind (ereg q) (ekind q)) (@pair reg equation_kind r1 k1)) (EqSet.In (Eq k2 r2 (eloc q)) (eqs1 (subst_reg_kind r1 k1 r2 k2 e0)))) (EqSet.In q (eqs1 (subst_reg_kind r1 k1 r2 k2 e0))) *)
  generalize (in_elements_between_1 r1 e0).
(* Goal: forall _ : forall q : EqSet.elt, iff (EqSet.In q (EqSet.elements_between (select_reg_l r1) (select_reg_h r1) (eqs1 e0))) (and (EqSet.In q (eqs1 e0)) (@eq reg (ereg q) r1)), or (and (@eq (prod reg equation_kind) (@pair reg equation_kind (ereg q) (ekind q)) (@pair reg equation_kind r1 k1)) (EqSet.In (Eq k2 r2 (eloc q)) (eqs1 (subst_reg_kind r1 k1 r2 k2 e0)))) (EqSet.In q (eqs1 (subst_reg_kind r1 k1 r2 k2 e0))) *)
  set (elt := EqSet.elements_between (select_reg_l r1) (select_reg_h r1) e0).
(* Goal: forall _ : forall q : EqSet.elt, iff (EqSet.In q elt) (and (EqSet.In q (eqs1 e0)) (@eq reg (ereg q) r1)), or (and (@eq (prod reg equation_kind) (@pair reg equation_kind (ereg q) (ekind q)) (@pair reg equation_kind r1 k1)) (EqSet.In (Eq k2 r2 (eloc q)) (eqs1 (subst_reg_kind r1 k1 r2 k2 e0)))) (EqSet.In q (eqs1 (subst_reg_kind r1 k1 r2 k2 e0))) *)
  intros IN_ELT.
  set (P := fun e1 e2 =>
         EqSet.In q e1 ->
         EqSet.In (Eq (ekind q) r2 (eloc q)) e2).
(* Goal: or (and (@eq (prod reg equation_kind) (@pair reg equation_kind (ereg q) (ekind q)) (@pair reg equation_kind r1 k1)) (EqSet.In (Eq k2 r2 (eloc q)) (eqs1 (subst_reg_kind r1 k1 r2 k2 e0)))) (EqSet.In q (eqs1 (subst_reg_kind r1 k1 r2 k2 e0))) *)
  assert (P elt (EqSet.fold f elt e0)).
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
  {
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
    apply ESP.fold_rec; unfold P; intros.
    - ESD.fsetdec.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
    - simpl. red in H1. apply H1 in H3. destruct H3.
      + subst x. ESD.fsetdec.
      + rewrite ESF.add_iff. rewrite ESF.remove_iff.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
        destruct (OrderedEquation.eq_dec x {| ekind := ekind q; ereg := r2; eloc := eloc q |}); auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
        left. subst x; auto.
  }
  set (Q := fun e1 e2 =>
         ~EqSet.In q e1 ->
         EqSet.In q e2).
(* Goal: or (and (@eq (prod reg equation_kind) (@pair reg equation_kind (ereg q) (ekind q)) (@pair reg equation_kind r1 k1)) (EqSet.In (Eq k2 r2 (eloc q)) (eqs1 (subst_reg_kind r1 k1 r2 k2 e0)))) (EqSet.In q (eqs1 (subst_reg_kind r1 k1 r2 k2 e0))) *)
  assert (Q elt (EqSet.fold f elt e0)).
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
  {
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
    apply ESP.fold_rec; unfold Q; intros.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    - auto.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
    - simpl. red in H2. rewrite H2 in H4. ESD.fsetdec.
  }
(* Goal: or (and (@eq (prod reg equation_kind) (@pair reg equation_kind (ereg q) (ekind q)) (@pair reg equation_kind r1 k1)) (EqSet.In (Eq k2 r2 (eloc q)) (eqs1 (subst_reg_kind r1 k1 r2 k2 e0)))) (EqSet.In q (eqs1 (subst_reg_kind r1 k1 r2 k2 e0))) *)
  destruct (ESP.In_dec q elt).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  left. split. apply IN_ELT. auto. apply H. auto.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  right. split. red; intros. elim n. rewrite IN_ELT. auto. apply H0. auto.
Qed.

Lemma subst_reg_satisf:
  forall src dst rs ls e,
  satisf rs ls (subst_reg dst src e) ->
  satisf (rs#dst <- (rs#src)) ls e.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros; red; intros.
(* Goal: Val.lessdef (sel_val (ekind q) (Regmap.get val (ereg q) (Regmap.set val dst (Regmap.get val src rs) rs))) (ls (eloc q)) *)
  destruct (in_subst_reg dst src q e H0) as [[A B] | [A B]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  subst dst. rewrite Regmap.gss. exploit H; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite Regmap.gso; auto.
Qed.

Lemma in_subst_reg_kind:
  forall r1 k1 r2 k2 q (e: eqs),
  EqSet.In q e ->
  (ereg q, ekind q) = (r1, k1) /\ EqSet.In (Eq k2 r2 (eloc q)) (subst_reg_kind r1 k1 r2 k2 e)
  \/ EqSet.In q (subst_reg_kind r1 k1 r2 k2 e).
Proof.
(* Goal: or (and (@eq (prod reg equation_kind) (@pair reg equation_kind (ereg q) (ekind q)) (@pair reg equation_kind r1 k1)) (EqSet.In (Eq k2 r2 (eloc q)) (eqs1 (subst_reg_kind r1 k1 r2 k2 e0)))) (EqSet.In q (eqs1 (subst_reg_kind r1 k1 r2 k2 e0))) *)
  intros r1 k1 r2 k2 q e0 IN0. unfold subst_reg.
  set (f := fun (q: EqSet.elt) e =>
      if IndexedEqKind.eq (ekind q) k1
      then add_equation (Eq k2 r2 (eloc q)) (remove_equation q e)
      else e).
(* Goal: or (and (@eq (prod reg equation_kind) (@pair reg equation_kind (ereg q) (ekind q)) (@pair reg equation_kind r1 k1)) (EqSet.In (Eq k2 r2 (eloc q)) (eqs1 (subst_reg_kind r1 k1 r2 k2 e0)))) (EqSet.In q (eqs1 (subst_reg_kind r1 k1 r2 k2 e0))) *)
  generalize (in_elements_between_1 r1 e0).
(* Goal: forall _ : forall q : EqSet.elt, iff (EqSet.In q (EqSet.elements_between (select_reg_l r1) (select_reg_h r1) (eqs1 e0))) (and (EqSet.In q (eqs1 e0)) (@eq reg (ereg q) r1)), or (and (@eq (prod reg equation_kind) (@pair reg equation_kind (ereg q) (ekind q)) (@pair reg equation_kind r1 k1)) (EqSet.In (Eq k2 r2 (eloc q)) (eqs1 (subst_reg_kind r1 k1 r2 k2 e0)))) (EqSet.In q (eqs1 (subst_reg_kind r1 k1 r2 k2 e0))) *)
  set (elt := EqSet.elements_between (select_reg_l r1) (select_reg_h r1) e0).
(* Goal: forall _ : forall q : EqSet.elt, iff (EqSet.In q elt) (and (EqSet.In q (eqs1 e0)) (@eq reg (ereg q) r1)), or (and (@eq (prod reg equation_kind) (@pair reg equation_kind (ereg q) (ekind q)) (@pair reg equation_kind r1 k1)) (EqSet.In (Eq k2 r2 (eloc q)) (eqs1 (subst_reg_kind r1 k1 r2 k2 e0)))) (EqSet.In q (eqs1 (subst_reg_kind r1 k1 r2 k2 e0))) *)
  intros IN_ELT.
  set (P := fun e1 e2 =>
         EqSet.In q e1 -> ekind q = k1 ->
         EqSet.In (Eq k2 r2 (eloc q)) e2).
(* Goal: or (and (@eq (prod reg equation_kind) (@pair reg equation_kind (ereg q) (ekind q)) (@pair reg equation_kind r1 k1)) (EqSet.In (Eq k2 r2 (eloc q)) (eqs1 (subst_reg_kind r1 k1 r2 k2 e0)))) (EqSet.In q (eqs1 (subst_reg_kind r1 k1 r2 k2 e0))) *)
  assert (P elt (EqSet.fold f elt e0)).
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
  {
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
    intros; apply ESP.fold_rec; unfold P; intros.
    - ESD.fsetdec.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
    - simpl. red in H1. apply H1 in H3. destruct H3.
      + subst x. unfold f. destruct (IndexedEqKind.eq (ekind q) k1).
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
        simpl. ESD.fsetdec. contradiction.
      + unfold f. destruct (IndexedEqKind.eq (ekind x) k1).
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
        simpl. rewrite ESF.add_iff. rewrite ESF.remove_iff.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
        destruct (OrderedEquation.eq_dec x {| ekind := k2; ereg := r2; eloc := eloc q |}); auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
        left. subst x; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
        auto.
  }
  set (Q := fun e1 e2 =>
         ~EqSet.In q e1 \/ ekind q <> k1 ->
         EqSet.In q e2).
(* Goal: or (and (@eq (prod reg equation_kind) (@pair reg equation_kind (ereg q) (ekind q)) (@pair reg equation_kind r1 k1)) (EqSet.In (Eq k2 r2 (eloc q)) (eqs1 (subst_reg_kind r1 k1 r2 k2 e0)))) (EqSet.In q (eqs1 (subst_reg_kind r1 k1 r2 k2 e0))) *)
  assert (Q elt (EqSet.fold f elt e0)).
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
  {
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
    apply ESP.fold_rec; unfold Q; intros.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    - auto.
    - unfold f. red in H2. rewrite H2 in H4.
(* Goal: EqSet.In q (eqs1 (if IndexedEqKind.eq (ekind x) k1 then add_equation (Eq k2 r2 (eloc x)) (remove_equation x a) else a)) *)
      destruct (IndexedEqKind.eq (ekind x) k1).
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
      simpl. rewrite ESF.add_iff. rewrite ESF.remove_iff.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
      right. split. apply H3. tauto. intuition congruence.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
      apply H3. intuition auto.
  }
(* Goal: or (and (@eq (prod reg equation_kind) (@pair reg equation_kind (ereg q) (ekind q)) (@pair reg equation_kind r1 k1)) (EqSet.In (Eq k2 r2 (eloc q)) (eqs1 (subst_reg_kind r1 k1 r2 k2 e0)))) (EqSet.In q (eqs1 (subst_reg_kind r1 k1 r2 k2 e0))) *)
  destruct (ESP.In_dec q elt).
(* Goal: or (and (@eq (prod reg equation_kind) (@pair reg equation_kind (ereg q) (ekind q)) (@pair reg equation_kind r1 k1)) (EqSet.In (Eq k2 r2 (eloc q)) (eqs1 (subst_reg_kind r1 k1 r2 k2 e0)))) (EqSet.In q (eqs1 (subst_reg_kind r1 k1 r2 k2 e0))) *)
(* Goal: or (and (@eq (prod reg equation_kind) (@pair reg equation_kind (ereg q) (ekind q)) (@pair reg equation_kind r1 k1)) (EqSet.In (Eq k2 r2 (eloc q)) (eqs1 (subst_reg_kind r1 k1 r2 k2 e0)))) (EqSet.In q (eqs1 (subst_reg_kind r1 k1 r2 k2 e0))) *)
  destruct (IndexedEqKind.eq (ekind q) k1).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  left. split. f_equal. apply IN_ELT. auto. auto. apply H. auto. auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  right. apply H0. auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  right. apply H0. auto.
Qed.

Lemma subst_reg_kind_satisf_makelong:
  forall src1 src2 dst rs ls e,
  let e1 := subst_reg_kind dst High src1 Full e in
  let e2 := subst_reg_kind dst Low src2 Full e1 in
  reg_unconstrained dst e2 = true ->
  satisf rs ls e2 ->
  satisf (rs#dst <- (Val.longofwords rs#src1 rs#src2)) ls e.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros; red; intros.
  destruct (in_subst_reg_kind dst High src1 Full q e H1) as [[A B] | B]; fold e1 in B.
  destruct (in_subst_reg_kind dst Low src2 Full _ e1 B) as [[C D] | D]; fold e2 in D.
  simpl in C; simpl in D. inv C.
(* Goal: Val.lessdef (Val.hiword (Regmap.get val x (Regmap.set val x v rs))) (Locmap.set (R lo) (Val.loword v') (Locmap.set (R hi) (Val.hiword v') ls) (R hi)) *)
(* Goal: Val.lessdef (sel_val (ekind q) (Regmap.get val (ereg q) (Regmap.set val x v rs))) (Locmap.set (R lo) (Val.loword v') (Locmap.set (R hi) (Val.hiword v') ls) (eloc q)) *)
  inversion A. rewrite H3; rewrite H4. rewrite Regmap.gss.
  apply Val.lessdef_trans with (rs#src1).
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  simpl. destruct (rs#src1); simpl; auto. destruct (rs#src2); simpl; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite Int64.hi_ofwords. auto.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  exploit H0. eexact D. simpl. auto.
  destruct (in_subst_reg_kind dst Low src2 Full q e1 B) as [[C D] | D]; fold e2 in D.
(* Goal: Val.lessdef (Val.hiword (Regmap.get val x (Regmap.set val x v rs))) (Locmap.set (R lo) (Val.loword v') (Locmap.set (R hi) (Val.hiword v') ls) (R hi)) *)
(* Goal: Val.lessdef (sel_val (ekind q) (Regmap.get val (ereg q) (Regmap.set val x v rs))) (Locmap.set (R lo) (Val.loword v') (Locmap.set (R hi) (Val.hiword v') ls) (eloc q)) *)
  inversion C. rewrite H3; rewrite H4. rewrite Regmap.gss.
  apply Val.lessdef_trans with (rs#src2).
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  simpl. destruct (rs#src1); simpl; auto. destruct (rs#src2); simpl; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite Int64.lo_ofwords. auto.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  exploit H0. eexact D. simpl. auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite Regmap.gso. apply H0; auto. eapply reg_unconstrained_sound; eauto.
Qed.

Lemma subst_reg_kind_satisf_lowlong:
  forall src dst rs ls e,
  let e1 := subst_reg_kind dst Full src Low e in
  reg_unconstrained dst e1 = true ->
  satisf rs ls e1 ->
  satisf (rs#dst <- (Val.loword rs#src)) ls e.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros; red; intros.
  destruct (in_subst_reg_kind dst Full src Low q e H1) as [[A B] | B]; fold e1 in B.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  inversion A. rewrite H3; rewrite H4. simpl. rewrite Regmap.gss.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  exploit H0. eexact B. simpl. auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite Regmap.gso. apply H0; auto. eapply reg_unconstrained_sound; eauto.
Qed.

Lemma subst_reg_kind_satisf_highlong:
  forall src dst rs ls e,
  let e1 := subst_reg_kind dst Full src High e in
  reg_unconstrained dst e1 = true ->
  satisf rs ls e1 ->
  satisf (rs#dst <- (Val.hiword rs#src)) ls e.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros; red; intros.
  destruct (in_subst_reg_kind dst Full src High q e H1) as [[A B] | B]; fold e1 in B.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  inversion A. rewrite H3; rewrite H4. simpl. rewrite Regmap.gss.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  exploit H0. eexact B. simpl. auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite Regmap.gso. apply H0; auto. eapply reg_unconstrained_sound; eauto.
Qed.

Module ESF2 := FSetFacts.Facts(EqSet2).
Module ESP2 := FSetProperties.Properties(EqSet2).
Module ESD2 := FSetDecide.Decide(EqSet2).

Lemma partial_fold_ind:
  forall (A: Type) (P: EqSet2.t -> A -> Prop) f init final s,
  EqSet2.fold
         (fun q opte =>
            match opte with
            | None => None
            | Some e => f q e
            end)
         s (Some init) = Some final ->
  (forall s', EqSet2.Empty s' -> P s' init) ->
  (forall x a' a'' s' s'',
      EqSet2.In x s -> ~EqSet2.In x s' -> ESP2.Add x s' s'' ->
      f x a' = Some a'' -> P s' a' -> P s'' a'') ->
  P s final.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros.
  set (g := fun q opte => match opte with Some e => f q e | None => None end) in *.
(* Goal: P s final *)
  set (Q := fun s1 opte => match opte with None => True | Some e => P s1 e end).
(* Goal: P s final *)
  change (Q s (Some final)).
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  rewrite <- H. apply ESP2.fold_rec; unfold Q, g; intros.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  - auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  - destruct a as [e|]; auto. destruct (f x e) as [e'|] eqn:F; auto. eapply H1; eauto.
Qed.

Lemma in_subst_loc:
  forall l1 l2 q (e e': eqs),
  EqSet.In q e ->
  subst_loc l1 l2 e = Some e' ->
  (eloc q = l1 /\ EqSet.In (Eq (ekind q) (ereg q) l2) e') \/ (Loc.diff l1 (eloc q) /\ EqSet.In q e').
Proof.
  unfold subst_loc; intros l1 l2 q e0 e0' IN SUBST.
  set (elt := EqSet2.elements_between (select_loc_l l1) (select_loc_h l1) (eqs2 e0)) in *.
  set (f := fun q0 e =>
             if Loc.eq l1 (eloc q0) then
                Some (add_equation
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
                     {| ekind := ekind q0; ereg := ereg q0; eloc := l2 |}
                     (remove_equation q0 e))
             else None).
  set (P := fun e1 e2 => EqSet2.In q e1 -> eloc q = l1 /\ EqSet.In (Eq (ekind q) (ereg q) l2) e2).
  assert (A: P elt e0').
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
  { eapply partial_fold_ind with (f := f) (s := elt) (final := e0'). eexact SUBST.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  - unfold P; intros. ESD2.fsetdec.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  - unfold P, f; intros. destruct (Loc.eq l1 (eloc x)); inversion H2; subst a''; clear H2.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
    simpl. rewrite ESF.add_iff, ESF.remove_iff.
    apply H1 in H4; destruct H4.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    subst x; rewrite e; auto.
(* Goal: @eq signature (funsig tf) signature_main *)
(* Goal: match_states (RTL.Callstate (@nil RTL.stackframe) f (@nil val) m0) (Callstate (@nil stackframe) tf (Locmap.init Vundef) m0) *)
    apply H3 in H2; destruct H2. split. congruence.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    destruct (OrderedEquation.eq_dec x {| ekind := ekind q; ereg := ereg q; eloc := l2 |}); auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    subst x; auto.
  }
  set (Q := fun e1 e2 => ~EqSet2.In q e1 -> EqSet.In q e2).
  assert (B: Q elt e0').
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
  { eapply partial_fold_ind with (f := f) (s := elt) (final := e0'). eexact SUBST.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  - unfold Q; intros. auto.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  - unfold Q, f; intros. destruct (Loc.eq l1 (eloc x)); inversion H2; subst a''; clear H2.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
    simpl. rewrite ESF.add_iff, ESF.remove_iff.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    red in H1. rewrite H1 in H4. intuition auto. }
  destruct (ESP2.In_dec q elt).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  left. apply A; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  right. split; auto.
  rewrite <- select_loc_charact.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  destruct (select_loc_l l1 q) eqn: LL; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  destruct (select_loc_h l1 q) eqn: LH; auto.
(* Goal: False *)
(* Goal: EqSet.In q (eqs1 (@EqSet.fold eqs f elt e0)) *)
  elim n. eapply EqSet2.elements_between_iff.
  exact (select_loc_l_monotone l1).
  exact (select_loc_h_monotone l1).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  split. apply eqs_same; auto. auto.
Qed.

Lemma loc_type_compat_charact:
  forall env l e q,
  loc_type_compat env l e = true ->
  EqSet.In q e ->
  subtype (sel_type (ekind q) (env (ereg q))) (Loc.type l) = true \/ Loc.diff l (eloc q).
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  unfold loc_type_compat; intros.
(* Goal: or (@eq bool (subtype (env (ereg q)) Tlong) true) (Loc.diff l (eloc q)) *)
  rewrite EqSet2.for_all_between_iff in H.
(* Goal: or (@eq bool (subtype (env (ereg q)) Tlong) true) (Loc.diff l (eloc q)) *)
(* Goal: forall (x1 x2 : equation) (_ : @eq OrderedEquation'.t x1 x2), @eq bool (subtype (env (ereg x1)) Tlong) (subtype (env (ereg x2)) Tlong) *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x1) (eloc x2)) (and (@eq loc (eloc x1) (eloc x2)) (or (Plt (ereg x1) (ereg x2)) (and (@eq reg (ereg x1) (ereg x2)) (OrderedEqKind.lt (ekind x1) (ekind x2))))))) (_ : @eq bool (select_loc_l l x1) true), @eq bool (select_loc_l l x2) true *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_loc_h l x1) true), @eq bool (select_loc_h l x2) true *)
  destruct (select_loc_l l q) eqn: LL.
(* Goal: or (@eq bool (subtype (env (ereg q)) Tlong) true) (Loc.diff l (eloc q)) *)
(* Goal: or (@eq bool (subtype (env (ereg q)) Tlong) true) (Loc.diff l (eloc q)) *)
(* Goal: forall (x1 x2 : equation) (_ : @eq OrderedEquation'.t x1 x2), @eq bool (subtype (env (ereg x1)) Tlong) (subtype (env (ereg x2)) Tlong) *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x1) (eloc x2)) (and (@eq loc (eloc x1) (eloc x2)) (or (Plt (ereg x1) (ereg x2)) (and (@eq reg (ereg x1) (ereg x2)) (OrderedEqKind.lt (ekind x1) (ekind x2))))))) (_ : @eq bool (select_loc_l l x1) true), @eq bool (select_loc_l l x2) true *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_loc_h l x1) true), @eq bool (select_loc_h l x2) true *)
  destruct (select_loc_h l q) eqn: LH.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  left; apply H; auto. apply eqs_same; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  right. apply select_loc_charact. auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  right. apply select_loc_charact. auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  intros; subst; auto.
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x1) (eloc x2)) (and (@eq loc (eloc x1) (eloc x2)) (or (Plt (ereg x1) (ereg x2)) (and (@eq reg (ereg x1) (ereg x2)) (OrderedEqKind.lt (ekind x1) (ekind x2))))))) (_ : @eq bool (select_loc_l l x1) true), @eq bool (select_loc_l l x2) true *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_loc_h l x1) true), @eq bool (select_loc_h l x2) true *)
  exact (select_loc_l_monotone l).
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_loc_h l x1) true), @eq bool (select_loc_h l x2) true *)
  exact (select_loc_h_monotone l).
Qed.

Lemma well_typed_move_charact:
  forall env l e k r rs,
  well_typed_move env l e = true ->
  EqSet.In (Eq k r l) e ->
  wt_regset env rs ->
  match l with
  | R mr => True
  | S sl ofs ty => Val.has_type (sel_val k rs#r) ty
  end.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  unfold well_typed_move; intros.
  destruct l as [mr | sl ofs ty].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit loc_type_compat_charact; eauto. intros [A | A].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  simpl in A. eapply Val.has_subtype; eauto.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  generalize (H1 r). destruct k; simpl; intros.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  auto.
(* Goal: wf_move (MV (R src) (S sl ofs ty)) *)
(* Goal: forall _ : and (wf_moves mv) (@eq bblock (expand_moves (@rev move (@cons move (MV (R src) (S sl ofs ty)) accu)) b) (expand_moves mv b')), and (wf_moves mv) (@eq bblock (expand_moves (@rev move accu) (@cons instruction (Lsetstack src sl ofs ty) b)) (expand_moves mv b')) *)
  destruct (rs#r); exact I.
(* Goal: wf_move (MV (R src) (S sl ofs ty)) *)
(* Goal: forall _ : and (wf_moves mv) (@eq bblock (expand_moves (@rev move (@cons move (MV (R src) (S sl ofs ty)) accu)) b) (expand_moves mv b')), and (wf_moves mv) (@eq bblock (expand_moves (@rev move accu) (@cons instruction (Lsetstack src sl ofs ty) b)) (expand_moves mv b')) *)
  destruct (rs#r); exact I.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eelim Loc.diff_not_eq. eexact A. auto.
Qed.

Remark val_lessdef_normalize:
  forall v v' ty,
  Val.has_type v ty -> Val.lessdef v v' ->
  Val.lessdef v (Val.load_result (chunk_of_type ty) v').
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. inv H0. rewrite Val.load_result_same; auto. auto.
Qed.

Lemma subst_loc_satisf:
  forall env src dst rs ls e e',
  subst_loc dst src e = Some e' ->
  well_typed_move env dst e = true ->
  wt_regset env rs ->
  satisf rs ls e' ->
  satisf rs (Locmap.set dst (ls src) ls) e.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros; red; intros.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit in_subst_loc; eauto. intros [[A B] | [A B]].
(* Goal: Val.lessdef (Val.hiword v) (Locmap.set (R hi) (Val.hiword v') ls (R hi)) *)
(* Goal: Val.lessdef (sel_val (ekind q) (Regmap.get val (ereg q) (Regmap.set val x v rs))) (Locmap.set (R lo) (Val.loword v') (Locmap.set (R hi) (Val.hiword v') ls) (eloc q)) *)
  subst dst. rewrite Locmap.gss.
  destruct q as [k r l]; simpl in *.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit well_typed_move_charact; eauto.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  destruct l as [mr | sl ofs ty]; intros.
(* Goal: Val.lessdef (sel_val k (Regmap.get val r rs)) (ls src) *)
(* Goal: Val.lessdef (sel_val (ekind q) (Regmap.get val (ereg q) rs)) (Locmap.set dst (ls src) ls (eloc q)) *)
  apply (H2 _ B).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  apply val_lessdef_normalize; auto. apply (H2 _ B).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite Locmap.gso; auto.
Qed.

Lemma in_subst_loc_part:
  forall l1 l2 k q (e e': eqs),
  EqSet.In q e ->
  subst_loc_part l1 l2 k e = Some e' ->
  (eloc q = l1 /\ ekind q = k /\ EqSet.In (Eq Full (ereg q) l2) e') \/ (Loc.diff l1 (eloc q) /\ EqSet.In q e').
Proof.
  unfold subst_loc_part; intros l1 l2 k q e0 e0' IN SUBST.
  set (elt := EqSet2.elements_between (select_loc_l l1) (select_loc_h l1) (eqs2 e0)) in *.
  set (f := fun q0 e =>
             if Loc.eq l1 (eloc q0) then
             if IndexedEqKind.eq (ekind q0) k then
                Some (add_equation
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
                     {| ekind := Full; ereg := ereg q0; eloc := l2 |}
                     (remove_equation q0 e))
             else None else None).
  set (P := fun e1 e2 => EqSet2.In q e1 -> eloc q = l1 /\ ekind q = k /\ EqSet.In (Eq Full (ereg q) l2) e2).
  assert (A: P elt e0').
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
  { eapply partial_fold_ind with (f := f) (s := elt) (final := e0'). eexact SUBST.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  - unfold P; intros. ESD2.fsetdec.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  - unfold P, f; intros. destruct (Loc.eq l1 (eloc x)); try discriminate.
    destruct (IndexedEqKind.eq (ekind x) k); inversion H2; subst a''; clear H2.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
    simpl. rewrite ESF.add_iff, ESF.remove_iff.
    apply H1 in H4; destruct H4.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    subst x; rewrite e, <- e1; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    apply H3 in H2; destruct H2 as (X & Y & Z). split; auto. split; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    destruct (OrderedEquation.eq_dec x {| ekind := Full; ereg := ereg q; eloc := l2 |}); auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    subst x; auto.
  }
  set (Q := fun e1 e2 => ~EqSet2.In q e1 -> EqSet.In q e2).
  assert (B: Q elt e0').
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
  { eapply partial_fold_ind with (f := f) (s := elt) (final := e0'). eexact SUBST.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  - unfold Q; intros. auto.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  - unfold Q, f; intros. destruct (Loc.eq l1 (eloc x)); try congruence.
    destruct (IndexedEqKind.eq (ekind x) k); inversion H2; subst a''; clear H2.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
    simpl. rewrite ESF.add_iff, ESF.remove_iff.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    red in H1. rewrite H1 in H4. intuition auto. }
  destruct (ESP2.In_dec q elt).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  left. apply A; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  right. split; auto.
  rewrite <- select_loc_charact.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  destruct (select_loc_l l1 q) eqn: LL; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  destruct (select_loc_h l1 q) eqn: LH; auto.
(* Goal: False *)
(* Goal: EqSet.In q (eqs1 (@EqSet.fold eqs f elt e0)) *)
  elim n. eapply EqSet2.elements_between_iff.
  exact (select_loc_l_monotone l1).
  exact (select_loc_h_monotone l1).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  split. apply eqs_same; auto. auto.
Qed.

Lemma subst_loc_part_satisf_lowlong:
  forall src dst rs ls e e',
  subst_loc_part (R dst) (R src) Low e = Some e' ->
  satisf rs ls e' ->
  satisf rs (Locmap.set (R dst) (Val.loword (ls (R src))) ls) e.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros; red; intros.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit in_subst_loc_part; eauto. intros [[A [B C]] | [A B]].
(* Goal: Val.lessdef (Val.hiword v) (Locmap.set (R hi) (Val.hiword v') ls (R hi)) *)
(* Goal: Val.lessdef (sel_val (ekind q) (Regmap.get val (ereg q) (Regmap.set val x v rs))) (Locmap.set (R lo) (Val.loword v') (Locmap.set (R hi) (Val.hiword v') ls) (eloc q)) *)
  rewrite A, B. apply H0 in C. rewrite Locmap.gss. apply Val.loword_lessdef. exact C.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite Locmap.gso; auto.
Qed.

Lemma subst_loc_part_satisf_highlong:
  forall src dst rs ls e e',
  subst_loc_part (R dst) (R src) High e = Some e' ->
  satisf rs ls e' ->
  satisf rs (Locmap.set (R dst) (Val.hiword (ls (R src))) ls) e.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros; red; intros.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit in_subst_loc_part; eauto. intros [[A [B C]] | [A B]].
(* Goal: Val.lessdef (Val.hiword v) (Locmap.set (R hi) (Val.hiword v') ls (R hi)) *)
(* Goal: Val.lessdef (sel_val (ekind q) (Regmap.get val (ereg q) (Regmap.set val x v rs))) (Locmap.set (R lo) (Val.loword v') (Locmap.set (R hi) (Val.hiword v') ls) (eloc q)) *)
  rewrite A, B. apply H0 in C. rewrite Locmap.gss. apply Val.hiword_lessdef. exact C.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite Locmap.gso; auto.
Qed.

Lemma in_subst_loc_pair:
  forall l1 l2 l2' q (e e': eqs),
  EqSet.In q e ->
  subst_loc_pair l1 l2  l2' e = Some e' ->
  (eloc q = l1 /\ ekind q = Full /\ EqSet.In (Eq High (ereg q) l2) e' /\ EqSet.In (Eq Low (ereg q) l2') e')
  \/ (Loc.diff l1 (eloc q) /\ EqSet.In q e').
Proof.
  unfold subst_loc_pair; intros l1 l2 l2' q e0 e0' IN SUBST.
  set (elt := EqSet2.elements_between (select_loc_l l1) (select_loc_h l1) (eqs2 e0)) in *.
  set (f := fun q0 e =>
             if Loc.eq l1 (eloc q0) then
             if IndexedEqKind.eq (ekind q0) Full then
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
                Some (add_equation {| ekind := High; ereg := ereg q0; eloc := l2 |}
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
                     (add_equation {| ekind := Low; ereg := ereg q0; eloc := l2' |}
                     (remove_equation q0 e)))
             else None else None).
  set (P := fun e1 e2 => EqSet2.In q e1 -> eloc q = l1 /\ ekind q = Full
                                        /\ EqSet.In (Eq High (ereg q) l2) e2
                                        /\ EqSet.In (Eq Low (ereg q) l2') e2).
  assert (A: P elt e0').
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
  { eapply partial_fold_ind with (f := f) (s := elt) (final := e0'). eexact SUBST.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  - unfold P; intros. ESD2.fsetdec.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  - unfold P, f; intros. destruct (Loc.eq l1 (eloc x)); try discriminate.
    destruct (IndexedEqKind.eq (ekind x) Full); inversion H2; subst a''; clear H2.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
    simpl. rewrite ! ESF.add_iff, ! ESF.remove_iff.
    apply H1 in H4; destruct H4.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    subst x. rewrite e, e1. intuition auto.
    apply H3 in H2; destruct H2 as (U & V & W & X).
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
    destruct (OrderedEquation.eq_dec x {| ekind := High; ereg := ereg q; eloc := l2 |}).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    subst x. intuition auto.
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
    destruct (OrderedEquation.eq_dec x {| ekind := Low; ereg := ereg q; eloc := l2' |}).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    subst x. intuition auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    intuition auto. }
  set (Q := fun e1 e2 => ~EqSet2.In q e1 -> EqSet.In q e2).
  assert (B: Q elt e0').
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
  { eapply partial_fold_ind with (f := f) (s := elt) (final := e0'). eexact SUBST.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  - unfold Q; intros. auto.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  - unfold Q, f; intros. destruct (Loc.eq l1 (eloc x)); try congruence.
    destruct (IndexedEqKind.eq (ekind x) Full); inversion H2; subst a''; clear H2.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
    simpl. rewrite ! ESF.add_iff, ! ESF.remove_iff.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    red in H1. rewrite H1 in H4. intuition auto. }
  destruct (ESP2.In_dec q elt).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  left. apply A; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  right. split; auto.
  rewrite <- select_loc_charact.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  destruct (select_loc_l l1 q) eqn: LL; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  destruct (select_loc_h l1 q) eqn: LH; auto.
(* Goal: False *)
(* Goal: EqSet.In q (eqs1 (@EqSet.fold eqs f elt e0)) *)
  elim n. eapply EqSet2.elements_between_iff.
  exact (select_loc_l_monotone l1).
  exact (select_loc_h_monotone l1).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  split. apply eqs_same; auto. auto.
Qed.

Lemma long_type_compat_charact:
  forall env l e q,
  long_type_compat env l e = true ->
  EqSet.In q e ->
  subtype (env (ereg q)) Tlong = true \/ Loc.diff l (eloc q).
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  unfold long_type_compat; intros.
(* Goal: or (@eq bool (subtype (env (ereg q)) Tlong) true) (Loc.diff l (eloc q)) *)
  rewrite EqSet2.for_all_between_iff in H.
(* Goal: or (@eq bool (subtype (env (ereg q)) Tlong) true) (Loc.diff l (eloc q)) *)
(* Goal: forall (x1 x2 : equation) (_ : @eq OrderedEquation'.t x1 x2), @eq bool (subtype (env (ereg x1)) Tlong) (subtype (env (ereg x2)) Tlong) *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x1) (eloc x2)) (and (@eq loc (eloc x1) (eloc x2)) (or (Plt (ereg x1) (ereg x2)) (and (@eq reg (ereg x1) (ereg x2)) (OrderedEqKind.lt (ekind x1) (ekind x2))))))) (_ : @eq bool (select_loc_l l x1) true), @eq bool (select_loc_l l x2) true *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_loc_h l x1) true), @eq bool (select_loc_h l x2) true *)
  destruct (select_loc_l l q) eqn: LL.
(* Goal: or (@eq bool (subtype (env (ereg q)) Tlong) true) (Loc.diff l (eloc q)) *)
(* Goal: or (@eq bool (subtype (env (ereg q)) Tlong) true) (Loc.diff l (eloc q)) *)
(* Goal: forall (x1 x2 : equation) (_ : @eq OrderedEquation'.t x1 x2), @eq bool (subtype (env (ereg x1)) Tlong) (subtype (env (ereg x2)) Tlong) *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x1) (eloc x2)) (and (@eq loc (eloc x1) (eloc x2)) (or (Plt (ereg x1) (ereg x2)) (and (@eq reg (ereg x1) (ereg x2)) (OrderedEqKind.lt (ekind x1) (ekind x2))))))) (_ : @eq bool (select_loc_l l x1) true), @eq bool (select_loc_l l x2) true *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_loc_h l x1) true), @eq bool (select_loc_h l x2) true *)
  destruct (select_loc_h l q) eqn: LH.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  left; apply H; auto. apply eqs_same; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  right. apply select_loc_charact. auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  right. apply select_loc_charact. auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  intros; subst; auto.
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x1) (eloc x2)) (and (@eq loc (eloc x1) (eloc x2)) (or (Plt (ereg x1) (ereg x2)) (and (@eq reg (ereg x1) (ereg x2)) (OrderedEqKind.lt (ekind x1) (ekind x2))))))) (_ : @eq bool (select_loc_l l x1) true), @eq bool (select_loc_l l x2) true *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_loc_h l x1) true), @eq bool (select_loc_h l x2) true *)
  exact (select_loc_l_monotone l).
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_loc_h l x1) true), @eq bool (select_loc_h l x2) true *)
  exact (select_loc_h_monotone l).
Qed.

Lemma subst_loc_pair_satisf_makelong:
  forall env src1 src2 dst rs ls e e',
  subst_loc_pair (R dst) (R src1) (R src2) e = Some e' ->
  long_type_compat env (R dst) e = true ->
  wt_regset env rs ->
  satisf rs ls e' ->
  Archi.ptr64 = false ->
  satisf rs (Locmap.set (R dst) (Val.longofwords (ls (R src1)) (ls (R src2))) ls) e.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros; red; intros.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit in_subst_loc_pair; eauto. intros [[A [B [C D]]] | [A B]].
- rewrite A, B. apply H2 in C. apply H2 in D.
(* Goal: Val.lessdef (sel_val Full (Regmap.get val (ereg q) rs)) (Locmap.set (R dst) (Val.longofwords (ls (R src1)) (ls (R src2))) ls (R dst)) *)
  assert (subtype (env (ereg q)) Tlong = true).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  { exploit long_type_compat_charact; eauto. intros [P|P]; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    eelim Loc.diff_not_eq; eauto. }
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  rewrite Locmap.gss. simpl. rewrite <- (val_longofwords_eq_1 rs#(ereg q)).
(* Goal: Val.lessdef (Val.longofwords (Val.hiword (Regmap.get val (ereg q) rs)) (Val.loword (Regmap.get val (ereg q) rs))) (Val.longofwords (ls (R src1)) (ls (R src2))) *)
(* Goal: Val.has_type (Regmap.get val (ereg q) rs) Tlong *)
(* Goal: @eq bool Archi.ptr64 false *)
  apply Val.longofwords_lessdef. exact C. exact D.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply Val.has_subtype; eauto.
(* Goal: Val.lessdef (sel_val Full v) v' *)
(* Goal: satisf rs (undef_regs und ls) (remove_equation (Eq Full res (R res')) e) *)
  assumption.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
- rewrite Locmap.gso; auto.
Qed.

Lemma can_undef_sound:
  forall e ml q,
  can_undef ml e = true -> EqSet.In q e -> Loc.notin (eloc q) (map R ml).
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  induction ml; simpl; intros.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  tauto.
(* Goal: satisf (init_regs vl (@cons reg r1 rl)) ls e *)
  InvBooleans. split.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  apply Loc.diff_sym. eapply loc_unconstrained_sound; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eauto.
Qed.

Lemma undef_regs_outside:
  forall ml ls l,
  Loc.notin l (map R ml) -> undef_regs ml ls l = ls l.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  induction ml; simpl; intros. auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite Locmap.gso. apply IHml. tauto. apply Loc.diff_sym. tauto.
Qed.

Lemma can_undef_satisf:
  forall ml e rs ls,
  can_undef ml e = true ->
  satisf rs ls e ->
  satisf rs (undef_regs ml ls) e.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros; red; intros. rewrite undef_regs_outside. eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply can_undef_sound; eauto.
Qed.

Lemma can_undef_except_sound:
  forall lx e ml q,
  can_undef_except lx ml e = true -> EqSet.In q e -> Loc.diff (eloc q) lx -> Loc.notin (eloc q) (map R ml).
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  induction ml; simpl; intros.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  tauto.
(* Goal: satisf (init_regs vl (@cons reg r1 rl)) ls e *)
  InvBooleans. split.
(* Goal: Loc.diff (eloc q) (R a) *)
(* Goal: Loc.notin (eloc q) (@map mreg loc R ml) *)
  destruct (orb_true_elim _ _ H2).
(* Goal: @eq signature (funsig tf) signature_main *)
(* Goal: match_states (RTL.Callstate (@nil RTL.stackframe) f (@nil val) m0) (Callstate (@nil stackframe) tf (Locmap.init Vundef) m0) *)
  apply proj_sumbool_true in e0. congruence.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  apply Loc.diff_sym. eapply loc_unconstrained_sound; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply IHml; eauto.
Qed.

Lemma subst_loc_undef_satisf:
  forall env src dst rs ls ml e e',
  subst_loc dst src e = Some e' ->
  well_typed_move env dst e = true ->
  can_undef_except dst ml e = true ->
  wt_regset env rs ->
  satisf rs ls e' ->
  satisf rs (Locmap.set dst (ls src) (undef_regs ml ls)) e.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros; red; intros.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit in_subst_loc; eauto. intros [[A B] | [A B]].
(* Goal: Val.lessdef (Val.hiword v) (Locmap.set (R hi) (Val.hiword v') ls (R hi)) *)
(* Goal: Val.lessdef (sel_val (ekind q) (Regmap.get val (ereg q) (Regmap.set val x v rs))) (Locmap.set (R lo) (Val.loword v') (Locmap.set (R hi) (Val.hiword v') ls) (eloc q)) *)
  subst dst. rewrite Locmap.gss.
  destruct q as [k r l]; simpl in *.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit well_typed_move_charact; eauto.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  destruct l as [mr | sl ofs ty]; intros.
(* Goal: Val.lessdef (sel_val k (Regmap.get val r rs)) (ls src) *)
(* Goal: Val.lessdef (sel_val (ekind q) (Regmap.get val (ereg q) rs)) (Locmap.set dst (ls src) (undef_regs ml ls) (eloc q)) *)
  apply (H3 _ B).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  apply val_lessdef_normalize; auto. apply (H3 _ B).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite Locmap.gso; auto. rewrite undef_regs_outside. eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply can_undef_except_sound; eauto. apply Loc.diff_sym; auto.
Qed.

Lemma transfer_use_def_satisf:
  forall args res args' res' und e e' rs ls,
  transfer_use_def args res args' res' und e = Some e' ->
  satisf rs ls e' ->
  Val.lessdef_list rs##args (reglist ls args') /\
  (forall v v', Val.lessdef v v' ->
    satisf (rs#res <- v) (Locmap.set (R res') v' (undef_regs und ls)) e).
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  unfold transfer_use_def; intros. MonadInv.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  split. eapply add_equations_lessdef; eauto.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. eapply parallel_assignment_satisf; eauto. assumption.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply can_undef_satisf; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply add_equations_satisf; eauto.
Qed.

Lemma add_equations_res_lessdef:
  forall r oty l e e' rs ls,
  add_equations_res r oty l e = Some e' ->
  satisf rs ls e' ->
  Val.has_type rs#r (match oty with Some ty => ty | None => Tint end) ->
  Val.lessdef rs#r (Locmap.getpair (map_rpair R l) ls).
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. functional inversion H; simpl.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
- subst. eapply add_equation_lessdef with (q := Eq Full r (R mr)); eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
- subst. rewrite <- (val_longofwords_eq_1 rs#r) by auto.
(* Goal: Val.lessdef (Val.longofwords (Val.hiword (Regmap.get val (ereg q) rs)) (Val.loword (Regmap.get val (ereg q) rs))) (Val.longofwords (ls (R src1)) (ls (R src2))) *)
(* Goal: Val.has_type (Regmap.get val (ereg q) rs) Tlong *)
(* Goal: @eq bool Archi.ptr64 false *)
  apply Val.longofwords_lessdef.
  eapply add_equation_lessdef with (q := Eq High r (R mr1)).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply add_equation_satisf. eauto.
  eapply add_equation_lessdef with (q := Eq Low r (R mr2)).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eauto.
Qed.

Lemma return_regs_agree_callee_save:
  forall caller callee,
  agree_callee_save caller (return_regs caller callee).
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros; red; intros. unfold return_regs. red in H.
(* Goal: @eq val (caller l) match l with | R r => if is_callee_save r then caller (R r) else callee (R r) | S (Local as sl) ofs ty => caller (S sl ofs ty) | S (Incoming as sl) ofs ty => caller (S sl ofs ty) | S (Outgoing as sl) ofs ty => Vundef end *)
  destruct l.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite H; auto.
(* Goal: @eq signature (funsig tf) signature_main *)
(* Goal: match_states (RTL.Callstate (@nil RTL.stackframe) f (@nil val) m0) (Callstate (@nil stackframe) tf (Locmap.init Vundef) m0) *)
  destruct sl; auto || congruence.
Qed.

Lemma no_caller_saves_sound:
  forall e q,
  no_caller_saves e = true ->
  EqSet.In q e ->
  callee_save_loc (eloc q).
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  unfold no_caller_saves, callee_save_loc; intros.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit EqSet.for_all_2; eauto.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  hnf. intros. simpl in H1. rewrite H1. auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  lazy beta. destruct (eloc q). auto. destruct sl; congruence.
Qed.

Lemma val_hiword_longofwords:
  forall v1 v2, Val.lessdef (Val.hiword (Val.longofwords v1 v2)) v1.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. destruct v1; simpl; auto. destruct v2; auto. unfold Val.hiword.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite Int64.hi_ofwords. auto.
Qed.

Lemma val_loword_longofwords:
  forall v1 v2, Val.lessdef (Val.loword (Val.longofwords v1 v2)) v2.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. destruct v1; simpl; auto. destruct v2; auto. unfold Val.loword.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite Int64.lo_ofwords. auto.
Qed.

Lemma function_return_satisf:
  forall rs ls_before ls_after res res' sg e e' v,
  res' = loc_result sg ->
  remove_equations_res res res' e = Some e' ->
  satisf rs ls_before e' ->
  forallb (fun l => reg_loc_unconstrained res l e') (map R (regs_of_rpair res')) = true ->
  no_caller_saves e' = true ->
  Val.lessdef v (Locmap.getpair (map_rpair R res') ls_after) ->
  agree_callee_save ls_before ls_after ->
  satisf (rs#res <- v) ls_after e.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros; red; intros.
  functional inversion H0.
- (* One register *)
  subst. rewrite <- H8 in *. simpl in *. InvBooleans.
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
  set (e' := remove_equation {| ekind := Full; ereg := res; eloc := R mr |} e) in *.
  destruct (OrderedEquation.eq_dec q (Eq Full res (R mr))).
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  subst q; simpl. rewrite Regmap.gss; auto.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  assert (EqSet.In q e'). unfold e', remove_equation; simpl. ESD.fsetdec.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit reg_loc_unconstrained_sound; eauto. intros [A B].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite Regmap.gso; auto.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  exploit no_caller_saves_sound; eauto. intros.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  red in H5. rewrite <- H5; auto.
- (* Two 32-bit halves *)
  subst. rewrite <- H9 in *. simpl in *.
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
  set (e' := remove_equation {| ekind := Low; ereg := res; eloc := R mr2 |}
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
          (remove_equation {| ekind := High; ereg := res; eloc := R mr1 |} e)) in *.
(* Goal: satisf (init_regs vl (@cons reg r1 rl)) ls e *)
  InvBooleans.
(* Goal: Val.lessdef (sel_val (ekind q) (Regmap.get val (ereg q) (Regmap.set val res v rs))) (Locmap.set (R mr2) (Val.loword v') (Locmap.set (R mr1) (Val.hiword v') ls) (eloc q)) *)
  destruct (OrderedEquation.eq_dec q (Eq Low res (R mr2))).
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  subst q; simpl. rewrite Regmap.gss.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply Val.lessdef_trans. apply Val.loword_lessdef. eauto. apply val_loword_longofwords.
(* Goal: Val.lessdef (sel_val (ekind q) (Regmap.get val (ereg q) (Regmap.set val res v rs))) (Locmap.set (R mr2) (Val.loword v') (Locmap.set (R mr1) (Val.hiword v') ls) (eloc q)) *)
  destruct (OrderedEquation.eq_dec q (Eq High res (R mr1))).
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  subst q; simpl. rewrite Regmap.gss.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply Val.lessdef_trans. apply Val.hiword_lessdef. eauto. apply val_hiword_longofwords.
(* Goal: EqSet.In (Eq k2 r2 (eloc q)) (EqSet.add (Eq k2 r2 (eloc q)) (EqSet.remove q (eqs1 a))) *)
(* Goal: EqSet.In (Eq k2 r2 (eloc q)) (eqs1 a) *)
  assert (EqSet.In q e'). unfold e', remove_equation; simpl; ESD.fsetdec.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit reg_loc_unconstrained_sound. eexact H. eauto. intros [A B].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit reg_loc_unconstrained_sound. eexact H2. eauto. intros [C D].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite Regmap.gso; auto.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  exploit no_caller_saves_sound; eauto. intros.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  red in H5. rewrite <- H5; auto.
Qed.

Lemma compat_left_sound:
  forall r l e q,
  compat_left r l e = true -> EqSet.In q e -> ereg q = r -> ekind q = Full /\ eloc q = l.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  unfold compat_left; intros.
(* Goal: or (and (@eq equation_kind (ekind q) High) (@eq loc (eloc q) l1)) (and (@eq equation_kind (ekind q) Low) (@eq loc (eloc q) l2)) *)
  rewrite EqSet.for_all_between_iff in H.
(* Goal: or (and (@eq equation_kind (ekind q) High) (@eq loc (eloc q) l1)) (and (@eq equation_kind (ekind q) Low) (@eq loc (eloc q) l2)) *)
(* Goal: forall (x1 x2 : equation) (_ : @eq OrderedEquation.t x1 x2), @eq bool match ekind x1 with | Full => false | Low => @proj_sumbool (@eq loc l2 (eloc x1)) (not (@eq loc l2 (eloc x1))) (Loc.eq l2 (eloc x1)) | High => @proj_sumbool (@eq loc l1 (eloc x1)) (not (@eq loc l1 (eloc x1))) (Loc.eq l1 (eloc x1)) end match ekind x2 with | Full => false | Low => @proj_sumbool (@eq loc l2 (eloc x2)) (not (@eq loc l2 (eloc x2))) (Loc.eq l2 (eloc x2)) | High => @proj_sumbool (@eq loc l1 (eloc x2)) (not (@eq loc l1 (eloc x2))) (Loc.eq l1 (eloc x2)) end *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation.t x1 x2) (or (Plt (ereg x1) (ereg x2)) (and (@eq reg (ereg x1) (ereg x2)) (or (OrderedLoc.lt (eloc x1) (eloc x2)) (and (@eq loc (eloc x1) (eloc x2)) (OrderedEqKind.lt (ekind x1) (ekind x2))))))) (_ : @eq bool (select_reg_l r x1) true), @eq bool (select_reg_l r x2) true *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation.t x1 x2) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_reg_h r x1) true), @eq bool (select_reg_h r x2) true *)
  apply select_reg_charact in H1. destruct H1.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  exploit H; eauto. intros.
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls1 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls2 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
  destruct (ekind q); try discriminate.
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls1 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls2 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
  destruct (Loc.eq l (eloc q)); try discriminate.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  auto.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. subst x2. auto.
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation.t x1 x2) (or (Plt (ereg x1) (ereg x2)) (and (@eq reg (ereg x1) (ereg x2)) (or (OrderedLoc.lt (eloc x1) (eloc x2)) (and (@eq loc (eloc x1) (eloc x2)) (OrderedEqKind.lt (ekind x1) (ekind x2))))))) (_ : @eq bool (select_reg_l r x1) true), @eq bool (select_reg_l r x2) true *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation.t x1 x2) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_reg_h r x1) true), @eq bool (select_reg_h r x2) true *)
  exact (select_reg_l_monotone r).
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation.t x1 x2) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_reg_h r x1) true), @eq bool (select_reg_h r x2) true *)
  exact (select_reg_h_monotone r).
Qed.

Lemma compat_left2_sound:
  forall r l1 l2 e q,
  compat_left2 r l1 l2 e = true -> EqSet.In q e -> ereg q = r ->
  (ekind q = High /\ eloc q = l1) \/ (ekind q = Low /\ eloc q = l2).
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  unfold compat_left2; intros.
(* Goal: or (and (@eq equation_kind (ekind q) High) (@eq loc (eloc q) l1)) (and (@eq equation_kind (ekind q) Low) (@eq loc (eloc q) l2)) *)
  rewrite EqSet.for_all_between_iff in H.
(* Goal: or (and (@eq equation_kind (ekind q) High) (@eq loc (eloc q) l1)) (and (@eq equation_kind (ekind q) Low) (@eq loc (eloc q) l2)) *)
(* Goal: forall (x1 x2 : equation) (_ : @eq OrderedEquation.t x1 x2), @eq bool match ekind x1 with | Full => false | Low => @proj_sumbool (@eq loc l2 (eloc x1)) (not (@eq loc l2 (eloc x1))) (Loc.eq l2 (eloc x1)) | High => @proj_sumbool (@eq loc l1 (eloc x1)) (not (@eq loc l1 (eloc x1))) (Loc.eq l1 (eloc x1)) end match ekind x2 with | Full => false | Low => @proj_sumbool (@eq loc l2 (eloc x2)) (not (@eq loc l2 (eloc x2))) (Loc.eq l2 (eloc x2)) | High => @proj_sumbool (@eq loc l1 (eloc x2)) (not (@eq loc l1 (eloc x2))) (Loc.eq l1 (eloc x2)) end *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation.t x1 x2) (or (Plt (ereg x1) (ereg x2)) (and (@eq reg (ereg x1) (ereg x2)) (or (OrderedLoc.lt (eloc x1) (eloc x2)) (and (@eq loc (eloc x1) (eloc x2)) (OrderedEqKind.lt (ekind x1) (ekind x2))))))) (_ : @eq bool (select_reg_l r x1) true), @eq bool (select_reg_l r x2) true *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation.t x1 x2) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_reg_h r x1) true), @eq bool (select_reg_h r x2) true *)
  apply select_reg_charact in H1. destruct H1.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  exploit H; eauto. intros.
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls1 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls2 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
  destruct (ekind q); try discriminate.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  InvBooleans. auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  InvBooleans. auto.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. subst x2. auto.
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation.t x1 x2) (or (Plt (ereg x1) (ereg x2)) (and (@eq reg (ereg x1) (ereg x2)) (or (OrderedLoc.lt (eloc x1) (eloc x2)) (and (@eq loc (eloc x1) (eloc x2)) (OrderedEqKind.lt (ekind x1) (ekind x2))))))) (_ : @eq bool (select_reg_l r x1) true), @eq bool (select_reg_l r x2) true *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation.t x1 x2) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_reg_h r x1) true), @eq bool (select_reg_h r x2) true *)
  exact (select_reg_l_monotone r).
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation.t x1 x2) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_reg_h r x1) true), @eq bool (select_reg_h r x2) true *)
  exact (select_reg_h_monotone r).
Qed.

Lemma compat_entry_satisf:
  forall rl ll e,
  compat_entry rl ll e = true ->
  forall vl ls,
  Val.lessdef_list vl (map (fun p => Locmap.getpair p ls) ll) ->
  satisf (init_regs vl rl) ls e.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros until e. functional induction (compat_entry rl ll e); intros.
- (* no params *)
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  simpl. red; intros. rewrite Regmap.gi. destruct (ekind q); simpl; auto.
- (* a param in a single location *)
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  InvBooleans. simpl in H0. inv H0. simpl.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  red; intros. rewrite Regmap.gsspec. destruct (peq (ereg q) r1).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit compat_left_sound; eauto. intros [A B]. rewrite A; rewrite B; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply IHb; eauto.
- (* a param split across two locations *)
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  InvBooleans. simpl in H0. inv H0. simpl.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  red; intros. rewrite Regmap.gsspec. destruct (peq (ereg q) r1).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit compat_left2_sound; eauto.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  intros [[A B] | [A B]]; rewrite A; rewrite B; simpl.
(* Goal: Val.lessdef (Val.hiword v1) (ls l1) *)
(* Goal: Val.lessdef (Val.loword v1) (ls l2) *)
(* Goal: Val.lessdef (sel_val (ekind q) (Regmap.get val (ereg q) (init_regs vl1 rl))) (ls (eloc q)) *)
  apply Val.lessdef_trans with (Val.hiword (Val.longofwords (ls l1) (ls l2))).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  apply Val.hiword_lessdef; auto. apply val_hiword_longofwords.
(* Goal: Val.lessdef (Val.loword v1) (ls l2) *)
(* Goal: Val.lessdef (sel_val (ekind q) (Regmap.get val (ereg q) (init_regs vl1 rl))) (ls (eloc q)) *)
  apply Val.lessdef_trans with (Val.loword (Val.longofwords (ls l1) (ls l2))).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  apply Val.loword_lessdef; auto. apply val_loword_longofwords.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply IHb; eauto.
- (* error case *)
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls1 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls2 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
  discriminate.
Qed.

Lemma call_regs_param_values:
  forall sg ls,
  map (fun p => Locmap.getpair p (call_regs ls)) (loc_parameters sg)
  = map (fun p => Locmap.getpair p ls) (loc_arguments sg).
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. unfold loc_parameters. rewrite list_map_compose.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  apply list_map_exten; intros. symmetry.
  assert (A: forall l, loc_argument_acceptable l -> call_regs ls (parameter_of_argument l) = ls l).
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
  { destruct l as [r | [] ofs ty]; simpl; auto; contradiction. }
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  exploit loc_arguments_acceptable; eauto. destruct x; simpl; intros.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
- auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
- destruct H0; f_equal; auto.
Qed.

Lemma return_regs_arg_values:
  forall sg ls1 ls2,
  tailcall_is_possible sg = true ->
  map (fun p => Locmap.getpair p (return_regs ls1 ls2)) (loc_arguments sg)
  = map (fun p => Locmap.getpair p ls2) (loc_arguments sg).
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros.
(* Goal: @eq (list val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (return_regs ls1 ls2)) (loc_arguments sg)) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p ls2) (loc_arguments sg)) *)
  apply tailcall_is_possible_correct in H.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  apply list_map_exten; intros.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  apply Locmap.getpair_exten; intros.
(* Goal: @eq val (ls2 l) (return_regs ls1 ls2 l) *)
  assert (In l (regs_of_rpairs (loc_arguments sg))) by (eapply in_regs_of_rpairs; eauto).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit loc_arguments_acceptable_2; eauto. exploit H; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  destruct l; simpl; intros; try contradiction. rewrite H4; auto.
Qed.

Lemma find_function_tailcall:
  forall tge ros ls1 ls2,
  ros_compatible_tailcall ros = true ->
  find_function tge ros (return_regs ls1 ls2) = find_function tge ros ls2.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  unfold ros_compatible_tailcall, find_function; intros.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  destruct ros as [r|id]; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  unfold return_regs. destruct (is_callee_save r). discriminate. auto.
Qed.

Lemma loadv_int64_split:
  forall m a v,
  Mem.loadv Mint64 m a = Some v -> Archi.splitlong = true ->
  exists v1 v2,
     Mem.loadv Mint32 m a = Some (if Archi.big_endian then v1 else v2)
  /\ Mem.loadv Mint32 m (Val.add a (Vint (Int.repr 4))) = Some (if Archi.big_endian then v2 else v1)
  /\ Val.lessdef (Val.hiword v) v1
  /\ Val.lessdef (Val.loword v) v2.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. apply Archi.splitlong_ptr32 in H0.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit Mem.loadv_int64_split; eauto. intros (v1 & v2 & A & B & C).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exists v1, v2. split; auto. split; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  inv C; auto. destruct v1, v2; simpl; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite Int64.hi_ofwords, Int64.lo_ofwords; auto.
Qed.

Lemma add_equations_builtin_arg_satisf:
  forall env rs ls arg arg' e e',
  add_equations_builtin_arg env arg arg' e = Some e' ->
  satisf rs ls e' -> satisf rs ls e.
Proof.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  induction arg; destruct arg'; simpl; intros; MonadInv; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply add_equation_satisf; eauto.
(* Goal: transf_function_spec f tf *)
  destruct arg'1; MonadInv. destruct arg'2; MonadInv. eauto using add_equation_satisf.
Qed.

Lemma add_equations_builtin_arg_lessdef:
  forall env (ge: RTL.genv) sp rs ls m arg v,
  eval_builtin_arg ge (fun r => rs#r) sp m arg v ->
  forall e e' arg',
  add_equations_builtin_arg env arg arg' e = Some e' ->
  satisf rs ls e' ->
  wt_regset env rs ->
  exists v', eval_builtin_arg ge ls sp m arg' v' /\ Val.lessdef v v'.
Proof.
(* Goal: transf_function_spec f tf *)
  induction 1; simpl; intros e e' arg' AE SAT WT; destruct arg'; MonadInv.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
- exploit add_equation_lessdef; eauto. simpl; intros.
  exists (ls x0); auto with barg.
- destruct arg'1; MonadInv. destruct arg'2; MonadInv.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit add_equation_lessdef. eauto. simpl; intros LD1.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit add_equation_lessdef. eapply add_equation_satisf. eauto. simpl; intros LD2.
  exists (Val.longofwords (ls x0) (ls x1)); split; auto with barg.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite <- (val_longofwords_eq_2 rs#x); auto. apply Val.longofwords_lessdef; auto.
  rewrite <- e0; apply WT.
- econstructor; eauto with barg.
- econstructor; eauto with barg.
- econstructor; eauto with barg.
- econstructor; eauto with barg.
- econstructor; eauto with barg.
- econstructor; eauto with barg.
- econstructor; eauto with barg.
- econstructor; eauto with barg.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
- exploit IHeval_builtin_arg1; eauto. eapply add_equations_builtin_arg_satisf; eauto.
  intros (v1 & A & B).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit IHeval_builtin_arg2; eauto. intros (v2 & C & D).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exists (Val.longofwords v1 v2); split; auto with barg. apply Val.longofwords_lessdef; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
- exploit IHeval_builtin_arg1; eauto. eapply add_equations_builtin_arg_satisf; eauto.
  intros (v1' & A & B).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit IHeval_builtin_arg2; eauto. intros (v2' & C & D).
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  econstructor; split. eauto with barg.
  destruct Archi.ptr64; auto using Val.add_lessdef, Val.addl_lessdef.
Qed.

Lemma add_equations_builtin_args_satisf:
  forall env rs ls arg arg' e e',
  add_equations_builtin_args env arg arg' e = Some e' ->
  satisf rs ls e' -> satisf rs ls e.
Proof.
(* Goal: forall (env : regenv) (rs : regset) (ls : locset) (arg : list (builtin_arg reg)) (arg' : list (builtin_arg loc)) (e e' : eqs) (_ : @eq (option eqs) (add_equations_builtin_args env arg arg' e) (@Some eqs e')) (_ : satisf rs ls e'), satisf rs ls e *)
  induction arg; destruct arg'; simpl; intros; MonadInv; eauto using add_equations_builtin_arg_satisf.
Qed.

Lemma add_equations_builtin_args_lessdef:
  forall env (ge: RTL.genv) sp rs ls m tm arg vl,
  eval_builtin_args ge (fun r => rs#r) sp m arg vl ->
  forall arg' e e',
  add_equations_builtin_args env arg arg' e = Some e' ->
  satisf rs ls e' ->
  wt_regset env rs ->
  Mem.extends m tm ->
  exists vl', eval_builtin_args ge ls sp tm arg' vl' /\ Val.lessdef_list vl vl'.
Proof.
(* Goal: transf_function_spec f tf *)
  induction 1; simpl; intros; destruct arg'; MonadInv.
- exists (@nil val); split; constructor.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
- exploit IHlist_forall2; eauto. intros (vl' & A & B).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit add_equations_builtin_arg_lessdef; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply add_equations_builtin_args_satisf; eauto. intros (v1' & C & D).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit (@eval_builtin_arg_lessdef _ ge ls ls); eauto. intros (v1'' & E & F).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exists (v1'' :: vl'); split; constructor; auto. eapply Val.lessdef_trans; eauto.
Qed.

Lemma add_equations_debug_args_satisf:
  forall env rs ls arg arg' e e',
  add_equations_debug_args env arg arg' e = Some e' ->
  satisf rs ls e' -> satisf rs ls e.
Proof.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  induction arg; destruct arg'; simpl; intros; MonadInv; auto.
  destruct (add_equations_builtin_arg env a b e) as [e1|] eqn:A;
  eauto using add_equations_builtin_arg_satisf.
Qed.

Lemma add_equations_debug_args_eval:
  forall env (ge: RTL.genv) sp rs ls m tm arg vl,
  eval_builtin_args ge (fun r => rs#r) sp m arg vl ->
  forall arg' e e',
  add_equations_debug_args env arg arg' e = Some e' ->
  satisf rs ls e' ->
  wt_regset env rs ->
  Mem.extends m tm ->
  exists vl', eval_builtin_args ge ls sp tm arg' vl'.
Proof.
(* Goal: transf_function_spec f tf *)
  induction 1; simpl; intros; destruct arg'; MonadInv.
- exists (@nil val); constructor.
- exists (@nil val); constructor.
- destruct (add_equations_builtin_arg env a1 b e) as [e1|] eqn:A.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
+ exploit IHlist_forall2; eauto. intros (vl' & B).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit add_equations_builtin_arg_lessdef; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply add_equations_debug_args_satisf; eauto. intros (v1' & C & D).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit (@eval_builtin_arg_lessdef _ ge ls ls); eauto. intros (v1'' & E & F).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exists (v1'' :: vl'); constructor; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
+ eauto.
Qed.

Lemma add_equations_builtin_eval:
  forall ef env args args' e1 e2 m1 m1' rs ls (ge: RTL.genv) sp vargs t vres m2,
  wt_regset env rs ->
  match ef with
  | EF_debug _ _ _ => add_equations_debug_args env args args' e1
  | _              => add_equations_builtin_args env args args' e1
  end = Some e2 ->
  Mem.extends m1 m1' ->
  satisf rs ls e2 ->
  eval_builtin_args ge (fun r => rs # r) sp m1 args vargs ->
  external_call ef ge vargs m1 t vres m2 ->
  satisf rs ls e1 /\
  exists vargs' vres' m2',
     eval_builtin_args ge ls sp m1' args' vargs'
  /\ external_call ef ge vargs' m1' t vres' m2'
  /\ Val.lessdef vres vres'
  /\ Mem.extends m2 m2'.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros.
  assert (DEFAULT: add_equations_builtin_args env args args' e1 = Some e2 ->
    satisf rs ls e1 /\
    exists vargs' vres' m2',
       eval_builtin_args ge ls sp m1' args' vargs'
    /\ external_call ef ge vargs' m1' t vres' m2'
    /\ Val.lessdef vres vres'
    /\ Mem.extends m2 m2').
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
  {
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
    intros. split. eapply add_equations_builtin_args_satisf; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    exploit add_equations_builtin_args_lessdef; eauto.
(* Goal: forall _ : @ex (list val) (fun vl' : list val => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vl') (Val.lessdef_list vargs vl')), @ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call ef (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2')))))) *)
    intros (vargs' & A & B).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    exploit external_call_mem_extends; eauto.
(* Goal: forall _ : @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (external_call ef (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (and (Mem.extends m2 m2') (Mem.unchanged_on (loc_out_of_bounds m1) m1' m2'))))), @ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call ef (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2')))))) *)
    intros (vres' & m2' & C & D & E & F).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    exists vargs', vres', m2'; auto.
  }
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  destruct ef; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  split. eapply add_equations_debug_args_satisf; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit add_equations_debug_args_eval; eauto.
(* Goal: forall _ : @ex (list val) (fun vl' : list val => @eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vl'), @ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2')))))) *)
  intros (vargs' & A).
(* Goal: @ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2')))))) *)
  simpl in H4; inv H4.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  exists vargs', Vundef, m1'. intuition auto. simpl. constructor.
Qed.

Lemma parallel_set_builtin_res_satisf:
  forall env res res' e0 e1 rs ls v v',
  remove_equations_builtin_res env res res' e0 = Some e1 ->
  forallb (fun r => reg_unconstrained r e1) (params_of_builtin_res res) = true ->
  forallb (fun mr => loc_unconstrained (R mr) e1) (params_of_builtin_res res') = true ->
  satisf rs ls e1 ->
  Val.lessdef v v' ->
  satisf (regmap_setres res v rs) (Locmap.setres res' v' ls) e0.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. rewrite forallb_forall in *.
(* Goal: final_state st2 r *)
  destruct res, res'; simpl in *; inv H.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
- apply parallel_assignment_satisf with (k := Full); auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  unfold reg_loc_unconstrained. rewrite H0 by auto. rewrite H1 by auto. auto.
- destruct res'1; try discriminate. destruct res'2; try discriminate.
(* Goal: transf_function_spec f tf *)
  rename x0 into hi; rename x1 into lo. MonadInv. destruct (mreg_eq hi lo); inv H5.
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
  set (e' := remove_equation {| ekind := High; ereg := x; eloc := R hi |} e0) in *.
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
  set (e'' := remove_equation {| ekind := Low; ereg := x; eloc := R lo |} e') in *.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  simpl in *. red; intros.
(* Goal: Val.lessdef (sel_val (ekind q) (Regmap.get val (ereg q) (Regmap.set val x v rs))) (Locmap.set (R lo) (Val.loword v') (Locmap.set (R hi) (Val.hiword v') ls) (eloc q)) *)
  destruct (OrderedEquation.eq_dec q (Eq Low x (R lo))).
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  subst q; simpl. rewrite Regmap.gss. rewrite Locmap.gss. apply Val.loword_lessdef; auto.
(* Goal: Val.lessdef (sel_val (ekind q) (Regmap.get val (ereg q) (Regmap.set val x v rs))) (Locmap.set (R lo) (Val.loword v') (Locmap.set (R hi) (Val.hiword v') ls) (eloc q)) *)
  destruct (OrderedEquation.eq_dec q (Eq High x (R hi))).
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  subst q; simpl. rewrite Regmap.gss. rewrite Locmap.gso by (red; auto).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite Locmap.gss. apply Val.hiword_lessdef; auto.
(* Goal: Val.lessdef (sel_val (ekind q) (Regmap.get val (ereg q) (Regmap.set val x v rs))) (Locmap.set (R lo) (Val.loword v') (Locmap.set (R hi) (Val.hiword v') ls) (eloc q)) *)
  assert (EqSet.In q e'').
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
  { unfold e'', e', remove_equation; simpl; ESD.fsetdec. }
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite Regmap.gso. rewrite ! Locmap.gso. auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply loc_unconstrained_sound; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply loc_unconstrained_sound; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply reg_unconstrained_sound; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
- auto.
Qed.

(** * Properties of the dataflow analysis *)

Lemma analyze_successors:
  forall f env bsh an pc bs s e,
  analyze f env bsh = Some an ->
  bsh!pc = Some bs ->
  In s (successors_block_shape bs) ->
  an!!pc = OK e ->
  exists e', transfer f env bsh s an!!s = OK e' /\ EqSet.Subset e' e.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  unfold analyze; intros. exploit DS.fixpoint_allnodes_solution; eauto.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  rewrite H2. unfold DS.L.ge. destruct (transfer f env bsh s an#s); intros.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exists e0; auto.
(* Goal: @ex eqs (fun e' : eqs => and (@eq (res eqs) (@Error eqs e0) (@OK eqs e')) (EqSet.Subset (eqs1 e') (eqs1 e))) *)
  contradiction.
Qed.

Lemma satisf_successors:
  forall f env bsh an pc bs s e rs ls,
  analyze f env bsh = Some an ->
  bsh!pc = Some bs ->
  In s (successors_block_shape bs) ->
  an!!pc = OK e ->
  satisf rs ls e ->
  exists e', transfer f env bsh s an!!s = OK e' /\ satisf rs ls e'.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. exploit analyze_successors; eauto. intros [e' [A B]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exists e'; split; auto. eapply satisf_incr; eauto.
Qed.

(** Inversion on [transf_function] *)

Inductive transf_function_spec (f: RTL.function) (tf: LTL.function) : Prop :=
  | transf_function_spec_intro:
      forall env an mv k e1 e2,
      wt_function f env ->
      analyze f env (pair_codes f tf) = Some an ->
      (LTL.fn_code tf)!(LTL.fn_entrypoint tf) = Some(expand_moves mv (Lbranch (RTL.fn_entrypoint f) :: k)) ->
      wf_moves mv ->
      transfer f env (pair_codes f tf) (RTL.fn_entrypoint f) an!!(RTL.fn_entrypoint f) = OK e1 ->
      track_moves env mv e1 = Some e2 ->
      compat_entry (RTL.fn_params f) (loc_parameters (fn_sig tf)) e2 = true ->
      can_undef destroyed_at_function_entry e2 = true ->
      RTL.fn_stacksize f = LTL.fn_stacksize tf ->
      RTL.fn_sig f = LTL.fn_sig tf ->
      transf_function_spec f tf.

Lemma transf_function_inv:
  forall f tf,
  transf_function f = OK tf ->
  transf_function_spec f tf.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  unfold transf_function; intros.
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls1 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls2 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
  destruct (type_function f) as [env|] eqn:TY; try discriminate.
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls1 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls2 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
  destruct (regalloc f); try discriminate.
(* Goal: final_state st2 r *)
  destruct (check_function f f0 env) as [] eqn:?; inv H.
(* Goal: transf_function_spec f tf *)
  unfold check_function in Heqr.
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls1 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls2 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
  destruct (analyze f env (pair_codes f tf)) as [an|] eqn:?; try discriminate.
(* Goal: transf_function_spec f tf *)
  monadInv Heqr.
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls1 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls2 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
  destruct (check_entrypoints_aux f tf env x) as [y|] eqn:?; try discriminate.
(* Goal: transf_function_spec f tf *)
  unfold check_entrypoints_aux, pair_entrypoints in Heqo0. MonadInv.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit extract_moves_ext_sound; eauto. intros [A B]. subst b.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit check_succ_sound; eauto. intros [k EQ1]. subst b0.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto. eapply type_function_correct; eauto. congruence.
Qed.

Lemma invert_code:
  forall f env tf pc i opte e,
  wt_function f env ->
  (RTL.fn_code f)!pc = Some i ->
  transfer f env (pair_codes f tf) pc opte = OK e ->
  exists eafter, exists bsh, exists bb,
  opte = OK eafter /\
  (pair_codes f tf)!pc = Some bsh /\
  (LTL.fn_code tf)!pc = Some bb /\
  expand_block_shape bsh i bb /\
  transfer_aux f env bsh eafter = Some e /\
  wt_instr f env i.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. destruct opte as [eafter|]; simpl in H1; try discriminate. exists eafter.
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls1 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls2 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
  destruct (pair_codes f tf)!pc as [bsh|] eqn:?; try discriminate. exists bsh.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit matching_instr_block; eauto. intros [bb [A B]].
(* Goal: @ex bblock (fun bb : bblock => and (@eq (res eqs) (@OK eqs eafter) (@OK eqs eafter)) (and (@eq (option block_shape) (@Some block_shape bsh) (@Some block_shape bsh)) (and (@eq (option bblock) (@PTree.get bblock pc (fn_code tf)) (@Some bblock bb)) (and (expand_block_shape bsh i bb) (and (@eq (option eqs) (transfer_aux f env bsh eafter) (@Some eqs e)) (wt_instr f env i)))))) *)
  destruct (transfer_aux f env bsh eafter) as [e1|] eqn:?; inv H1.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exists bb. exploit wt_instr_at; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  tauto.
Qed.

(** * Semantic preservation *)

Section PRESERVATION.

Variable prog: RTL.program.
Variable tprog: LTL.program.
Hypothesis TRANSF: match_prog prog tprog.

Let ge := Genv.globalenv prog.
Let tge := Genv.globalenv tprog.

Lemma symbols_preserved:
  forall (s: ident), Genv.find_symbol tge s = Genv.find_symbol ge s.
Proof (Genv.find_symbol_match TRANSF).

Lemma senv_preserved:
  Senv.equiv ge tge.
Proof (Genv.senv_match TRANSF).

Lemma functions_translated:
  forall (v: val) (f: RTL.fundef),
  Genv.find_funct ge v = Some f ->
  exists tf,
  Genv.find_funct tge v = Some tf /\ transf_fundef f = OK tf.
Proof (Genv.find_funct_transf_partial TRANSF).

Lemma function_ptr_translated:
  forall (b: block) (f: RTL.fundef),
  Genv.find_funct_ptr ge b = Some f ->
  exists tf,
  Genv.find_funct_ptr tge b = Some tf /\ transf_fundef f = OK tf.
Proof (Genv.find_funct_ptr_transf_partial TRANSF).

Lemma sig_function_translated:
  forall f tf,
  transf_fundef f = OK tf ->
  LTL.funsig tf = RTL.funsig f.
Proof.
(* Goal: forall (f : RTL.fundef) (tf : fundef) (_ : @eq (res fundef) (transf_fundef f) (@OK fundef tf)), @eq signature (funsig tf) (RTL.funsig f) *)
  intros; destruct f; monadInv H.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  destruct (transf_function_inv _ _ EQ). simpl; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  auto.
Qed.

Lemma find_function_translated:
  forall ros rs fd ros' e e' ls,
  RTL.find_function ge ros rs = Some fd ->
  add_equation_ros ros ros' e = Some e' ->
  satisf rs ls e' ->
  exists tfd,
  LTL.find_function tge ros' ls = Some tfd /\ transf_fundef fd = OK tfd.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  unfold RTL.find_function, LTL.find_function; intros.
(* Goal: transf_function_spec f tf *)
  destruct ros as [r|id]; destruct ros' as [r'|id']; simpl in H0; MonadInv.
  (* two regs *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit add_equation_lessdef; eauto. intros LD. inv LD.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply functions_translated; eauto.
  rewrite <- H2 in H. simpl in H. congruence.
  (* two symbols *)
(* Goal: @eq (option block) (@Genv.find_symbol fundef unit (@Genv.globalenv fundef unit tprog) (@prog_main fundef unit tprog)) (@Some block b) *)
(* Goal: @eq signature (funsig tf) signature_main *)
(* Goal: match_states (RTL.Callstate (@nil RTL.stackframe) f (@nil val) m0) (Callstate (@nil stackframe) tf (Locmap.init Vundef) m0) *)
  rewrite symbols_preserved. rewrite Heqo.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply function_ptr_translated; eauto.
Qed.

Lemma exec_moves:
  forall mv env rs s f sp bb m e e' ls,
  track_moves env mv e = Some e' ->
  wf_moves mv ->
  satisf rs ls e' ->
  wt_regset env rs ->
  exists ls',
    star step tge (Block s f sp (expand_moves mv bb) ls m)
               E0 (Block s f sp bb ls' m)
  /\ satisf rs ls' e.
Proof.
Opaque destroyed_by_op.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  induction mv; simpl; intros.
  (* base *)
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
- unfold expand_moves; simpl. inv H. exists ls; split. apply star_refl. auto.
  (* step *)
- assert (wf_moves mv) by (inv H0; auto).
(* Goal: transf_function_spec f tf *)
  destruct a; unfold expand_moves; simpl; MonadInv.
+ (* loc-loc move *)
  destruct src as [rsrc | ssrc]; destruct dst as [rdst | sdst].
* (* reg-reg *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit IHmv; eauto. eapply subst_loc_undef_satisf; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  intros [ls' [A B]]. exists ls'; split; auto. eapply star_left; eauto.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  econstructor. simpl. eauto. auto. auto.
* (* reg->stack *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit IHmv; eauto. eapply subst_loc_undef_satisf; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  intros [ls' [A B]]. exists ls'; split; auto. eapply star_left; eauto.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  econstructor. simpl. eauto. auto.
* (* stack->reg *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  simpl in Heqb. exploit IHmv; eauto. eapply subst_loc_undef_satisf; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  intros [ls' [A B]]. exists ls'; split; auto. eapply star_left; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor. auto. auto.
* (* stack->stack *)
(* Goal: final_state st2 r *)
  inv H0. simpl in H6. contradiction.
+ (* makelong *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit IHmv; eauto. eapply subst_loc_pair_satisf_makelong; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  intros [ls' [A B]]. exists ls'; split; auto. eapply star_left; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor. simpl; eauto. reflexivity. traceEq.
+ (* lowlong *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit IHmv; eauto. eapply subst_loc_part_satisf_lowlong; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  intros [ls' [A B]]. exists ls'; split; auto. eapply star_left; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor. simpl; eauto. reflexivity. traceEq.
+ (* highlong *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit IHmv; eauto. eapply subst_loc_part_satisf_highlong; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  intros [ls' [A B]]. exists ls'; split; auto. eapply star_left; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor. simpl; eauto. reflexivity. traceEq.
Qed.

(** The simulation relation *)

Inductive match_stackframes: list RTL.stackframe -> list LTL.stackframe -> signature -> Prop :=
  | match_stackframes_nil: forall sg,
      sg.(sig_res) = Some Tint ->
      match_stackframes nil nil sg
  | match_stackframes_cons:
      forall res f sp pc rs s tf bb ls ts sg an e env
        (STACKS: match_stackframes s ts (fn_sig tf))
        (FUN: transf_function f = OK tf)
        (ANL: analyze f env (pair_codes f tf) = Some an)
        (EQ: transfer f env (pair_codes f tf) pc an!!pc = OK e)
        (WTF: wt_function f env)
        (WTRS: wt_regset env rs)
        (WTRES: env res = proj_sig_res sg)
        (STEPS: forall v ls1 m,
           Val.lessdef v (Locmap.getpair (map_rpair R (loc_result sg)) ls1) ->
           Val.has_type v (env res) ->
           agree_callee_save ls ls1 ->
           exists ls2,
           star LTL.step tge (Block ts tf sp bb ls1 m)
                          E0 (State ts tf sp pc ls2 m)
           /\ satisf (rs#res <- v) ls2 e),
      match_stackframes
        (RTL.Stackframe res f sp pc rs :: s)
        (LTL.Stackframe tf sp ls bb :: ts)
        sg.

Inductive match_states: RTL.state -> LTL.state -> Prop :=
  | match_states_intro:
      forall s f sp pc rs m ts tf ls m' an e env
        (STACKS: match_stackframes s ts (fn_sig tf))
        (FUN: transf_function f = OK tf)
        (ANL: analyze f env (pair_codes f tf) = Some an)
        (EQ: transfer f env (pair_codes f tf) pc an!!pc = OK e)
        (SAT: satisf rs ls e)
        (MEM: Mem.extends m m')
        (WTF: wt_function f env)
        (WTRS: wt_regset env rs),
      match_states (RTL.State s f sp pc rs m)
                   (LTL.State ts tf sp pc ls m')
  | match_states_call:
      forall s f args m ts tf ls m'
        (STACKS: match_stackframes s ts (funsig tf))
        (FUN: transf_fundef f = OK tf)
        (ARGS: Val.lessdef_list args (map (fun p => Locmap.getpair p ls) (loc_arguments (funsig tf))))
        (AG: agree_callee_save (parent_locset ts) ls)
        (MEM: Mem.extends m m')
        (WTARGS: Val.has_type_list args (sig_args (funsig tf))),
      match_states (RTL.Callstate s f args m)
                   (LTL.Callstate ts tf ls m')
  | match_states_return:
      forall s res m ts ls m' sg
        (STACKS: match_stackframes s ts sg)
        (RES: Val.lessdef res (Locmap.getpair (map_rpair R (loc_result sg)) ls))
        (AG: agree_callee_save (parent_locset ts) ls)
        (MEM: Mem.extends m m')
        (WTRES: Val.has_type res (proj_sig_res sg)),
      match_states (RTL.Returnstate s res m)
                   (LTL.Returnstate ts ls m').

Lemma match_stackframes_change_sig:
  forall s ts sg sg',
  match_stackframes s ts sg ->
  sg'.(sig_res) = sg.(sig_res) ->
  match_stackframes s ts sg'.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. inv H.
(* Goal: Val.has_type_list (@nil val) (sig_args signature_main) *)
  constructor. congruence.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  unfold proj_sig_res in *. rewrite H0; auto.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. rewrite (loc_result_exten sg' sg) in H by auto. eauto.
Qed.

Ltac UseShape :=
  match goal with
  | [ WT: wt_function _ _, CODE: (RTL.fn_code _)!_ = Some _, EQ: transfer _ _ _ _ _ = OK _ |- _ ] =>
      destruct (invert_code _ _ _ _ _ _ _ WT CODE EQ) as (eafter & bsh & bb & AFTER & BSH & TCODE & EBS & TR & WTI);
      inv EBS; unfold transfer_aux in TR; MonadInv
  end.

Remark addressing_not_long:
  forall env f addr args dst s r,
  wt_instr f env (Iload Mint64 addr args dst s) -> Archi.splitlong = true ->
  In r args -> r <> dst.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. inv H.
  assert (A: forall ty, In ty (type_of_addressing addr) -> ty = Tptr).
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  { intros. destruct addr; simpl in H; intuition. }
(* Goal: not (@eq reg r dst) *)
  assert (B: In (env r) (type_of_addressing addr)).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  { rewrite <- H5. apply in_map; auto. }
(* Goal: not (@eq reg r dst) *)
  assert (C: env r = Tint).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  { apply A in B. rewrite B. unfold Tptr. rewrite Archi.splitlong_ptr32 by auto. auto. }
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls1 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls2 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
  red; intros; subst r. rewrite C in H8; discriminate.
Qed.

(** The proof of semantic preservation is a simulation argument of the
    "plus" kind. *)

Lemma step_simulation:
  forall S1 t S2, RTL.step ge S1 t S2 -> wt_state S1 ->
  forall S1', match_states S1 S1' ->
  exists S2', plus LTL.step tge S1' t S2' /\ match_states S2 S2'.
Proof.
  induction 1; intros WT S1' MS; inv MS; try UseShape.

(* nop *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
- exploit exec_moves; eauto. intros [ls1 [X Y]].
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  econstructor; split.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply plus_left. econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply star_right. eexact X. econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eauto. traceEq.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit satisf_successors; eauto. simpl; eauto. intros [enext [U V]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto.

(* op move *)
- generalize (wt_exec_Iop _ _ _ _ _ _ _ _ _ _ _ WTI H0 WTRS). intros WTRS'.
(* Goal: final_state st2 r *)
  simpl in H0. inv H0.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit (exec_moves mv); eauto. intros [ls1 [X Y]].
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  econstructor; split.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply plus_left. econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply star_right. eexact X. econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eauto. traceEq.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit satisf_successors; eauto. simpl; eauto. eapply subst_reg_satisf; eauto.
  intros [enext [U V]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto.

(* op makelong *)
- generalize (wt_exec_Iop _ _ _ _ _ _ _ _ _ _ _ WTI H0 WTRS). intros WTRS'.
(* Goal: final_state st2 r *)
  simpl in H0. inv H0.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit (exec_moves mv); eauto. intros [ls1 [X Y]].
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  econstructor; split.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply plus_left. econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply star_right. eexact X. econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eauto. traceEq.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit satisf_successors; eauto. simpl; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply subst_reg_kind_satisf_makelong. eauto. eauto.
  intros [enext [U V]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto.

(* op lowlong *)
- generalize (wt_exec_Iop _ _ _ _ _ _ _ _ _ _ _ WTI H0 WTRS). intros WTRS'.
(* Goal: final_state st2 r *)
  simpl in H0. inv H0.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit (exec_moves mv); eauto. intros [ls1 [X Y]].
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  econstructor; split.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply plus_left. econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply star_right. eexact X. econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eauto. traceEq.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit satisf_successors; eauto. simpl; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply subst_reg_kind_satisf_lowlong. eauto. eauto.
  intros [enext [U V]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto.

(* op highlong *)
- generalize (wt_exec_Iop _ _ _ _ _ _ _ _ _ _ _ WTI H0 WTRS). intros WTRS'.
(* Goal: final_state st2 r *)
  simpl in H0. inv H0.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit (exec_moves mv); eauto. intros [ls1 [X Y]].
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  econstructor; split.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply plus_left. econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply star_right. eexact X. econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eauto. traceEq.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit satisf_successors; eauto. simpl; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply subst_reg_kind_satisf_highlong. eauto. eauto.
  intros [enext [U V]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto.

(* op regular *)
- generalize (wt_exec_Iop _ _ _ _ _ _ _ _ _ _ _ WTI H0 WTRS). intros WTRS'.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit (exec_moves mv1); eauto. intros [ls1 [A1 B1]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit transfer_use_def_satisf; eauto. intros [X Y].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit eval_operation_lessdef; eauto. intros [v' [F G]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit (exec_moves mv2); eauto. intros [ls2 [A2 B2]].
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  econstructor; split.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply plus_left. econstructor; eauto.
  eapply star_trans. eexact A1.
  eapply star_left. econstructor. instantiate (1 := v'). rewrite <- F.
  apply eval_operation_preserved. exact symbols_preserved.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eauto. eapply star_right. eexact A2. constructor.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eauto. eauto. eauto. traceEq.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit satisf_successors; eauto. simpl; eauto. intros [enext [U V]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto.

(* op dead *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
- exploit exec_moves; eauto. intros [ls1 [X Y]].
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  econstructor; split.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply plus_left. econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply star_right. eexact X. econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eauto. traceEq.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit satisf_successors. eauto. eauto. simpl; eauto. eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply reg_unconstrained_satisf; eauto.
  intros [enext [U V]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply wt_exec_Iop; eauto.

(* load regular *)
- generalize (wt_exec_Iload _ _ _ _ _ _ _ _ _ _ _ WTI H1 WTRS). intros WTRS'.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit (exec_moves mv1); eauto. intros [ls1 [A1 B1]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit transfer_use_def_satisf; eauto. intros [X Y].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit eval_addressing_lessdef; eauto. intros [a' [F G]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit Mem.loadv_extends; eauto. intros [v' [P Q]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit (exec_moves mv2); eauto. intros [ls2 [A2 B2]].
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  econstructor; split.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply plus_left. econstructor; eauto.
  eapply star_trans. eexact A1.
  eapply star_left. econstructor. instantiate (1 := a'). rewrite <- F.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  apply eval_addressing_preserved. exact symbols_preserved. eauto. eauto.
(* Goal: Val.has_type_list (@nil val) (sig_args signature_main) *)
  eapply star_right. eexact A2. constructor.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eauto. eauto. eauto. traceEq.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit satisf_successors; eauto. simpl; eauto. intros [enext [U V]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto.

(* load pair *)
- generalize (wt_exec_Iload _ _ _ _ _ _ _ _ _ _ _ WTI H1 WTRS). intros WTRS'.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit loadv_int64_split; eauto. intros (v1 & v2 & LOAD1 & LOAD2 & V1 & V2).
  set (v2' := if Archi.big_endian then v2 else v1) in *.
  set (v1' := if Archi.big_endian then v1 else v2) in *.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit (exec_moves mv1); eauto. intros [ls1 [A1 B1]].
  assert (LD1: Val.lessdef_list rs##args (reglist ls1 args1')).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  { eapply add_equations_lessdef; eauto. }
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit eval_addressing_lessdef. eexact LD1. eauto. intros [a1' [F1 G1]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit Mem.loadv_extends. eauto. eexact LOAD1. eexact G1. intros (v1'' & LOAD1' & LD2).
  set (ls2 := Locmap.set (R dst1') v1'' (undef_regs (destroyed_by_load Mint32 addr) ls1)).
  assert (SAT2: satisf (rs#dst <- v) ls2 e2).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  { eapply loc_unconstrained_satisf. eapply can_undef_satisf; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    eapply reg_unconstrained_satisf. eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    eapply add_equations_satisf; eauto. assumption.
(* Goal: Val.lessdef (Val.hiword (Regmap.get val x (Regmap.set val x v rs))) (Locmap.set (R lo) (Val.loword v') (Locmap.set (R hi) (Val.hiword v') ls) (R hi)) *)
(* Goal: Val.lessdef (sel_val (ekind q) (Regmap.get val (ereg q) (Regmap.set val x v rs))) (Locmap.set (R lo) (Val.loword v') (Locmap.set (R hi) (Val.hiword v') ls) (eloc q)) *)
    rewrite Regmap.gss.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    apply Val.lessdef_trans with v1'; unfold sel_val; unfold kind_first_word; unfold v1'; destruct Archi.big_endian; auto.
  }
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit (exec_moves mv2); eauto. intros [ls3 [A3 B3]].
  assert (LD3: Val.lessdef_list rs##args (reglist ls3 args2')).
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
  { replace (rs##args) with ((rs#dst<-v)##args).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    eapply add_equations_lessdef; eauto.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
    apply list_map_exten; intros. rewrite Regmap.gso; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    eapply addressing_not_long; eauto.
  }
  exploit eval_addressing_lessdef. eexact LD3.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply eval_offset_addressing; eauto; apply Archi.splitlong_ptr32; auto.
  intros [a2' [F2 G2]].
  assert (LOADX: exists v2'', Mem.loadv Mint32 m' a2' = Some v2'' /\ Val.lessdef v2' v2'').
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
  { discriminate || (eapply Mem.loadv_extends; [eauto|eexact LOAD2|eexact G2]). }
  destruct LOADX as (v2'' & LOAD2' & LD4).
  set (ls4 := Locmap.set (R dst2') v2'' (undef_regs (destroyed_by_load Mint32 addr2) ls3)).
  assert (SAT4: satisf (rs#dst <- v) ls4 e0).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  { eapply loc_unconstrained_satisf. eapply can_undef_satisf; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    eapply add_equations_satisf; eauto. assumption.
(* Goal: Val.lessdef (Val.hiword (Regmap.get val x (Regmap.set val x v rs))) (Locmap.set (R lo) (Val.loword v') (Locmap.set (R hi) (Val.hiword v') ls) (R hi)) *)
(* Goal: Val.lessdef (sel_val (ekind q) (Regmap.get val (ereg q) (Regmap.set val x v rs))) (Locmap.set (R lo) (Val.loword v') (Locmap.set (R hi) (Val.hiword v') ls) (eloc q)) *)
    rewrite Regmap.gss.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    apply Val.lessdef_trans with v2'; unfold sel_val; unfold kind_second_word; unfold v2'; destruct Archi.big_endian; auto.
  }
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit (exec_moves mv3); eauto. intros [ls5 [A5 B5]].
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  econstructor; split.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply plus_left. econstructor; eauto.
  eapply star_trans. eexact A1.
(* Goal: Val.has_type_list (@nil val) (sig_args signature_main) *)
  eapply star_left. econstructor.
  instantiate (1 := a1'). rewrite <- F1. apply eval_addressing_preserved. exact symbols_preserved.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eexact LOAD1'. instantiate (1 := ls2); auto.
  eapply star_trans. eexact A3.
(* Goal: Val.has_type_list (@nil val) (sig_args signature_main) *)
  eapply star_left. econstructor.
  instantiate (1 := a2'). rewrite <- F2. apply eval_addressing_preserved. exact symbols_preserved.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eexact LOAD2'. instantiate (1 := ls4); auto.
(* Goal: or (@eq bool (subtype (env (ereg q)) Tlong) true) (Loc.diff l (eloc q)) *)
(* Goal: forall (x1 x2 : equation) (_ : @eq OrderedEquation'.t x1 x2), @eq bool (subtype (env (ereg x1)) Tlong) (subtype (env (ereg x2)) Tlong) *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x1) (eloc x2)) (and (@eq loc (eloc x1) (eloc x2)) (or (Plt (ereg x1) (ereg x2)) (and (@eq reg (ereg x1) (ereg x2)) (OrderedEqKind.lt (ekind x1) (ekind x2))))))) (_ : @eq bool (select_loc_l l x1) true), @eq bool (select_loc_l l x2) true *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_loc_h l x1) true), @eq bool (select_loc_h l x2) true *)
  eapply star_right. eexact A5.
(* Goal: Val.has_type_list (@nil val) (sig_args signature_main) *)
  constructor.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eauto. eauto. eauto. eauto. eauto. traceEq.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit satisf_successors; eauto. simpl; eauto. intros [enext [W Z]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto.

(* load first word of a pair *)
- generalize (wt_exec_Iload _ _ _ _ _ _ _ _ _ _ _ WTI H1 WTRS). intros WTRS'.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit loadv_int64_split; eauto. intros (v1 & v2 & LOAD1 & LOAD2 & V1 & V2).
  set (v2' := if Archi.big_endian then v2 else v1) in *.
  set (v1' := if Archi.big_endian then v1 else v2) in *.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit (exec_moves mv1); eauto. intros [ls1 [A1 B1]].
  assert (LD1: Val.lessdef_list rs##args (reglist ls1 args')).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  { eapply add_equations_lessdef; eauto. }
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit eval_addressing_lessdef. eexact LD1. eauto. intros [a1' [F1 G1]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit Mem.loadv_extends. eauto. eexact LOAD1. eexact G1. intros (v1'' & LOAD1' & LD2).
  set (ls2 := Locmap.set (R dst') v1'' (undef_regs (destroyed_by_load Mint32 addr) ls1)).
  assert (SAT2: satisf (rs#dst <- v) ls2 e0).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  { eapply parallel_assignment_satisf; eauto.
    apply Val.lessdef_trans with v1';
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    unfold sel_val; unfold kind_first_word; unfold v1'; destruct Archi.big_endian; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    eapply can_undef_satisf. eauto. eapply add_equations_satisf; eauto.
  }
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit (exec_moves mv2); eauto. intros [ls3 [A3 B3]].
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  econstructor; split.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply plus_left. econstructor; eauto.
  eapply star_trans. eexact A1.
(* Goal: Val.has_type_list (@nil val) (sig_args signature_main) *)
  eapply star_left. econstructor.
  instantiate (1 := a1'). rewrite <- F1. apply eval_addressing_preserved. exact symbols_preserved.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eexact LOAD1'. instantiate (1 := ls2); auto.
(* Goal: or (@eq bool (subtype (env (ereg q)) Tlong) true) (Loc.diff l (eloc q)) *)
(* Goal: forall (x1 x2 : equation) (_ : @eq OrderedEquation'.t x1 x2), @eq bool (subtype (env (ereg x1)) Tlong) (subtype (env (ereg x2)) Tlong) *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x1) (eloc x2)) (and (@eq loc (eloc x1) (eloc x2)) (or (Plt (ereg x1) (ereg x2)) (and (@eq reg (ereg x1) (ereg x2)) (OrderedEqKind.lt (ekind x1) (ekind x2))))))) (_ : @eq bool (select_loc_l l x1) true), @eq bool (select_loc_l l x2) true *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_loc_h l x1) true), @eq bool (select_loc_h l x2) true *)
  eapply star_right. eexact A3.
(* Goal: Val.has_type_list (@nil val) (sig_args signature_main) *)
  constructor.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eauto. eauto. eauto. traceEq.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit satisf_successors; eauto. simpl; eauto. intros [enext [W Z]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto.

(* load second word of a pair *)
- generalize (wt_exec_Iload _ _ _ _ _ _ _ _ _ _ _ WTI H1 WTRS). intros WTRS'.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit loadv_int64_split; eauto. intros (v1 & v2 & LOAD1 & LOAD2 & V1 & V2).
  set (v2' := if Archi.big_endian then v2 else v1) in *.
  set (v1' := if Archi.big_endian then v1 else v2) in *.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit (exec_moves mv1); eauto. intros [ls1 [A1 B1]].
  assert (LD1: Val.lessdef_list rs##args (reglist ls1 args')).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  { eapply add_equations_lessdef; eauto. }
  exploit eval_addressing_lessdef. eexact LD1.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply eval_offset_addressing; eauto; apply Archi.splitlong_ptr32; auto.
  intros [a1' [F1 G1]].
  assert (LOADX: exists v2'', Mem.loadv Mint32 m' a1' = Some v2'' /\ Val.lessdef v2' v2'').
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
  { discriminate || (eapply Mem.loadv_extends; [eauto|eexact LOAD2|eexact G1]). }
  destruct LOADX as (v2'' & LOAD2' & LD2).
  set (ls2 := Locmap.set (R dst') v2'' (undef_regs (destroyed_by_load Mint32 addr2) ls1)).
  assert (SAT2: satisf (rs#dst <- v) ls2 e0).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  { eapply parallel_assignment_satisf; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    apply Val.lessdef_trans with v2'; unfold sel_val; unfold kind_second_word; unfold v2'; destruct Archi.big_endian; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    eapply can_undef_satisf. eauto. eapply add_equations_satisf; eauto.
  }
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit (exec_moves mv2); eauto. intros [ls3 [A3 B3]].
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  econstructor; split.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply plus_left. econstructor; eauto.
  eapply star_trans. eexact A1.
(* Goal: Val.has_type_list (@nil val) (sig_args signature_main) *)
  eapply star_left. econstructor.
  instantiate (1 := a1'). rewrite <- F1. apply eval_addressing_preserved. exact symbols_preserved.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eexact LOAD2'. instantiate (1 := ls2); auto.
(* Goal: or (@eq bool (subtype (env (ereg q)) Tlong) true) (Loc.diff l (eloc q)) *)
(* Goal: forall (x1 x2 : equation) (_ : @eq OrderedEquation'.t x1 x2), @eq bool (subtype (env (ereg x1)) Tlong) (subtype (env (ereg x2)) Tlong) *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x1) (eloc x2)) (and (@eq loc (eloc x1) (eloc x2)) (or (Plt (ereg x1) (ereg x2)) (and (@eq reg (ereg x1) (ereg x2)) (OrderedEqKind.lt (ekind x1) (ekind x2))))))) (_ : @eq bool (select_loc_l l x1) true), @eq bool (select_loc_l l x2) true *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_loc_h l x1) true), @eq bool (select_loc_h l x2) true *)
  eapply star_right. eexact A3.
(* Goal: Val.has_type_list (@nil val) (sig_args signature_main) *)
  constructor.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eauto. eauto. eauto. traceEq.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit satisf_successors; eauto. simpl; eauto. intros [enext [W Z]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto.

(* load dead *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
- exploit exec_moves; eauto. intros [ls1 [X Y]].
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  econstructor; split.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply plus_left. econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply star_right. eexact X. econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eauto. traceEq.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit satisf_successors. eauto. eauto. simpl; eauto. eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply reg_unconstrained_satisf; eauto.
  intros [enext [U V]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply wt_exec_Iload; eauto.

(* store *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
- exploit exec_moves; eauto. intros [ls1 [X Y]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit add_equations_lessdef; eauto. intros LD. simpl in LD. inv LD.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit eval_addressing_lessdef; eauto. intros [a' [F G]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit Mem.storev_extends; eauto. intros [m'' [P Q]].
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  econstructor; split.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply plus_left. econstructor; eauto.
  eapply star_trans. eexact X.
  eapply star_two. econstructor. instantiate (1 := a'). rewrite <- F.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  apply eval_addressing_preserved. exact symbols_preserved. eauto. eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  constructor. eauto. eauto. traceEq.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit satisf_successors; eauto. simpl; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply can_undef_satisf; eauto. eapply add_equations_satisf; eauto. intros [enext [U V]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto.

(* store 2 *)
- assert (SF: Archi.ptr64 = false) by (apply Archi.splitlong_ptr32; auto).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit Mem.storev_int64_split; eauto.
  replace (if Archi.big_endian then Val.hiword rs#src else Val.loword rs#src)
     with (sel_val kind_first_word rs#src)
       by (unfold kind_first_word; destruct Archi.big_endian; reflexivity).
  replace (if Archi.big_endian then Val.loword rs#src else Val.hiword rs#src)
     with (sel_val kind_second_word rs#src)
       by (unfold kind_second_word; destruct Archi.big_endian; reflexivity).
  intros [m1 [STORE1 STORE2]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit (exec_moves mv1); eauto. intros [ls1 [X Y]].
  exploit add_equations_lessdef. eexact Heqo1. eexact Y. intros LD1.
  exploit add_equation_lessdef. eapply add_equations_satisf. eexact Heqo1. eexact Y.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  simpl. intros LD2.
  set (ls2 := undef_regs (destroyed_by_store Mint32 addr) ls1).
  assert (SAT2: satisf rs ls2 e1).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    eapply can_undef_satisf. eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    eapply add_equation_satisf. eapply add_equations_satisf; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit eval_addressing_lessdef. eexact LD1. eauto. intros [a1' [F1 G1]].
  assert (F1': eval_addressing tge sp addr (reglist ls1 args1') = Some a1').
    rewrite <- F1. apply eval_addressing_preserved. exact symbols_preserved.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit Mem.storev_extends. eauto. eexact STORE1. eexact G1. eauto.
  intros [m1' [STORE1' EXT1]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit (exec_moves mv2); eauto. intros [ls3 [U V]].
  exploit add_equations_lessdef. eexact Heqo. eexact V. intros LD3.
  exploit add_equation_lessdef. eapply add_equations_satisf. eexact Heqo. eexact V.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  simpl. intros LD4.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit eval_addressing_lessdef. eexact LD3. eauto. intros [a2' [F2 G2]].
  assert (F2': eval_addressing tge sp addr (reglist ls3 args2') = Some a2').
    rewrite <- F2. apply eval_addressing_preserved. exact symbols_preserved.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit (eval_offset_addressing tge); eauto. intros F2''.
  assert (STOREX: exists m2', Mem.storev Mint32 m1' (Val.add a2' (Vint (Int.repr 4))) (ls3 (R src2')) = Some m2' /\ Mem.extends m' m2').
(* Goal: @eq typ (env r) Tint *)
(* Goal: not (@eq reg r dst) *)
  { try discriminate;
    (eapply Mem.storev_extends;
     [eexact EXT1 | eexact STORE2 | apply Val.add_lessdef; [eexact G2|eauto] | eauto]). }
  destruct STOREX as [m2' [STORE2' EXT2]].
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  econstructor; split.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply plus_left. econstructor; eauto.
  eapply star_trans. eexact X.
(* Goal: or (and (@eq (prod reg equation_kind) (@pair reg equation_kind (ereg q) (ekind q)) (@pair reg equation_kind r1 k1)) (EqSet.In (Eq k2 r2 (eloc q)) (eqs1 (subst_reg_kind r1 k1 r2 k2 e0)))) (EqSet.In q (eqs1 (subst_reg_kind r1 k1 r2 k2 e0))) *)
(* Goal: or (and (@eq (prod reg equation_kind) (@pair reg equation_kind (ereg q) (ekind q)) (@pair reg equation_kind r1 k1)) (EqSet.In (Eq k2 r2 (eloc q)) (eqs1 (subst_reg_kind r1 k1 r2 k2 e0)))) (EqSet.In q (eqs1 (subst_reg_kind r1 k1 r2 k2 e0))) *)
(* Goal: or (and (@eq (prod reg equation_kind) (@pair reg equation_kind (ereg q) (ekind q)) (@pair reg equation_kind r1 k1)) (EqSet.In (Eq k2 r2 (eloc q)) (eqs1 (subst_reg_kind r1 k1 r2 k2 e0)))) (EqSet.In q (eqs1 (subst_reg_kind r1 k1 r2 k2 e0))) *)
  eapply star_left.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor. eexact F1'. eexact STORE1'. instantiate (1 := ls2). auto.
  eapply star_trans. eexact U.
  eapply star_two.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply exec_Lstore with (m' := m2'). eexact F2''. discriminate||exact STORE2'. eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  constructor. eauto. eauto. eauto. eauto. traceEq.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit satisf_successors; eauto. simpl; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply can_undef_satisf. eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply add_equation_satisf. eapply add_equations_satisf; eauto.
  intros [enext [P Q]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto.

(* call *)
- set (sg := RTL.funsig fd) in *.
  set (args' := loc_arguments sg) in *.
  set (res' := loc_result sg) in *.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit (exec_moves mv1); eauto. intros [ls1 [A1 B1]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit find_function_translated. eauto. eauto. eapply add_equations_args_satisf; eauto.
  intros [tfd [E F]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  assert (SIG: funsig tfd = sg). eapply sig_function_translated; eauto.
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  econstructor; split.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply plus_left. econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply star_right. eexact A1. econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eauto. traceEq.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  exploit analyze_successors; eauto. simpl. left; eauto. intros [enext [U V]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto.
(* Goal: @eq signature (funsig tf) signature_main *)
(* Goal: match_states (RTL.Callstate (@nil RTL.stackframe) f (@nil val) m0) (Callstate (@nil stackframe) tf (Locmap.init Vundef) m0) *)
  inv WTI. congruence.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. exploit (exec_moves mv2). eauto. eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply function_return_satisf with (v := v) (ls_before := ls1) (ls_after := ls0); eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply add_equation_ros_satisf; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply add_equations_args_satisf; eauto.
(* Goal: @eq signature (funsig tf) signature_main *)
(* Goal: match_states (RTL.Callstate (@nil RTL.stackframe) f (@nil val) m0) (Callstate (@nil stackframe) tf (Locmap.init Vundef) m0) *)
  congruence.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  apply wt_regset_assign; auto.
  intros [ls2 [A2 B2]].
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  exists ls2; split.
(* Goal: Val.has_type_list (@nil val) (sig_args signature_main) *)
  eapply star_right. eexact A2. constructor. traceEq.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  apply satisf_incr with eafter; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite SIG. eapply add_equations_args_lessdef; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  inv WTI. rewrite <- H7. apply wt_regset_list; auto.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  simpl. red; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  inv WTI. rewrite SIG. rewrite <- H7. apply wt_regset_list; auto.

(* tailcall *)
- set (sg := RTL.funsig fd) in *.
  set (args' := loc_arguments sg) in *.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit Mem.free_parallel_extends; eauto. intros [m'' [P Q]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit (exec_moves mv); eauto. intros [ls1 [A1 B1]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit find_function_translated. eauto. eauto. eapply add_equations_args_satisf; eauto.
  intros [tfd [E F]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  assert (SIG: funsig tfd = sg). eapply sig_function_translated; eauto.
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  econstructor; split.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply plus_left. econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply star_right. eexact A1. econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite <- E. apply find_function_tailcall; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  replace (fn_stacksize tf) with (RTL.fn_stacksize f); eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  destruct (transf_function_inv _ _ FUN); auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eauto. traceEq.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply match_stackframes_change_sig; eauto. rewrite SIG. rewrite e0. decEq.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  destruct (transf_function_inv _ _ FUN); auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite SIG. rewrite return_regs_arg_values; auto. eapply add_equations_args_lessdef; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  inv WTI. rewrite <- H6. apply wt_regset_list; auto.
  apply return_regs_agree_callee_save.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite SIG. inv WTI. rewrite <- H6. apply wt_regset_list; auto.

(* builtin *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
- exploit (exec_moves mv1); eauto. intros [ls1 [A1 B1]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit add_equations_builtin_eval; eauto.
  intros (C & vargs' & vres' & m'' & D & E & F & G).
  assert (WTRS': wt_regset env (regmap_setres res vres rs)) by (eapply wt_exec_Ibuiltin; eauto).
  set (ls2 := Locmap.setres res' vres' (undef_regs (destroyed_by_builtin ef) ls1)).
  assert (satisf (regmap_setres res vres rs) ls2 e0).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  { eapply parallel_set_builtin_res_satisf; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    eapply can_undef_satisf; eauto. }
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit (exec_moves mv2); eauto. intros [ls3 [A3 B3]].
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  econstructor; split.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply plus_left. econstructor; eauto.
  eapply star_trans. eexact A1.
(* Goal: Val.has_type_list (@nil val) (sig_args signature_main) *)
  eapply star_left. econstructor.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply eval_builtin_args_preserved with (ge1 := ge); eauto. exact symbols_preserved.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply external_call_symbols_preserved. apply senv_preserved. eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  instantiate (1 := ls2); auto.
(* Goal: or (@eq bool (subtype (env (ereg q)) Tlong) true) (Loc.diff l (eloc q)) *)
(* Goal: forall (x1 x2 : equation) (_ : @eq OrderedEquation'.t x1 x2), @eq bool (subtype (env (ereg x1)) Tlong) (subtype (env (ereg x2)) Tlong) *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x1) (eloc x2)) (and (@eq loc (eloc x1) (eloc x2)) (or (Plt (ereg x1) (ereg x2)) (and (@eq reg (ereg x1) (ereg x2)) (OrderedEqKind.lt (ekind x1) (ekind x2))))))) (_ : @eq bool (select_loc_l l x1) true), @eq bool (select_loc_l l x2) true *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_loc_h l x1) true), @eq bool (select_loc_h l x2) true *)
  eapply star_right. eexact A3.
(* Goal: Val.has_type_list (@nil val) (sig_args signature_main) *)
  econstructor.
(* Goal: @eq val (Val.longofwords (Val.hiword Vundef) (Val.loword Vundef)) Vundef *)
  reflexivity. reflexivity. reflexivity. traceEq.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit satisf_successors; eauto. simpl; eauto.
  intros [enext [U V]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto.

(* cond *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
- exploit (exec_moves mv); eauto. intros [ls1 [A1 B1]].
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  econstructor; split.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply plus_left. econstructor; eauto.
(* Goal: or (@eq bool (subtype (env (ereg q)) Tlong) true) (Loc.diff l (eloc q)) *)
(* Goal: forall (x1 x2 : equation) (_ : @eq OrderedEquation'.t x1 x2), @eq bool (subtype (env (ereg x1)) Tlong) (subtype (env (ereg x2)) Tlong) *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x1) (eloc x2)) (and (@eq loc (eloc x1) (eloc x2)) (or (Plt (ereg x1) (ereg x2)) (and (@eq reg (ereg x1) (ereg x2)) (OrderedEqKind.lt (ekind x1) (ekind x2))))))) (_ : @eq bool (select_loc_l l x1) true), @eq bool (select_loc_l l x2) true *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_loc_h l x1) true), @eq bool (select_loc_h l x2) true *)
  eapply star_right. eexact A1.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor. eapply eval_condition_lessdef; eauto. eapply add_equations_lessdef; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eauto. eauto. eauto. traceEq.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit satisf_successors; eauto.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  instantiate (1 := if b then ifso else ifnot). simpl. destruct b; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply can_undef_satisf. eauto. eapply add_equations_satisf; eauto.
  intros [enext [U V]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto.

(* jumptable *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
- exploit (exec_moves mv); eauto. intros [ls1 [A1 B1]].
  assert (Val.lessdef (Vint n) (ls1 (R arg'))).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    rewrite <- H0. eapply add_equation_lessdef with (q := Eq Full arg (R arg')); eauto.
  inv H2.
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  econstructor; split.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply plus_left. econstructor; eauto.
(* Goal: or (@eq bool (subtype (env (ereg q)) Tlong) true) (Loc.diff l (eloc q)) *)
(* Goal: forall (x1 x2 : equation) (_ : @eq OrderedEquation'.t x1 x2), @eq bool (subtype (env (ereg x1)) Tlong) (subtype (env (ereg x2)) Tlong) *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x1) (eloc x2)) (and (@eq loc (eloc x1) (eloc x2)) (or (Plt (ereg x1) (ereg x2)) (and (@eq reg (ereg x1) (ereg x2)) (OrderedEqKind.lt (ekind x1) (ekind x2))))))) (_ : @eq bool (select_loc_l l x1) true), @eq bool (select_loc_l l x2) true *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_loc_h l x1) true), @eq bool (select_loc_h l x2) true *)
  eapply star_right. eexact A1.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor. eauto. eauto. eauto. eauto. traceEq.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit satisf_successors; eauto.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  instantiate (1 := pc'). simpl. eapply list_nth_z_in; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply can_undef_satisf. eauto. eapply add_equation_satisf; eauto.
  intros [enext [U V]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto.

(* return *)
- destruct (transf_function_inv _ _ FUN).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit Mem.free_parallel_extends; eauto. rewrite H10. intros [m'' [P Q]].
(* Goal: transf_function_spec f tf *)
  inv WTI; MonadInv.
+ (* without an argument *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit (exec_moves mv); eauto. intros [ls1 [A1 B1]].
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  econstructor; split.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply plus_left. econstructor; eauto.
(* Goal: or (@eq bool (subtype (env (ereg q)) Tlong) true) (Loc.diff l (eloc q)) *)
(* Goal: forall (x1 x2 : equation) (_ : @eq OrderedEquation'.t x1 x2), @eq bool (subtype (env (ereg x1)) Tlong) (subtype (env (ereg x2)) Tlong) *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x1) (eloc x2)) (and (@eq loc (eloc x1) (eloc x2)) (or (Plt (ereg x1) (ereg x2)) (and (@eq reg (ereg x1) (ereg x2)) (OrderedEqKind.lt (ekind x1) (ekind x2))))))) (_ : @eq bool (select_loc_l l x1) true), @eq bool (select_loc_l l x2) true *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_loc_h l x1) true), @eq bool (select_loc_h l x2) true *)
  eapply star_right. eexact A1.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor. eauto. eauto. traceEq.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  simpl. econstructor; eauto.
  apply return_regs_agree_callee_save.
(* Goal: Val.has_type_list (@nil val) (sig_args signature_main) *)
  constructor.
+ (* with an argument *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit (exec_moves mv); eauto. intros [ls1 [A1 B1]].
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  econstructor; split.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply plus_left. econstructor; eauto.
(* Goal: or (@eq bool (subtype (env (ereg q)) Tlong) true) (Loc.diff l (eloc q)) *)
(* Goal: forall (x1 x2 : equation) (_ : @eq OrderedEquation'.t x1 x2), @eq bool (subtype (env (ereg x1)) Tlong) (subtype (env (ereg x2)) Tlong) *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x1) (eloc x2)) (and (@eq loc (eloc x1) (eloc x2)) (or (Plt (ereg x1) (ereg x2)) (and (@eq reg (ereg x1) (ereg x2)) (OrderedEqKind.lt (ekind x1) (ekind x2))))))) (_ : @eq bool (select_loc_l l x1) true), @eq bool (select_loc_l l x2) true *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_loc_h l x1) true), @eq bool (select_loc_h l x2) true *)
  eapply star_right. eexact A1.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor. eauto. eauto. traceEq.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  simpl. econstructor; eauto. rewrite <- H11.
  replace (Locmap.getpair (map_rpair R (loc_result (RTL.fn_sig f)))
                          (return_regs (parent_locset ts) ls1))
  with (Locmap.getpair (map_rpair R (loc_result (RTL.fn_sig f))) ls1).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply add_equations_res_lessdef; eauto.
  rewrite H13. apply WTRS.
  generalize (loc_result_caller_save (RTL.fn_sig f)).
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  destruct (loc_result (RTL.fn_sig f)); simpl.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  intros A; rewrite A; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  intros [A B]; rewrite A, B; auto.
  apply return_regs_agree_callee_save.
  unfold proj_sig_res. rewrite <- H11; rewrite H13. apply WTRS.

(* internal function *)
- monadInv FUN. simpl in *.
(* Goal: @eq signature (funsig (@Internal function x)) (RTL.funsig (@Internal RTL.function f)) *)
(* Goal: @eq signature (funsig (@External function e)) (RTL.funsig (@External RTL.function e)) *)
  destruct (transf_function_inv _ _ EQ).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit Mem.alloc_extends; eauto. apply Z.le_refl. rewrite H8; apply Z.le_refl.
  intros [m'' [U V]].
  assert (WTRS: wt_regset env (init_regs args (fn_params f))).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  { apply wt_init_regs. inv H0. rewrite wt_params. rewrite H9. auto. }
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit (exec_moves mv). eauto. eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
    eapply can_undef_satisf; eauto. eapply compat_entry_satisf; eauto.
    rewrite call_regs_param_values. eexact ARGS.
    exact WTRS.
  intros [ls1 [A B]].
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  econstructor; split.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply plus_left. econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply star_left. econstructor; eauto.
(* Goal: or (@eq bool (subtype (env (ereg q)) Tlong) true) (Loc.diff l (eloc q)) *)
(* Goal: forall (x1 x2 : equation) (_ : @eq OrderedEquation'.t x1 x2), @eq bool (subtype (env (ereg x1)) Tlong) (subtype (env (ereg x2)) Tlong) *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x1) (eloc x2)) (and (@eq loc (eloc x1) (eloc x2)) (or (Plt (ereg x1) (ereg x2)) (and (@eq reg (ereg x1) (ereg x2)) (OrderedEqKind.lt (ekind x1) (ekind x2))))))) (_ : @eq bool (select_loc_l l x1) true), @eq bool (select_loc_l l x2) true *)
(* Goal: forall (x1 x2 : equation) (_ : or (@eq OrderedEquation'.t x1 x2) (or (OrderedLoc.lt (eloc x2) (eloc x1)) (and (@eq loc (eloc x2) (eloc x1)) (or (Plt (ereg x2) (ereg x1)) (and (@eq reg (ereg x2) (ereg x1)) (OrderedEqKind.lt (ekind x2) (ekind x1))))))) (_ : @eq bool (select_loc_h l x1) true), @eq bool (select_loc_h l x2) true *)
  eapply star_right. eexact A.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eauto. eauto. traceEq.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto.

(* external function *)
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
- exploit external_call_mem_extends; eauto. intros [v' [m'' [F [G [J K]]]]].
  simpl in FUN; inv FUN.
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  econstructor; split.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  apply plus_one. econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply external_call_symbols_preserved with (ge1 := ge); eauto. apply senv_preserved.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto.
(* Goal: external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' E0 Vundef m1' *)
  simpl. destruct (loc_result (ef_sig ef)) eqn:RES; simpl.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite Locmap.gss; auto.
  generalize (loc_result_pair (ef_sig ef)); rewrite RES; intros (A & B & C & D & E).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit external_call_well_typed; eauto. unfold proj_sig_res; rewrite B. intros WTRES'.
(* Goal: Val.lessdef (Val.hiword v) (Locmap.set (R hi) (Val.hiword v') ls (R hi)) *)
(* Goal: Val.lessdef (sel_val (ekind q) (Regmap.get val (ereg q) (Regmap.set val x v rs))) (Locmap.set (R lo) (Val.loword v') (Locmap.set (R hi) (Val.hiword v') ls) (eloc q)) *)
  rewrite Locmap.gss. rewrite Locmap.gso by (red; auto). rewrite Locmap.gss.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite val_longofwords_eq_1 by auto. auto.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  red; intros. rewrite (AG l H0).
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite locmap_get_set_loc_result_callee_save by auto.
(* Goal: satisf (init_regs vl (@cons reg r1 rl)) ls e *)
  unfold undef_caller_save_regs. destruct l; simpl in H0.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite H0; auto.
(* Goal: @eq signature (funsig tf) signature_main *)
(* Goal: match_states (RTL.Callstate (@nil RTL.stackframe) f (@nil val) m0) (Callstate (@nil stackframe) tf (Locmap.init Vundef) m0) *)
  destruct sl; auto; congruence.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply external_call_well_typed; eauto.

(* return *)
- inv STACKS.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit STEPS; eauto. rewrite WTRES0; auto. intros [ls2 [A B]].
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  econstructor; split.
(* Goal: Val.has_type_list (@nil val) (sig_args signature_main) *)
  eapply plus_left. constructor. eexact A. traceEq.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  apply wt_regset_assign; auto. rewrite WTRES0; auto.
Qed.

Lemma initial_states_simulation:
  forall st1, RTL.initial_state prog st1 ->
  exists st2, LTL.initial_state tprog st2 /\ match_states st1 st2.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. inv H.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit function_ptr_translated; eauto. intros [tf [FIND TR]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit sig_function_translated; eauto. intros SIG.
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  exists (LTL.Callstate nil tf (Locmap.init Vundef) m0); split.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor; eauto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply (Genv.init_mem_transf_partial TRANSF); eauto.
(* Goal: @eq (option block) (@Genv.find_symbol fundef unit (@Genv.globalenv fundef unit tprog) (@prog_main fundef unit tprog)) (@Some block b) *)
(* Goal: @eq signature (funsig tf) signature_main *)
(* Goal: match_states (RTL.Callstate (@nil RTL.stackframe) f (@nil val) m0) (Callstate (@nil stackframe) tf (Locmap.init Vundef) m0) *)
  rewrite symbols_preserved.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite (match_program_main TRANSF).  auto.
(* Goal: @eq signature (funsig tf) signature_main *)
(* Goal: match_states (RTL.Callstate (@nil RTL.stackframe) f (@nil val) m0) (Callstate (@nil stackframe) tf (Locmap.init Vundef) m0) *)
  congruence.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  constructor; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  constructor. rewrite SIG; rewrite H3; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite SIG, H3, loc_arguments_main. auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  red; auto.
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  apply Mem.extends_refl.
(* Goal: Val.has_type_list (@nil val) (sig_args signature_main) *)
  rewrite SIG, H3. constructor.
Qed.

Lemma final_states_simulation:
  forall st1 st2 r,
  match_states st1 st2 -> RTL.final_state st1 r -> LTL.final_state st2 r.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  intros. inv H0. inv H. inv STACKS.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor. rewrite <- (loc_result_exten sg). inv RES; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  rewrite H; auto.
Qed.

Lemma wt_prog: wt_program prog.
Proof.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
  red; intros.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit list_forall2_in_left. eexact (proj1 TRANSF). eauto.
  intros ([i' gd] & A & B & C). simpl in *; subst i'.
  inv C. destruct f; simpl in *.
- monadInv H2.
  unfold transf_function in EQ.
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls1 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
(* Goal: @eq (option fundef) (@Genv.find_funct fundef unit tge (ls2 (R r))) (@Genv.find_funct fundef unit tge (ls2 (R r))) *)
  destruct (type_function f) as [env|] eqn:TF; try discriminate.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  econstructor. eapply type_function_correct; eauto.
- constructor.
Qed.

Theorem transf_program_correct:
  forward_simulation (RTL.semantics prog) (LTL.semantics tprog).
Proof.
  set (ms := fun s s' => wt_state s /\ match_states s s').
  eapply forward_simulation_plus with (match_states := ms).
- apply senv_preserved.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
- intros. exploit initial_states_simulation; eauto. intros [st2 [A B]].
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exists st2; split; auto. split; auto.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  apply wt_initial_state with (p := prog); auto. exact wt_prog.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
- intros. destruct H. eapply final_states_simulation; eauto.
(* Goal: forall (st1 : RTL.state) (st2 : state) (r : Int.int) (_ : match_states st1 st2) (_ : RTL.final_state st1 r), final_state st2 r *)
- intros. destruct H0.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  exploit step_simulation; eauto. intros [s2' [A B]].
(* Goal: and (satisf rs ls e1) (@ex (list val) (fun vargs' : list val => @ex val (fun vres' : val => @ex Mem.mem (fun m2' : Mem.mem => and (@eval_builtin_args loc (@Genv.to_senv RTL.fundef unit ge) ls sp m1' args' vargs') (and (external_call (EF_debug kind text targs) (@Genv.to_senv RTL.fundef unit ge) vargs' m1' t vres' m2') (and (Val.lessdef vres vres') (Mem.extends m2 m2'))))))) *)
  exists s2'; split. exact A. split.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  eapply subject_reduction; eauto. eexact wt_prog. eexact H.
(* Goal: Val.lessdef_list (@nil val) (@map (rpair loc) val (fun p : rpair loc => Locmap.getpair p (Locmap.init Vundef)) (@nil (rpair loc))) *)
(* Goal: agree_callee_save (parent_locset (@nil stackframe)) (Locmap.init Vundef) *)
(* Goal: Mem.extends m0 m0 *)
(* Goal: Val.has_type_list (@nil val) (sig_args (funsig tf)) *)
  auto.
Qed.

End PRESERVATION.
