aboutsummaryrefslogtreecommitdiffstats
path: root/backend
diff options
context:
space:
mode:
authorDavid Monniaux <david.monniaux@univ-grenoble-alpes.fr>2019-12-02 19:49:30 +0100
committerDavid Monniaux <david.monniaux@univ-grenoble-alpes.fr>2019-12-02 19:49:30 +0100
commitf0c1cc8327ecf2b1e3021bce66f2d6bb0265f6c0 (patch)
tree6d5c6988ad68cfe7052dc6dac267c4de53f0202b /backend
parentbe3d241a0c2247f48dab2988f49e9c651417328b (diff)
parenteaea751c200213e0f86cf51c1fe93b7ba09c4227 (diff)
downloadcompcert-kvx-f0c1cc8327ecf2b1e3021bce66f2d6bb0265f6c0.tar.gz
compcert-kvx-f0c1cc8327ecf2b1e3021bce66f2d6bb0265f6c0.zip
Merge remote-tracking branch 'origin/mppa-work' into mppa-non-trapping-load
Diffstat (limited to 'backend')
-rw-r--r--backend/Duplicate.v198
-rw-r--r--backend/Duplicateaux.ml13
-rw-r--r--backend/Duplicateproof.v494
-rw-r--r--backend/Lineartyping.v5
4 files changed, 709 insertions, 1 deletions
diff --git a/backend/Duplicate.v b/backend/Duplicate.v
new file mode 100644
index 00000000..3ad37c83
--- /dev/null
+++ b/backend/Duplicate.v
@@ -0,0 +1,198 @@
+(** RTL node duplication using external oracle. Used to form superblock
+ structures *)
+
+Require Import AST RTL Maps Globalenvs.
+Require Import Coqlib Errors Op.
+
+Local Open Scope error_monad_scope.
+Local Open Scope positive_scope.
+
+(** External oracle returning the new RTL code (entry point unchanged),
+ along with the new entrypoint, and a mapping of new nodes to old nodes *)
+Axiom duplicate_aux: function -> code * node * (PTree.t node).
+
+Extract Constant duplicate_aux => "Duplicateaux.duplicate_aux".
+
+(** * Verification of node duplications *)
+
+Definition verify_is_copy dupmap n n' :=
+ match dupmap!n' with
+ | None => Error(msg "verify_is_copy None")
+ | Some revn => match (Pos.compare n revn) with Eq => OK tt | _ => Error(msg "verify_is_copy invalid map") end
+ end.
+
+Fixpoint verify_is_copy_list dupmap ln ln' :=
+ match ln with
+ | n::ln => match ln' with
+ | n'::ln' => do u <- verify_is_copy dupmap n n';
+ verify_is_copy_list dupmap ln ln'
+ | nil => Error (msg "verify_is_copy_list: ln' bigger than ln") end
+ | nil => match ln' with
+ | n :: ln' => Error (msg "verify_is_copy_list: ln bigger than ln'")
+ | nil => OK tt end
+ end.
+
+Definition verify_mapping_entrypoint dupmap (f f': function): res unit :=
+ verify_is_copy dupmap (fn_entrypoint f) (fn_entrypoint f').
+
+Lemma product_eq {A B: Type} :
+ (forall (a b: A), {a=b} + {a<>b}) ->
+ (forall (c d: B), {c=d} + {c<>d}) ->
+ forall (x y: A+B), {x=y} + {x<>y}.
+Proof.
+ intros H H'. intros. decide equality.
+Qed.
+
+(** FIXME Ideally i would like to put this in AST.v but i get an "illegal application"
+ * error when doing so *)
+Remark builtin_arg_eq_pos: forall (a b: builtin_arg positive), {a=b} + {a<>b}.
+Proof.
+ intros.
+ apply (builtin_arg_eq Pos.eq_dec).
+Defined.
+Global Opaque builtin_arg_eq_pos.
+
+Remark builtin_res_eq_pos: forall (a b: builtin_res positive), {a=b} + {a<>b}.
+Proof. intros. apply (builtin_res_eq Pos.eq_dec). Qed.
+Global Opaque builtin_res_eq_pos.
+
+Definition verify_match_inst dupmap inst tinst :=
+ match inst with
+ | Inop n => match tinst with Inop n' => do u <- verify_is_copy dupmap n n'; OK tt | _ => Error(msg "verify_match_inst Inop") end
+
+ | Iop op lr r n => match tinst with
+ Iop op' lr' r' n' =>
+ do u <- verify_is_copy dupmap n n';
+ if (eq_operation op op') then
+ if (list_eq_dec Pos.eq_dec lr lr') then
+ if (Pos.eq_dec r r') then
+ OK tt
+ else Error (msg "Different r in Iop")
+ else Error (msg "Different lr in Iop")
+ else Error(msg "Different operations in Iop")
+ | _ => Error(msg "verify_match_inst Inop") end
+
+ | Iload m a lr r n => match tinst with
+ | Iload m' a' lr' r' n' =>
+ do u <- verify_is_copy dupmap n n';
+ if (chunk_eq m m') then
+ if (eq_addressing a a') then
+ if (list_eq_dec Pos.eq_dec lr lr') then
+ if (Pos.eq_dec r r') then OK tt
+ else Error (msg "Different r in Iload")
+ else Error (msg "Different lr in Iload")
+ else Error (msg "Different addressing in Iload")
+ else Error (msg "Different mchunk in Iload")
+ | _ => Error (msg "verify_match_inst Iload") end
+
+ | Istore m a lr r n => match tinst with
+ | Istore m' a' lr' r' n' =>
+ do u <- verify_is_copy dupmap n n';
+ if (chunk_eq m m') then
+ if (eq_addressing a a') then
+ if (list_eq_dec Pos.eq_dec lr lr') then
+ if (Pos.eq_dec r r') then OK tt
+ else Error (msg "Different r in Istore")
+ else Error (msg "Different lr in Istore")
+ else Error (msg "Different addressing in Istore")
+ else Error (msg "Different mchunk in Istore")
+ | _ => Error (msg "verify_match_inst Istore") end
+
+ | Icall s ri lr r n => match tinst with
+ | Icall s' ri' lr' r' n' =>
+ do u <- verify_is_copy dupmap n n';
+ if (signature_eq s s') then
+ if (product_eq Pos.eq_dec ident_eq ri ri') then
+ if (list_eq_dec Pos.eq_dec lr lr') then
+ if (Pos.eq_dec r r') then OK tt
+ else Error (msg "Different r r' in Icall")
+ else Error (msg "Different lr in Icall")
+ else Error (msg "Different ri in Icall")
+ else Error (msg "Different signatures in Icall")
+ | _ => Error (msg "verify_match_inst Icall") end
+
+ | Itailcall s ri lr => match tinst with
+ | Itailcall s' ri' lr' =>
+ if (signature_eq s s') then
+ if (product_eq Pos.eq_dec ident_eq ri ri') then
+ if (list_eq_dec Pos.eq_dec lr lr') then OK tt
+ else Error (msg "Different lr in Itailcall")
+ else Error (msg "Different ri in Itailcall")
+ else Error (msg "Different signatures in Itailcall")
+ | _ => Error (msg "verify_match_inst Itailcall") end
+
+ | Ibuiltin ef lbar brr n => match tinst with
+ | Ibuiltin ef' lbar' brr' n' =>
+ do u <- verify_is_copy dupmap n n';
+ if (external_function_eq ef ef') then
+ if (list_eq_dec builtin_arg_eq_pos lbar lbar') then
+ if (builtin_res_eq_pos brr brr') then OK tt
+ else Error (msg "Different brr in Ibuiltin")
+ else Error (msg "Different lbar in Ibuiltin")
+ else Error (msg "Different ef in Ibuiltin")
+ | _ => Error (msg "verify_match_inst Ibuiltin") end
+
+ | Icond cond lr n1 n2 => match tinst with
+ | Icond cond' lr' n1' n2' =>
+ do u1 <- verify_is_copy dupmap n1 n1';
+ do u2 <- verify_is_copy dupmap n2 n2';
+ if (eq_condition cond cond') then
+ if (list_eq_dec Pos.eq_dec lr lr') then OK tt
+ else Error (msg "Different lr in Icond")
+ else Error (msg "Different cond in Icond")
+ | _ => Error (msg "verify_match_inst Icond") end
+
+ | Ijumptable r ln => match tinst with
+ | Ijumptable r' ln' =>
+ do u <- verify_is_copy_list dupmap ln ln';
+ if (Pos.eq_dec r r') then OK tt
+ else Error (msg "Different r in Ijumptable")
+ | _ => Error (msg "verify_match_inst Ijumptable") end
+
+ | Ireturn or => match tinst with
+ | Ireturn or' =>
+ if (option_eq Pos.eq_dec or or') then OK tt
+ else Error (msg "Different or in Ireturn")
+ | _ => Error (msg "verify_match_inst Ireturn") end
+ end.
+
+Definition verify_mapping_mn dupmap f f' (m: positive*positive) :=
+ let (tn, n) := m in
+ match (fn_code f)!n with
+ | None => Error (msg "verify_mapping_mn: Could not get an instruction at (fn_code f)!n")
+ | Some inst => match (fn_code f')!tn with
+ | None => Error (msg "verify_mapping_mn: Could not get an instruction at (fn_code xf)!tn")
+ | Some tinst => verify_match_inst dupmap inst tinst
+ end
+ end.
+
+Fixpoint verify_mapping_mn_rec dupmap f f' lm :=
+ match lm with
+ | nil => OK tt
+ | m :: lm => do u <- verify_mapping_mn dupmap f f' m;
+ do u2 <- verify_mapping_mn_rec dupmap f f' lm;
+ OK tt
+ end.
+
+Definition verify_mapping_match_nodes dupmap (f f': function): res unit :=
+ verify_mapping_mn_rec dupmap f f' (PTree.elements dupmap).
+
+(** Verifies that the [dupmap] of the translated function [f'] is giving correct information in regards to [f] *)
+Definition verify_mapping dupmap (f f': function) : res unit :=
+ do u <- verify_mapping_entrypoint dupmap f f';
+ do v <- verify_mapping_match_nodes dupmap f f'; OK tt.
+
+(** * Entry points *)
+
+Definition transf_function (f: function) : res function :=
+ let (tcte, dupmap) := duplicate_aux f in
+ let (tc, te) := tcte in
+ let f' := mkfunction (fn_sig f) (fn_params f) (fn_stacksize f) tc te in
+ do u <- verify_mapping dupmap f f';
+ OK f'.
+
+Definition transf_fundef (f: fundef) : res fundef :=
+ transf_partial_fundef transf_function f.
+
+Definition transf_program (p: program) : res program :=
+ transform_partial_program transf_fundef p. \ No newline at end of file
diff --git a/backend/Duplicateaux.ml b/backend/Duplicateaux.ml
new file mode 100644
index 00000000..9ff2ae55
--- /dev/null
+++ b/backend/Duplicateaux.ml
@@ -0,0 +1,13 @@
+open RTL
+open Maps
+
+let rec make_identity_ptree_rec = function
+| [] -> PTree.empty
+| m::lm -> let (n, _) = m in PTree.set n n (make_identity_ptree_rec lm)
+
+let make_identity_ptree f = make_identity_ptree_rec (PTree.elements (fn_code f))
+
+(* For now, identity function *)
+let duplicate_aux f =
+ let pTreeId = make_identity_ptree f
+ in (((fn_code f), (fn_entrypoint f)), pTreeId)
diff --git a/backend/Duplicateproof.v b/backend/Duplicateproof.v
new file mode 100644
index 00000000..39b7a353
--- /dev/null
+++ b/backend/Duplicateproof.v
@@ -0,0 +1,494 @@
+(** Correctness proof for code duplication *)
+Require Import AST Linking Errors Globalenvs Smallstep.
+Require Import Coqlib Maps Events Values.
+Require Import Op RTL Duplicate.
+
+Local Open Scope positive_scope.
+
+(** * Definition of [match_states] (independently of the translation) *)
+
+(* est-ce plus simple de prendre dupmap: node -> node, avec un noeud hors CFG à la place de None ? *)
+Inductive match_inst (dupmap: PTree.t node): instruction -> instruction -> Prop :=
+ | match_inst_nop: forall n n',
+ dupmap!n' = (Some n) -> match_inst dupmap (Inop n) (Inop n')
+ | match_inst_op: forall n n' op lr r,
+ dupmap!n' = (Some n) -> match_inst dupmap (Iop op lr r n) (Iop op lr r n')
+ | match_inst_load: forall n n' m a lr r,
+ dupmap!n' = (Some n) -> match_inst dupmap (Iload m a lr r n) (Iload m a lr r n')
+ | match_inst_store: forall n n' m a lr r,
+ dupmap!n' = (Some n) -> match_inst dupmap (Istore m a lr r n) (Istore m a lr r n')
+ | match_inst_call: forall n n' s ri lr r,
+ dupmap!n' = (Some n) -> match_inst dupmap (Icall s ri lr r n) (Icall s ri lr r n')
+ | match_inst_tailcall: forall s ri lr,
+ match_inst dupmap (Itailcall s ri lr) (Itailcall s ri lr)
+ | match_inst_builtin: forall n n' ef la br,
+ dupmap!n' = (Some n) -> match_inst dupmap (Ibuiltin ef la br n) (Ibuiltin ef la br n')
+ | match_inst_cond: forall ifso ifso' ifnot ifnot' c lr,
+ dupmap!ifso' = (Some ifso) -> dupmap!ifnot' = (Some ifnot) ->
+ match_inst dupmap (Icond c lr ifso ifnot) (Icond c lr ifso' ifnot')
+ | match_inst_jumptable: forall ln ln' r,
+ list_forall2 (fun n n' => (dupmap!n' = (Some n))) ln ln' ->
+ match_inst dupmap (Ijumptable r ln) (Ijumptable r ln')
+ | match_inst_return: forall or, match_inst dupmap (Ireturn or) (Ireturn or).
+
+Record match_function dupmap f f': Prop := {
+ dupmap_correct: forall n n', dupmap!n' = Some n ->
+ (forall i, (fn_code f)!n = Some i -> exists i', (fn_code f')!n' = Some i' /\ match_inst dupmap i i');
+ dupmap_entrypoint: dupmap!(fn_entrypoint f') = Some (fn_entrypoint f);
+ preserv_fnsig: fn_sig f = fn_sig f';
+ preserv_fnparams: fn_params f = fn_params f';
+ preserv_fnstacksize: fn_stacksize f = fn_stacksize f'
+}.
+
+Inductive match_fundef: RTL.fundef -> RTL.fundef -> Prop :=
+ | match_Internal dupmap f f': match_function dupmap f f' -> match_fundef (Internal f) (Internal f')
+ | match_External ef: match_fundef (External ef) (External ef).
+
+Inductive match_stackframes: stackframe -> stackframe -> Prop :=
+ | match_stackframe_intro
+ dupmap res f sp pc rs f' pc'
+ (TRANSF: match_function dupmap f f')
+ (DUPLIC: dupmap!pc' = Some pc):
+ match_stackframes (Stackframe res f sp pc rs) (Stackframe res f' sp pc' rs).
+
+Inductive match_states: state -> state -> Prop :=
+ | match_states_intro
+ dupmap st f sp pc rs m st' f' pc'
+ (STACKS: list_forall2 match_stackframes st st')
+ (TRANSF: match_function dupmap f f')
+ (DUPLIC: dupmap!pc' = Some pc):
+ match_states (State st f sp pc rs m) (State st' f' sp pc' rs m)
+ | match_states_call:
+ forall st st' f f' args m
+ (STACKS: list_forall2 match_stackframes st st')
+ (TRANSF: match_fundef f f'),
+ match_states (Callstate st f args m) (Callstate st' f' args m)
+ | match_states_return:
+ forall st st' v m
+ (STACKS: list_forall2 match_stackframes st st'),
+ match_states (Returnstate st v m) (Returnstate st' v m).
+
+(** * Auxiliary properties *)
+
+
+Theorem transf_function_preserves:
+ forall f f',
+ transf_function f = OK f' ->
+ fn_sig f = fn_sig f' /\ fn_params f = fn_params f' /\ fn_stacksize f = fn_stacksize f'.
+Proof.
+ intros. unfold transf_function in H. destruct (duplicate_aux _) as (tcte & mp). destruct tcte as (tc & te). monadInv H.
+ repeat (split; try reflexivity).
+Qed.
+
+
+Lemma verify_mapping_mn_rec_step:
+ forall dupmap lb b f f',
+ In b lb ->
+ verify_mapping_mn_rec dupmap f f' lb = OK tt ->
+ verify_mapping_mn dupmap f f' b = OK tt.
+Proof.
+ induction lb; intros.
+ - monadInv H0. inversion H.
+ - inversion H.
+ + subst. monadInv H0. destruct x. assumption.
+ + monadInv H0. destruct x0. eapply IHlb; assumption.
+Qed.
+
+Lemma verify_is_copy_correct:
+ forall dupmap n n',
+ verify_is_copy dupmap n n' = OK tt ->
+ dupmap ! n' = Some n.
+Proof.
+ intros. unfold verify_is_copy in H. destruct (_ ! n') eqn:REVM; [|inversion H].
+ destruct (n ?= p) eqn:NP; try (inversion H; fail).
+ eapply Pos.compare_eq in NP. subst.
+ reflexivity.
+Qed.
+
+Lemma verify_is_copy_list_correct:
+ forall dupmap ln ln',
+ verify_is_copy_list dupmap ln ln' = OK tt ->
+ list_forall2 (fun n n' => dupmap ! n' = Some n) ln ln'.
+Proof.
+ induction ln.
+ - intros. destruct ln'; monadInv H. constructor.
+ - intros. destruct ln'; monadInv H. destruct x. apply verify_is_copy_correct in EQ.
+ eapply IHln in EQ0. constructor; assumption.
+Qed.
+
+Lemma verify_match_inst_correct:
+ forall dupmap i i',
+ verify_match_inst dupmap i i' = OK tt ->
+ match_inst dupmap i i'.
+Proof.
+ intros. unfold verify_match_inst in H.
+ destruct i; try (inversion H; fail).
+(* Inop *)
+ - destruct i'; try (inversion H; fail). monadInv H.
+ destruct x. eapply verify_is_copy_correct in EQ.
+ constructor; eauto.
+(* Iop *)
+ - destruct i'; try (inversion H; fail). monadInv H.
+ destruct x. eapply verify_is_copy_correct in EQ.
+ destruct (eq_operation _ _); try discriminate.
+ destruct (list_eq_dec _ _ _); try discriminate.
+ destruct (Pos.eq_dec _ _); try discriminate. clear EQ0. subst.
+ constructor. assumption.
+(* Iload *)
+ - destruct i'; try (inversion H; fail). monadInv H.
+ destruct x. eapply verify_is_copy_correct in EQ.
+ destruct (chunk_eq _ _); try discriminate.
+ destruct (eq_addressing _ _); try discriminate.
+ destruct (list_eq_dec _ _ _); try discriminate.
+ destruct (Pos.eq_dec _ _); try discriminate. clear EQ0. subst.
+ constructor. assumption.
+(* Istore *)
+ - destruct i'; try (inversion H; fail). monadInv H.
+ destruct x. eapply verify_is_copy_correct in EQ.
+ destruct (chunk_eq _ _); try discriminate.
+ destruct (eq_addressing _ _); try discriminate.
+ destruct (list_eq_dec _ _ _); try discriminate.
+ destruct (Pos.eq_dec _ _); try discriminate. clear EQ0. subst.
+ constructor. assumption.
+(* Icall *)
+ - destruct i'; try (inversion H; fail). monadInv H.
+ destruct x. eapply verify_is_copy_correct in EQ.
+ destruct (signature_eq _ _); try discriminate.
+ destruct (product_eq _ _ _ _); try discriminate.
+ destruct (list_eq_dec _ _ _); try discriminate.
+ destruct (Pos.eq_dec _ _); try discriminate. subst.
+ constructor. assumption.
+(* Itailcall *)
+ - destruct i'; try (inversion H; fail).
+ destruct (signature_eq _ _); try discriminate.
+ destruct (product_eq _ _ _ _); try discriminate.
+ destruct (list_eq_dec _ _ _); try discriminate. subst. clear H.
+ constructor.
+(* Ibuiltin *)
+ - destruct i'; try (inversion H; fail). monadInv H.
+ destruct x. eapply verify_is_copy_correct in EQ.
+ destruct (external_function_eq _ _); try discriminate.
+ destruct (list_eq_dec _ _ _); try discriminate.
+ destruct (builtin_res_eq_pos _ _); try discriminate. subst.
+ constructor. assumption.
+(* Icond *)
+ - destruct i'; try (inversion H; fail). monadInv H.
+ destruct x. eapply verify_is_copy_correct in EQ.
+ destruct x0. eapply verify_is_copy_correct in EQ1.
+ destruct (eq_condition _ _); try discriminate.
+ destruct (list_eq_dec _ _ _); try discriminate. subst.
+ constructor; assumption.
+(* Ijumptable *)
+ - destruct i'; try (inversion H; fail). monadInv H.
+ destruct x. eapply verify_is_copy_list_correct in EQ.
+ destruct (Pos.eq_dec _ _); try discriminate. subst.
+ constructor. assumption.
+(* Ireturn *)
+ - destruct i'; try (inversion H; fail).
+ destruct (option_eq _ _ _); try discriminate. subst. clear H.
+ constructor.
+Qed.
+
+
+Lemma verify_mapping_mn_correct mp n n' i f f' tc:
+ mp ! n' = Some n ->
+ (fn_code f) ! n = Some i ->
+ (fn_code f') = tc ->
+ verify_mapping_mn mp f f' (n', n) = OK tt ->
+ exists i',
+ tc ! n' = Some i'
+ /\ match_inst mp i i'.
+Proof.
+ unfold verify_mapping_mn; intros H H0 H1 H2. rewrite H0 in H2. clear H0. rewrite H1 in H2. clear H1.
+ destruct (tc ! n') eqn:TCN; [| inversion H2].
+ exists i0. split; auto.
+ eapply verify_match_inst_correct. assumption.
+Qed.
+
+
+Lemma verify_mapping_mn_rec_correct:
+ forall mp n n' i f f' tc,
+ mp ! n' = Some n ->
+ (fn_code f) ! n = Some i ->
+ (fn_code f') = tc ->
+ verify_mapping_mn_rec mp f f' (PTree.elements mp) = OK tt ->
+ exists i',
+ tc ! n' = Some i'
+ /\ match_inst mp i i'.
+Proof.
+ intros. exploit PTree.elements_correct. eapply H. intros IN.
+ eapply verify_mapping_mn_rec_step in H2; eauto.
+ eapply verify_mapping_mn_correct; eauto.
+Qed.
+
+Theorem transf_function_correct f f':
+ transf_function f = OK f' -> exists dupmap, match_function dupmap f f'.
+Proof.
+ unfold transf_function.
+ intros TRANSF.
+ destruct (duplicate_aux _) as (tcte & mp). destruct tcte as (tc & te).
+ monadInv TRANSF.
+ unfold verify_mapping in EQ. monadInv EQ.
+ exists mp; constructor 1; simpl; auto.
+ + (* correct *)
+ intros until n'. intros REVM i FNC.
+ unfold verify_mapping_match_nodes in EQ. simpl in EQ. destruct x1.
+ eapply verify_mapping_mn_rec_correct; eauto.
+ simpl; eauto.
+ + (* entrypoint *)
+ intros. unfold verify_mapping_entrypoint in EQ0. simpl in EQ0.
+ eapply verify_is_copy_correct; eauto.
+ destruct x0; auto.
+Qed.
+
+Lemma transf_fundef_correct f f':
+ transf_fundef f = OK f' -> match_fundef f f'.
+Proof.
+ intros TRANSF; destruct f; simpl; monadInv TRANSF.
+ + exploit transf_function_correct; eauto.
+ intros (dupmap & MATCH_F).
+ eapply match_Internal; eauto.
+ + eapply match_External.
+Qed.
+
+(** * Preservation proof *)
+
+Definition match_prog (p tp: program) :=
+ match_program (fun _ f tf => transf_fundef f = OK tf) eq p tp.
+
+Lemma transf_program_match:
+ forall prog tprog, transf_program prog = OK tprog -> match_prog prog tprog.
+Proof.
+ intros. eapply match_transform_partial_program_contextual; eauto.
+Qed.
+
+Section PRESERVATION.
+
+Variable prog: program.
+Variable tprog: program.
+
+Hypothesis TRANSL: match_prog prog tprog.
+
+Let ge := Genv.globalenv prog.
+Let tge := Genv.globalenv tprog.
+
+Lemma symbols_preserved s: Genv.find_symbol tge s = Genv.find_symbol ge s.
+Proof.
+ rewrite <- (Genv.find_symbol_match TRANSL). reflexivity.
+Qed.
+
+(* UNUSED LEMMA ?
+Lemma senv_transitivity x y z: Senv.equiv x y -> Senv.equiv y z -> Senv.equiv x z.
+Proof.
+ unfold Senv.equiv. intuition congruence.
+Qed.
+*)
+
+Lemma senv_preserved:
+ Senv.equiv ge tge.
+Proof.
+ eapply (Genv.senv_match TRANSL).
+Qed.
+
+Lemma functions_translated:
+ forall (v: val) (f: fundef),
+ Genv.find_funct ge v = Some f ->
+ exists tf cunit, transf_fundef f = OK tf /\ Genv.find_funct tge v = Some tf /\ linkorder cunit prog.
+Proof.
+ intros. exploit (Genv.find_funct_match TRANSL); eauto.
+ intros (cu & tf & A & B & C).
+ repeat eexists; intuition eauto.
+ + unfold incl; auto.
+ + eapply linkorder_refl.
+Qed.
+
+Lemma function_ptr_translated:
+ forall v f,
+ Genv.find_funct_ptr ge v = Some f ->
+ exists tf,
+ Genv.find_funct_ptr tge v = Some tf /\ transf_fundef f = OK tf.
+Proof.
+ intros.
+ exploit (Genv.find_funct_ptr_transf_partial TRANSL); eauto.
+Qed.
+
+Lemma function_sig_translated:
+ forall f tf, transf_fundef f = OK tf -> funsig tf = funsig f.
+Proof.
+ intros. destruct f.
+ - simpl in H. monadInv H. simpl. symmetry. apply transf_function_preserves. assumption.
+ - simpl in H. monadInv H. reflexivity.
+Qed.
+
+Lemma list_nth_z_dupmap:
+ forall dupmap ln ln' (pc pc': node) val,
+ list_nth_z ln val = Some pc ->
+ list_forall2 (fun n n' => dupmap!n' = Some n) ln ln' ->
+ exists pc',
+ list_nth_z ln' val = Some pc'
+ /\ dupmap!pc' = Some pc.
+Proof.
+ induction ln; intros until val; intros LNZ LFA.
+ - inv LNZ.
+ - inv LNZ. destruct (zeq val 0) eqn:ZEQ.
+ + inv H0. destruct ln'; inv LFA.
+ simpl. exists p. split; auto.
+ + inv LFA. simpl. rewrite ZEQ. exploit IHln. 2: eapply H0. all: eauto.
+ intros (pc'1 & LNZ & REV). exists pc'1. split; auto. congruence.
+Qed.
+
+Theorem transf_initial_states:
+ forall s1, initial_state prog s1 ->
+ exists s2, initial_state tprog s2 /\ match_states s1 s2.
+Proof.
+ intros. inv H.
+ exploit function_ptr_translated; eauto. intros (tf & FIND & TRANSF).
+ eexists. split.
+ - econstructor; eauto.
+ + eapply (Genv.init_mem_transf_partial TRANSL); eauto.
+ + replace (prog_main tprog) with (prog_main prog). rewrite symbols_preserved. eauto.
+ symmetry. eapply match_program_main. eauto.
+ + destruct f.
+ * monadInv TRANSF. rewrite <- H3. symmetry; eapply transf_function_preserves. assumption.
+ * monadInv TRANSF. assumption.
+ - constructor; eauto.
+ + constructor.
+ + apply transf_fundef_correct; auto.
+Qed.
+
+Theorem transf_final_states:
+ forall s1 s2 r,
+ match_states s1 s2 -> final_state s1 r -> final_state s2 r.
+Proof.
+ intros. inv H0. inv H. inv STACKS. constructor.
+Qed.
+
+Theorem step_simulation:
+ forall s1 t s1', step ge s1 t s1' ->
+ forall s2 (MS: match_states s1 s2),
+ exists s2',
+ step tge s2 t s2'
+ /\ match_states s1' s2'.
+Proof.
+ Local Hint Resolve transf_fundef_correct.
+ induction 1; intros; inv MS.
+(* Inop *)
+ - eapply dupmap_correct in DUPLIC; eauto.
+ destruct DUPLIC as (i' & H2 & H3).
+ inv H3.
+ eexists. split.
+ + eapply exec_Inop; eauto.
+ + econstructor; eauto.
+(* Iop *)
+ - eapply dupmap_correct in DUPLIC; eauto.
+ destruct DUPLIC as (i' & H2 & H3). inv H3.
+ pose symbols_preserved as SYMPRES.
+ eexists. split.
+ + eapply exec_Iop; eauto. erewrite eval_operation_preserved; eauto.
+ + econstructor; eauto.
+(* Iload *)
+ - eapply dupmap_correct in DUPLIC; eauto.
+ destruct DUPLIC as (i' & H2 & H3). inv H3.
+ pose symbols_preserved as SYMPRES.
+ eexists. split.
+ + eapply exec_Iload; eauto. erewrite eval_addressing_preserved; eauto.
+ + econstructor; eauto.
+(* Istore *)
+ - eapply dupmap_correct in DUPLIC; eauto.
+ destruct DUPLIC as (i' & H2 & H3). inv H3.
+ pose symbols_preserved as SYMPRES.
+ eexists. split.
+ + eapply exec_Istore; eauto. erewrite eval_addressing_preserved; eauto.
+ + econstructor; eauto.
+(* Icall *)
+ - eapply dupmap_correct in DUPLIC; eauto.
+ destruct DUPLIC as (i' & H2 & H3). inv H3.
+ pose symbols_preserved as SYMPRES.
+ destruct ros.
+ * simpl in H0. apply functions_translated in H0.
+ destruct H0 as (tf & cunit & TFUN & GFIND & LO).
+ eexists. split.
+ + eapply exec_Icall. eassumption. simpl. eassumption.
+ apply function_sig_translated. assumption.
+ + repeat (econstructor; eauto).
+ * simpl in H0. destruct (Genv.find_symbol _ _) eqn:GFS; try discriminate.
+ apply function_ptr_translated in H0. destruct H0 as (tf & GFF & TF).
+ eexists. split.
+ + eapply exec_Icall. eassumption. simpl. rewrite symbols_preserved. rewrite GFS.
+ eassumption. apply function_sig_translated. assumption.
+ + repeat (econstructor; eauto).
+(* Itailcall *)
+ - eapply dupmap_correct in DUPLIC; eauto.
+ destruct DUPLIC as (i' & H10 & H11). inv H11.
+ pose symbols_preserved as SYMPRES.
+ destruct ros.
+ * simpl in H0. apply functions_translated in H0.
+ destruct H0 as (tf & cunit & TFUN & GFIND & LO).
+ eexists. split.
+ + eapply exec_Itailcall. eassumption. simpl. eassumption.
+ apply function_sig_translated. assumption.
+ erewrite <- preserv_fnstacksize; eauto.
+ + repeat (constructor; auto).
+ * simpl in H0. destruct (Genv.find_symbol _ _) eqn:GFS; try discriminate.
+ apply function_ptr_translated in H0. destruct H0 as (tf & GFF & TF).
+ eexists. split.
+ + eapply exec_Itailcall. eassumption. simpl. rewrite symbols_preserved. rewrite GFS.
+ eassumption. apply function_sig_translated. assumption.
+ erewrite <- preserv_fnstacksize; eauto.
+ + repeat (constructor; auto).
+(* Ibuiltin *)
+ - eapply dupmap_correct in DUPLIC; eauto.
+ destruct DUPLIC as (i' & H2 & H3). inv H3.
+ pose symbols_preserved as SYMPRES.
+ eexists. split.
+ + eapply exec_Ibuiltin; eauto. eapply eval_builtin_args_preserved; eauto.
+ eapply external_call_symbols_preserved; eauto. eapply senv_preserved.
+ + econstructor; eauto.
+(* Icond *)
+ - eapply dupmap_correct in DUPLIC; eauto.
+ destruct DUPLIC as (i' & H2 & H3). inv H3.
+ pose symbols_preserved as SYMPRES.
+ eexists. split.
+ + eapply exec_Icond; eauto.
+ + econstructor; eauto. destruct b; auto.
+(* Ijumptable *)
+ - eapply dupmap_correct in DUPLIC; eauto.
+ destruct DUPLIC as (i' & H2 & H3). inv H3.
+ pose symbols_preserved as SYMPRES.
+ exploit list_nth_z_dupmap; eauto. intros (pc'1 & LNZ & REVM).
+ eexists. split.
+ + eapply exec_Ijumptable; eauto.
+ + econstructor; eauto.
+(* Ireturn *)
+ - eapply dupmap_correct in DUPLIC; eauto.
+ destruct DUPLIC as (i' & H2 & H3). inv H3.
+ pose symbols_preserved as SYMPRES.
+ eexists. split.
+ + eapply exec_Ireturn; eauto. erewrite <- preserv_fnstacksize; eauto.
+ + econstructor; eauto.
+(* exec_function_internal *)
+ - inversion TRANSF as [dupmap f0 f0' MATCHF|]; subst. eexists. split.
+ + eapply exec_function_internal. erewrite <- preserv_fnstacksize; eauto.
+ + erewrite preserv_fnparams; eauto.
+ econstructor; eauto. apply dupmap_entrypoint. assumption.
+(* exec_function_external *)
+ - inversion TRANSF as [|]; subst. eexists. split.
+ + econstructor. eapply external_call_symbols_preserved; eauto. apply senv_preserved.
+ + constructor. assumption.
+(* exec_return *)
+ - inv STACKS. destruct b1 as [res' f' sp' pc' rs']. eexists. split.
+ + constructor.
+ + inv H1. econstructor; eauto.
+Qed.
+
+Theorem transf_program_correct:
+ forward_simulation (semantics prog) (semantics tprog).
+Proof.
+ eapply forward_simulation_step with match_states.
+ - eapply senv_preserved.
+ - eapply transf_initial_states.
+ - eapply transf_final_states.
+ - eapply step_simulation.
+Qed.
+
+End PRESERVATION.
diff --git a/backend/Lineartyping.v b/backend/Lineartyping.v
index 92c18415..994d2652 100644
--- a/backend/Lineartyping.v
+++ b/backend/Lineartyping.v
@@ -321,7 +321,10 @@ Local Opaque mreg_type.
+ (* other ops *)
destruct (type_of_operation op) as [ty_args ty_res] eqn:TYOP. InvBooleans.
econstructor; eauto.
- apply wt_setreg. eapply Val.has_subtype; eauto.
+
+ apply wt_setreg; auto; try (apply wt_undef_regs; auto).
+ eapply Val.has_subtype; eauto.
+
change ty_res with (snd (ty_args, ty_res)). rewrite <- TYOP. eapply type_of_operation_sound; eauto.
red; intros; subst op. simpl in ISMOVE.
destruct args; try discriminate. destruct args; discriminate.