aboutsummaryrefslogtreecommitdiffstats
path: root/backend
diff options
context:
space:
mode:
authorDavid Monniaux <david.monniaux@univ-grenoble-alpes.fr>2020-03-03 08:17:40 +0100
committerDavid Monniaux <david.monniaux@univ-grenoble-alpes.fr>2020-03-03 08:17:40 +0100
commit1ab7b51c30e1b10ac45b0bd64cefdc01da0f7f68 (patch)
tree210ffc156c83f04fb0c61a40b4f9037d7ba8a7e1 /backend
parent222c9047d61961db9c6b19fed5ca49829223fd33 (diff)
parent12be46d59a2483a10d77fa8ee67f7e0ca1bd702f (diff)
downloadcompcert-kvx-1ab7b51c30e1b10ac45b0bd64cefdc01da0f7f68.tar.gz
compcert-kvx-1ab7b51c30e1b10ac45b0bd64cefdc01da0f7f68.zip
Merge branch 'mppa-cse2' of gricad-gitlab.univ-grenoble-alpes.fr:sixcy/CompCert into mppa-work
Diffstat (limited to 'backend')
-rw-r--r--backend/Allnontrap.v26
-rw-r--r--backend/Allnontrapproof.v215
-rw-r--r--backend/Allocation.v18
-rw-r--r--backend/Allocproof.v115
-rw-r--r--backend/Asmaux.v5
-rw-r--r--backend/Asmexpandaux.ml4
-rw-r--r--backend/Bounds.v6
-rw-r--r--backend/CSE.v10
-rw-r--r--backend/CSE2.v6
-rw-r--r--backend/CSE2proof.v508
-rw-r--r--backend/CSEdomain.v13
-rw-r--r--backend/CSEproof.v170
-rw-r--r--backend/CleanupLabelsproof.v12
-rw-r--r--backend/Constprop.v4
-rw-r--r--backend/Constpropproof.v55
-rw-r--r--backend/Deadcode.v4
-rw-r--r--backend/Deadcodeproof.v77
-rw-r--r--backend/Debugvar.v2
-rw-r--r--backend/Debugvarproof.v16
-rw-r--r--backend/Duplicate.v203
-rw-r--r--backend/Duplicateaux.ml572
-rw-r--r--backend/Duplicateproof.v523
-rw-r--r--backend/ForwardMoves.v333
-rw-r--r--backend/ForwardMovesproof.v801
-rw-r--r--backend/IRC.ml5
-rw-r--r--backend/IRC.mli1
-rw-r--r--backend/Inlining.v4
-rw-r--r--backend/Inliningaux.ml2
-rw-r--r--backend/Inliningproof.v54
-rw-r--r--backend/Inliningspec.v6
-rw-r--r--backend/LTL.v19
-rw-r--r--backend/Linear.v23
-rw-r--r--backend/Linearize.v4
-rw-r--r--backend/Linearizeaux.ml57
-rw-r--r--backend/Linearizeproof.v48
-rw-r--r--backend/Lineartyping.v23
-rw-r--r--backend/Liveness.v2
-rw-r--r--backend/Mach.v19
-rw-r--r--backend/OpHelpers.v42
-rw-r--r--backend/OpHelpersproof.v78
-rw-r--r--backend/PrintLTL.ml7
-rw-r--r--backend/PrintMach.ml5
-rw-r--r--backend/PrintRTL.ml7
-rw-r--r--backend/PrintXTL.ml7
-rw-r--r--backend/RTL.v36
-rw-r--r--backend/RTLgen.v2
-rw-r--r--backend/RTLgenspec.v2
-rw-r--r--backend/RTLtyping.v26
-rw-r--r--backend/Regalloc.ml28
-rw-r--r--backend/Renumber.v2
-rw-r--r--backend/Renumberproof.v12
-rw-r--r--backend/SelectDiv.vp39
-rw-r--r--backend/SelectDivproof.v31
-rw-r--r--backend/Selection.v12
-rw-r--r--backend/Selectionaux.ml8
-rw-r--r--backend/Selectionproof.v29
-rw-r--r--backend/SplitLong.vp31
-rw-r--r--backend/SplitLongproof.v25
-rw-r--r--backend/Splitting.ml4
-rw-r--r--backend/Stacking.v4
-rw-r--r--backend/Stackingproof.v53
-rw-r--r--backend/Tailcallproof.v37
-rw-r--r--backend/Tunnelingproof.v25
-rw-r--r--backend/Unusedglob.v2
-rw-r--r--backend/Unusedglobproof.v32
-rw-r--r--backend/ValueAnalysis.v31
-rw-r--r--backend/XTL.ml4
-rw-r--r--backend/XTL.mli2
68 files changed, 4246 insertions, 342 deletions
diff --git a/backend/Allnontrap.v b/backend/Allnontrap.v
new file mode 100644
index 00000000..acf03eca
--- /dev/null
+++ b/backend/Allnontrap.v
@@ -0,0 +1,26 @@
+Require Import Coqlib Maps Errors Integers Floats Lattice Kildall.
+Require Import AST Linking.
+Require Import Memory Registers Op RTL.
+
+
+Definition transf_ros (ros: reg + ident) : reg + ident := ros.
+
+Definition transf_instr (pc: node) (instr: instruction) :=
+ match instr with
+ | Iload trap chunk addr args dst s => Iload NOTRAP chunk addr args dst s
+ | _ => instr
+ end.
+
+Definition transf_function (f: function) : function :=
+ {| fn_sig := f.(fn_sig);
+ fn_params := f.(fn_params);
+ fn_stacksize := f.(fn_stacksize);
+ fn_code := PTree.map transf_instr f.(fn_code);
+ fn_entrypoint := f.(fn_entrypoint) |}.
+
+Definition transf_fundef (fd: fundef) : fundef :=
+ AST.transf_fundef transf_function fd.
+
+Definition transf_program (p: program) : program :=
+ transform_program transf_fundef p.
+
diff --git a/backend/Allnontrapproof.v b/backend/Allnontrapproof.v
new file mode 100644
index 00000000..92e5a88c
--- /dev/null
+++ b/backend/Allnontrapproof.v
@@ -0,0 +1,215 @@
+Require Import FunInd.
+Require Import Coqlib Maps Errors Integers Floats Lattice Kildall.
+Require Import AST Linking.
+Require Import Values Memory Globalenvs Events Smallstep.
+Require Import Registers Op RTL.
+Require Import Allnontrap.
+
+
+Definition match_prog (p tp: RTL.program) :=
+ match_program (fun ctx f tf => tf = transf_fundef f) eq p tp.
+
+Lemma transf_program_match:
+ forall p, match_prog p (transf_program p).
+Proof.
+ intros. eapply match_transform_program; eauto.
+Qed.
+
+Section PRESERVATION.
+
+Variables prog tprog: program.
+Hypothesis TRANSL: match_prog prog tprog.
+Let ge := Genv.globalenv prog.
+Let tge := Genv.globalenv tprog.
+
+Lemma functions_translated:
+ forall v f,
+ Genv.find_funct ge v = Some f ->
+ Genv.find_funct tge v = Some (transf_fundef f).
+Proof (Genv.find_funct_transf TRANSL).
+
+Lemma function_ptr_translated:
+ forall v f,
+ Genv.find_funct_ptr ge v = Some f ->
+ Genv.find_funct_ptr tge v = Some (transf_fundef f).
+Proof (Genv.find_funct_ptr_transf TRANSL).
+
+Lemma symbols_preserved:
+ forall id,
+ Genv.find_symbol tge id = Genv.find_symbol ge id.
+Proof (Genv.find_symbol_transf TRANSL).
+
+Lemma senv_preserved:
+ Senv.equiv ge tge.
+Proof (Genv.senv_transf TRANSL).
+
+Lemma sig_preserved:
+ forall f, funsig (transf_fundef f) = funsig f.
+Proof.
+ destruct f; reflexivity.
+Qed.
+
+Lemma find_function_translated:
+ forall ros rs fd,
+ find_function ge ros rs = Some fd ->
+ find_function tge ros rs = Some (transf_fundef fd).
+Proof.
+ unfold find_function; intros. destruct ros as [r|id].
+ eapply functions_translated; eauto.
+ rewrite symbols_preserved. destruct (Genv.find_symbol ge id); try congruence.
+ eapply function_ptr_translated; eauto.
+Qed.
+
+Lemma transf_function_at:
+ forall f pc i,
+ f.(fn_code)!pc = Some i ->
+ (transf_function f).(fn_code)!pc = Some(transf_instr pc i).
+Proof.
+ intros until i. intro Hcode.
+ unfold transf_function; simpl.
+ rewrite PTree.gmap.
+ unfold option_map.
+ rewrite Hcode.
+ reflexivity.
+Qed.
+
+Ltac TR_AT :=
+ match goal with
+ | [ A: (fn_code _)!_ = Some _ |- _ ] =>
+ generalize (transf_function_at _ _ _ A); intros
+ end.
+
+
+Inductive match_frames: RTL.stackframe -> RTL.stackframe -> Prop :=
+ | match_frames_intro: forall res f sp pc rs,
+ match_frames (Stackframe res f sp pc rs)
+ (Stackframe res (transf_function f) sp pc rs).
+
+Inductive match_states: RTL.state -> RTL.state -> Prop :=
+ | match_regular_states: forall stk f sp pc rs m stk'
+ (STACKS: list_forall2 match_frames stk stk'),
+ match_states (State stk f sp pc rs m)
+ (State stk' (transf_function f) sp pc rs m)
+ | match_callstates: forall stk f args m stk'
+ (STACKS: list_forall2 match_frames stk stk'),
+ match_states (Callstate stk f args m)
+ (Callstate stk' (transf_fundef f) args m)
+ | match_returnstates: forall stk v m stk'
+ (STACKS: list_forall2 match_frames stk stk'),
+ match_states (Returnstate stk v m)
+ (Returnstate stk' v m).
+
+Lemma step_simulation:
+ forall S1 t S2, RTL.step ge S1 t S2 ->
+ forall S1', match_states S1 S1' ->
+ exists S2', RTL.step tge S1' t S2' /\ match_states S2 S2'.
+Proof.
+ induction 1; intros S1' MS; inv MS; try TR_AT.
+- (* nop *)
+ econstructor; split. eapply exec_Inop; eauto.
+ constructor; auto.
+- (* op *)
+ econstructor; split.
+ eapply exec_Iop with (v := v); eauto.
+ rewrite <- H0. apply eval_operation_preserved. exact symbols_preserved.
+ constructor; auto.
+(* load *)
+- econstructor; split.
+ assert (eval_addressing tge sp addr rs ## args = Some a).
+ rewrite <- H0. apply eval_addressing_preserved. exact symbols_preserved.
+ eapply exec_Iload; eauto.
+ constructor; auto.
+- (* load notrap1 *)
+ econstructor; split.
+ assert (eval_addressing tge sp addr rs ## args = None).
+ rewrite <- H0. apply eval_addressing_preserved. exact symbols_preserved.
+ eapply exec_Iload_notrap1; eauto.
+ constructor; auto.
+- (* load notrap2 *)
+ econstructor; split.
+ assert (eval_addressing tge sp addr rs ## args = Some a).
+ rewrite <- H0. apply eval_addressing_preserved. exact symbols_preserved.
+ eapply exec_Iload_notrap2; eauto.
+ constructor; auto.
+- (* store *)
+ econstructor; split.
+ assert (eval_addressing tge sp addr rs ## args = Some a).
+ rewrite <- H0. apply eval_addressing_preserved. exact symbols_preserved.
+ eapply exec_Istore; eauto.
+ constructor; auto.
+(* call *)
+- econstructor; split.
+ eapply exec_Icall with (fd := transf_fundef fd); eauto.
+ eapply find_function_translated; eauto.
+ apply sig_preserved.
+ constructor. constructor; auto. constructor.
+(* tailcall *)
+- econstructor; split.
+ eapply exec_Itailcall with (fd := transf_fundef fd); eauto.
+ eapply find_function_translated; eauto.
+ apply sig_preserved.
+ constructor. auto.
+(* builtin *)
+- econstructor; split.
+ eapply exec_Ibuiltin; eauto.
+ eapply eval_builtin_args_preserved with (ge1 := ge); eauto. exact symbols_preserved.
+ eapply external_call_symbols_preserved; eauto. apply senv_preserved.
+ constructor; auto.
+(* cond *)
+- econstructor; split.
+ eapply exec_Icond; eauto.
+ constructor; auto.
+(* jumptbl *)
+- econstructor; split.
+ eapply exec_Ijumptable; eauto.
+ constructor; auto.
+(* return *)
+- econstructor; split.
+ eapply exec_Ireturn; eauto.
+ constructor; auto.
+(* internal function *)
+- simpl. econstructor; split.
+ eapply exec_function_internal; eauto.
+ constructor; auto.
+(* external function *)
+- econstructor; split.
+ eapply exec_function_external; eauto.
+ eapply external_call_symbols_preserved; eauto. apply senv_preserved.
+ constructor; auto.
+(* return *)
+- inv STACKS. inv H1.
+ econstructor; split.
+ eapply exec_return; eauto.
+ constructor; auto.
+Qed.
+
+Lemma transf_initial_states:
+ forall S1, RTL.initial_state prog S1 ->
+ exists S2, RTL.initial_state tprog S2 /\ match_states S1 S2.
+Proof.
+ intros. inv H. econstructor; split.
+ econstructor.
+ eapply (Genv.init_mem_transf TRANSL); eauto.
+ rewrite symbols_preserved. rewrite (match_program_main TRANSL). eauto.
+ eapply function_ptr_translated; eauto.
+ rewrite <- H3; apply sig_preserved.
+ constructor. constructor.
+Qed.
+
+Lemma transf_final_states:
+ forall S1 S2 r, match_states S1 S2 -> RTL.final_state S1 r -> RTL.final_state S2 r.
+Proof.
+ intros. inv H0. inv H. inv STACKS. constructor.
+Qed.
+
+Theorem transf_program_correct:
+ forward_simulation (RTL.semantics prog) (RTL.semantics tprog).
+Proof.
+ eapply forward_simulation_step.
+ apply senv_preserved.
+ eexact transf_initial_states.
+ eexact transf_final_states.
+ exact step_simulation.
+Qed.
+
+End PRESERVATION.
diff --git a/backend/Allocation.v b/backend/Allocation.v
index 08e0a4f4..d18b07a9 100644
--- a/backend/Allocation.v
+++ b/backend/Allocation.v
@@ -58,7 +58,7 @@ Inductive block_shape: Type :=
(mv2: moves) (s: node)
| BSopdead (op: operation) (args: list reg) (res: reg)
(mv: moves) (s: node)
- | BSload (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
+ | BSload (trap : trapping_mode) (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
(mv1: moves) (args': list mreg) (dst': mreg)
(mv2: moves) (s: node)
| BSloaddead (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
@@ -226,15 +226,19 @@ Definition pair_instr_block
| operation_other _ _ =>
pair_Iop_block op args res s b
end
- | Iload chunk addr args dst s =>
+ | Iload trap chunk addr args dst s =>
let (mv1, b1) := extract_moves nil b in
match b1 with
- | Lload chunk' addr' args' dst' :: b2 =>
+ | Lload trap' chunk' addr' args' dst' :: b2 =>
+ assertion (trapping_mode_eq trap' trap);
if chunk_eq chunk Mint64 && Archi.splitlong then
+ (* TODO: do not support non trapping split loads *)
+ assertion (trapping_mode_eq trap TRAP);
assertion (chunk_eq chunk' Mint32);
let (mv2, b3) := extract_moves nil b2 in
match b3 with
- | Lload chunk'' addr'' args'' dst'' :: b4 =>
+ | Lload trap'' chunk'' addr'' args'' dst'' :: b4 =>
+ assertion (trapping_mode_eq trap'' TRAP);
let (mv3, b5) := extract_moves nil b4 in
assertion (chunk_eq chunk'' Mint32);
assertion (eq_addressing addr addr');
@@ -254,7 +258,7 @@ Definition pair_instr_block
assertion (chunk_eq chunk chunk');
assertion (eq_addressing addr addr');
assertion (check_succ s b3);
- Some(BSload chunk addr args dst mv1 args' dst' mv2 s))
+ Some(BSload trap chunk addr args dst mv1 args' dst' mv2 s))
| _ =>
assertion (check_succ s b1);
Some(BSloaddead chunk addr args dst mv1 s)
@@ -1023,7 +1027,7 @@ Definition transfer_aux (f: RTL.function) (env: regenv)
| BSopdead op args res mv s =>
assertion (reg_unconstrained res e);
track_moves env mv e
- | BSload chunk addr args dst mv1 args' dst' mv2 s =>
+ | BSload trap chunk addr args dst mv1 args' dst' mv2 s =>
do e1 <- track_moves env mv2 e;
do e2 <- transfer_use_def args dst args' dst' (destroyed_by_load chunk addr) e1;
track_moves env mv1 e2
@@ -1263,7 +1267,7 @@ Definition successors_block_shape (bsh: block_shape) : list node :=
| BShighlong src dst mv s => s :: nil
| BSop op args res mv1 args' res' mv2 s => s :: nil
| BSopdead op args res mv s => s :: nil
- | BSload chunk addr args dst mv1 args' dst' mv2 s => s :: nil
+ | BSload trap chunk addr args dst mv1 args' dst' mv2 s => s :: nil
| BSload2 addr addr' args dst mv1 args1' dst1' mv2 args2' dst2' mv3 s => s :: nil
| BSload2_1 addr args dst mv1 args' dst' mv2 s => s :: nil
| BSload2_2 addr addr' args dst mv1 args' dst' mv2 s => s :: nil
diff --git a/backend/Allocproof.v b/backend/Allocproof.v
index 51755912..b6880860 100644
--- a/backend/Allocproof.v
+++ b/backend/Allocproof.v
@@ -96,44 +96,44 @@ Inductive expand_block_shape: block_shape -> RTL.instruction -> LTL.bblock -> Pr
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,
+ | ebs_load: forall trap 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_block_shape (BSload trap chunk addr args dst mv1 args' dst' mv2 s)
+ (Iload trap chunk addr args dst s)
(expand_moves mv1
- (Lload chunk addr args' dst' :: expand_moves mv2 (Lbranch s :: k)))
+ (Lload trap 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)
+ (Iload TRAP Mint64 addr args dst s)
(expand_moves mv1
- (Lload Mint32 addr args1' dst1' ::
+ (Lload TRAP Mint32 addr args1' dst1' ::
expand_moves mv2
- (Lload Mint32 addr2 args2' dst2' ::
+ (Lload TRAP 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)
+ (Iload TRAP Mint64 addr args dst s)
(expand_moves mv1
- (Lload Mint32 addr args' dst' ::
+ (Lload TRAP 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)
+ (Iload TRAP Mint64 addr args dst s)
(expand_moves mv1
- (Lload Mint32 addr2 args' dst' ::
+ (Lload TRAP Mint32 addr2 args' dst' ::
expand_moves mv2 (Lbranch s :: k)))
- | ebs_load_dead: forall chunk addr args dst mv s k,
+ | ebs_load_dead: forall trap 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)
+ (Iload trap 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 ->
@@ -1970,8 +1970,8 @@ Ltac UseShape :=
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 ->
+ forall trap env f addr args dst s r,
+ wt_instr f env (Iload trap Mint64 addr args dst s) -> Archi.splitlong = true ->
In r args -> r <> dst.
Proof.
intros. inv H.
@@ -1981,7 +1981,7 @@ Proof.
{ rewrite <- H5. apply in_map; auto. }
assert (C: env r = Tint).
{ apply A in B. rewrite B. unfold Tptr. rewrite Archi.splitlong_ptr32 by auto. auto. }
- red; intros; subst r. rewrite C in H8; discriminate.
+ red; intros; subst r. rewrite C in H9; discriminate.
Qed.
(** The proof of semantic preservation is a simulation argument of the
@@ -2082,8 +2082,8 @@ Proof.
econstructor; eauto.
eapply wt_exec_Iop; eauto.
-(* load regular *)
-- generalize (wt_exec_Iload _ _ _ _ _ _ _ _ _ _ _ WTI H1 WTRS). intros WTRS'.
+(* load regular TRAP *)
+- generalize (wt_exec_Iload _ _ _ _ _ _ _ _ _ _ _ _ WTI H1 WTRS). intros WTRS'.
exploit (exec_moves mv1); eauto. intros [ls1 [A1 B1]].
exploit transfer_use_def_satisf; eauto. intros [X Y].
exploit eval_addressing_lessdef; eauto. intros [a' [F G]].
@@ -2100,7 +2100,7 @@ Proof.
econstructor; eauto.
(* load pair *)
-- generalize (wt_exec_Iload _ _ _ _ _ _ _ _ _ _ _ WTI H1 WTRS). intros WTRS'.
+- generalize (wt_exec_Iload _ _ _ _ _ _ _ _ _ _ _ _ WTI H1 WTRS). intros WTRS'.
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 *.
@@ -2155,7 +2155,7 @@ Proof.
econstructor; eauto.
(* load first word of a pair *)
-- generalize (wt_exec_Iload _ _ _ _ _ _ _ _ _ _ _ WTI H1 WTRS). intros WTRS'.
+- generalize (wt_exec_Iload _ _ _ _ _ _ _ _ _ _ _ _ WTI H1 WTRS). intros WTRS'.
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 *.
@@ -2185,7 +2185,7 @@ Proof.
econstructor; eauto.
(* load second word of a pair *)
-- generalize (wt_exec_Iload _ _ _ _ _ _ _ _ _ _ _ WTI H1 WTRS). intros WTRS'.
+- generalize (wt_exec_Iload _ _ _ _ _ _ _ _ _ _ _ _ WTI H1 WTRS). intros WTRS'.
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 *.
@@ -2229,6 +2229,79 @@ Proof.
econstructor; eauto.
eapply wt_exec_Iload; eauto.
+- (* load notrap1 *)
+ generalize (wt_exec_Iload_notrap _ _ _ _ _ _ _ _ WTI WTRS).
+ intro WTRS'.
+ exploit (exec_moves mv1); eauto. intros [ls1 [A1 B1]].
+ exploit transfer_use_def_satisf; eauto. intros [X Y].
+ exploit eval_addressing_lessdef_none; eauto. intro Haddr.
+ exploit (exec_moves mv2); eauto. intros [ls2 [A2 B2]].
+ econstructor; split.
+ eapply plus_left. econstructor; eauto.
+ eapply star_trans. eexact A1.
+ eapply star_left. eapply exec_Lload_notrap1. rewrite <- Haddr.
+ apply eval_addressing_preserved. exact symbols_preserved. eauto.
+
+ eapply star_right. eexact A2. constructor.
+ eauto. eauto. eauto. traceEq.
+ exploit satisf_successors; eauto. simpl; eauto. intros [enext [U V]].
+ econstructor; eauto.
+
+(* load notrap1 dead *)
+- exploit exec_moves; eauto. intros [ls1 [X Y]].
+ econstructor; split.
+ eapply plus_left. econstructor; eauto.
+ eapply star_right. eexact X. econstructor; eauto.
+ eauto. traceEq.
+ exploit satisf_successors. eauto. eauto. simpl; eauto. eauto.
+ eapply reg_unconstrained_satisf; eauto.
+ intros [enext [U V]].
+ econstructor; eauto.
+ eapply wt_exec_Iload_notrap; eauto.
+
+(* load regular notrap2 *)
+- generalize (wt_exec_Iload_notrap _ _ _ _ _ _ _ _ WTI WTRS).
+ intro WTRS'.
+ exploit (exec_moves mv1); eauto. intros [ls1 [A1 B1]].
+ exploit transfer_use_def_satisf; eauto. intros [X Y].
+ exploit eval_addressing_lessdef; eauto. intros [a' [F G]].
+ destruct (Mem.loadv chunk m' a') as [v' |] eqn:Hload.
+ { exploit (exec_moves mv2 env (rs # dst <- Vundef)); eauto. intros [ls2 [A2 B2]].
+ econstructor; split.
+ eapply plus_left. econstructor; eauto.
+ eapply star_trans. eexact A1.
+ eapply star_left. econstructor. instantiate (1 := a'). rewrite <- F.
+ apply eval_addressing_preserved. exact symbols_preserved. eauto. eauto.
+ eapply star_right. eexact A2. constructor.
+ eauto. eauto. eauto. traceEq.
+ exploit satisf_successors; eauto. simpl; eauto. intros [enext [U V]].
+ econstructor; eauto.
+ }
+ { exploit (exec_moves mv2 env (rs # dst <- Vundef)); eauto. intros [ls2 [A2 B2]].
+ econstructor; split.
+ eapply plus_left. econstructor; eauto.
+ eapply star_trans. eexact A1.
+ eapply star_left. eapply exec_Lload_notrap2. rewrite <- F.
+ apply eval_addressing_preserved. exact symbols_preserved. assumption.
+ eauto.
+ eapply star_right. eexact A2. constructor.
+ eauto. eauto. eauto. traceEq.
+ exploit satisf_successors; eauto. simpl; eauto. intros [enext [U V]].
+ econstructor; eauto.
+ }
+
+- (* load notrap2 dead *)
+ exploit exec_moves; eauto. intros [ls1 [X Y]].
+ econstructor; split.
+ eapply plus_left. econstructor; eauto.
+ eapply star_right. eexact X. econstructor; eauto.
+ eauto. traceEq.
+ exploit satisf_successors. eauto. eauto. simpl; eauto. eauto.
+ eapply reg_unconstrained_satisf; eauto.
+ intros [enext [U V]].
+ econstructor; eauto.
+ eapply wt_exec_Iload_notrap; eauto.
+
(* store *)
- exploit exec_moves; eauto. intros [ls1 [X Y]].
exploit add_equations_lessdef; eauto. intros LD. simpl in LD. inv LD.
diff --git a/backend/Asmaux.v b/backend/Asmaux.v
new file mode 100644
index 00000000..51e94f6b
--- /dev/null
+++ b/backend/Asmaux.v
@@ -0,0 +1,5 @@
+Require Import Asm.
+Require Import AST.
+
+(* Constant only needed by Asmexpandaux.ml *)
+Definition dummy_function := {| fn_code := nil; fn_sig := signature_main |}. \ No newline at end of file
diff --git a/backend/Asmexpandaux.ml b/backend/Asmexpandaux.ml
index 0530abe4..cc171cae 100644
--- a/backend/Asmexpandaux.ml
+++ b/backend/Asmexpandaux.ml
@@ -15,6 +15,7 @@
pseudo-instructions *)
open Asm
+open Asmaux
open AST
open Camlcoq
@@ -26,7 +27,10 @@ let emit i = current_code := i :: !current_code
(* Generation of fresh labels *)
+(* now imported from Asmaux.ml
let dummy_function = { fn_code = []; fn_sig = signature_main }
+*)
+
let current_function = ref dummy_function
let next_label = ref (None: label option)
diff --git a/backend/Bounds.v b/backend/Bounds.v
index fa695234..b8c12166 100644
--- a/backend/Bounds.v
+++ b/backend/Bounds.v
@@ -67,7 +67,7 @@ Definition instr_within_bounds (i: instruction) :=
| Lgetstack sl ofs ty r => slot_within_bounds sl ofs ty /\ mreg_within_bounds r
| Lsetstack r sl ofs ty => slot_within_bounds sl ofs ty
| Lop op args res => mreg_within_bounds res
- | Lload chunk addr args dst => mreg_within_bounds dst
+ | Lload trap chunk addr args dst => mreg_within_bounds dst
| Lcall sig ros => size_arguments sig <= bound_outgoing b
| Lbuiltin ef args res =>
(forall r, In r (params_of_builtin_res res) \/ In r (destroyed_by_builtin ef) -> mreg_within_bounds r)
@@ -104,7 +104,7 @@ Definition record_regs_of_instr (u: RegSet.t) (i: instruction) : RegSet.t :=
| Lgetstack sl ofs ty r => record_reg u r
| Lsetstack r sl ofs ty => record_reg u r
| Lop op args res => record_reg u res
- | Lload chunk addr args dst => record_reg u dst
+ | Lload trap chunk addr args dst => record_reg u dst
| Lstore chunk addr args src => u
| Lcall sig ros => u
| Ltailcall sig ros => u
@@ -280,7 +280,7 @@ Definition defined_by_instr (r': mreg) (i: instruction) :=
match i with
| Lgetstack sl ofs ty r => r' = r
| Lop op args res => r' = res
- | Lload chunk addr args dst => r' = dst
+ | Lload trap chunk addr args dst => r' = dst
| Lbuiltin ef args res => In r' (params_of_builtin_res res) \/ In r' (destroyed_by_builtin ef)
| _ => False
end.
diff --git a/backend/CSE.v b/backend/CSE.v
index ecfa1f9e..2827161d 100644
--- a/backend/CSE.v
+++ b/backend/CSE.v
@@ -459,8 +459,10 @@ Definition transfer (f: function) (approx: PMap.t VA.t) (pc: node) (before: numb
before
| Iop op args res s =>
add_op before res op args
- | Iload chunk addr args dst s =>
- add_load before dst chunk addr args
+ | Iload TRAP chunk addr args dst s =>
+ add_load before dst chunk addr args
+ | Iload NOTRAP _ _ _ dst _ =>
+ set_unknown before dst
| Istore chunk addr args src s =>
let app := approx!!pc in
let n := kill_loads_after_store app before chunk addr args in
@@ -534,14 +536,14 @@ Definition transf_instr (n: numbering) (instr: instruction) :=
let (op', args') := reduce _ combine_op n1 op args vl in
Iop op' args' res s
end
- | Iload chunk addr args dst s =>
+ | Iload TRAP chunk addr args dst s =>
let (n1, vl) := valnum_regs n args in
match find_rhs n1 (Load chunk addr vl) with
| Some r =>
Iop Omove (r :: nil) dst s
| None =>
let (addr', args') := reduce _ combine_addr n1 addr args vl in
- Iload chunk addr' args' dst s
+ Iload TRAP chunk addr' args' dst s
end
| Istore chunk addr args src s =>
let (n1, vl) := valnum_regs n args in
diff --git a/backend/CSE2.v b/backend/CSE2.v
index 19b633b0..41adba7b 100644
--- a/backend/CSE2.v
+++ b/backend/CSE2.v
@@ -465,7 +465,7 @@ Definition apply_instr instr (rel : RELATION.t) : RB.t :=
| Ijumptable _ _ => Some rel
| Istore _ _ _ _ _ => Some (kill_mem rel)
| Iop op args dst _ => Some (gen_oper op dst args rel)
- | Iload chunk addr args dst _ => Some (load chunk addr dst args rel)
+ | Iload trap chunk addr args dst _ => Some (load chunk addr dst args rel)
| Icall _ _ _ dst _ => Some (kill_reg dst (kill_mem rel))
| Ibuiltin _ _ res _ => Some (RELATION.top) (* TODO (kill_builtin_res res x) *)
| Itailcall _ _ _ | Ireturn _ => RB.bot
@@ -529,10 +529,10 @@ Definition transf_instr (fmap : option (PMap.t RB.t))
| None => Iop op args' dst s
| Some src => Iop Omove (src::nil) dst s
end
- | Iload chunk addr args dst s =>
+ | Iload trap chunk addr args dst s =>
let args' := subst_args fmap pc args in
match find_load_in_fmap fmap pc chunk addr args' with
- | None => Iload chunk addr args' dst s
+ | None => Iload trap chunk addr args' dst s
| Some src => Iop Omove (src::nil) dst s
end
| Istore chunk addr args src s =>
diff --git a/backend/CSE2proof.v b/backend/CSE2proof.v
index eb4268f0..577b1e69 100644
--- a/backend/CSE2proof.v
+++ b/backend/CSE2proof.v
@@ -561,8 +561,11 @@ Definition sem_sym_val sym rs (v : option val) : Prop :=
v = (eval_operation genv sp op (rs ## args) m)
| SLoad chunk addr args =>
match eval_addressing genv sp addr rs##args with
- | Some a => v = (Mem.loadv chunk m a)
- | None => v = None \/ v = Some Vundef
+ | Some a => match Mem.loadv chunk m a with
+ | Some dat => v = Some dat
+ | None => v = None \/ v = Some (default_notrap_load_value chunk)
+ end
+ | None => v = None \/ v = Some (default_notrap_load_value chunk)
end
end.
@@ -912,8 +915,11 @@ Lemma find_load_sound :
sem_rel rel rs ->
find_load rel chunk addr args = Some src ->
match eval_addressing genv sp addr rs##args with
- | Some a => (Mem.loadv chunk m a) = Some (rs # src)
- | None => True
+ | Some a => match Mem.loadv chunk m a with
+ | Some dat => rs#src = dat
+ | None => rs#src = default_notrap_load_value chunk
+ end
+ | None => rs#src = default_notrap_load_value chunk
end.
Proof.
intros until rs.
@@ -926,18 +932,24 @@ Proof.
| None => True
| Some src =>
match eval_addressing genv sp addr rs##args with
- | Some a => (Mem.loadv chunk m a) = Some (rs # src)
- | None => True
- end
+ | Some a => match Mem.loadv chunk m a with
+ | Some dat => rs#src = dat
+ | None => rs#src = default_notrap_load_value chunk
+ end
+ | None => rs#src = default_notrap_load_value chunk
+ end
end ->
fold_left
(fun (a : option reg) (p : positive * sym_val) =>
find_load_fold chunk addr args a (fst p) (snd p)) (PTree.elements (var_to_sym rel)) start =
Some src ->
match eval_addressing genv sp addr rs##args with
- | Some a => (Mem.loadv chunk m a) = Some (rs # src)
- | None => True
- end ) as REC.
+ | Some a => match Mem.loadv chunk m a with
+ | Some dat => rs#src = dat
+ | None => rs#src = default_notrap_load_value chunk
+ end
+ | None => rs#src = default_notrap_load_value chunk
+ end) as REC.
{
unfold sem_rel, sem_reg in REL.
@@ -978,11 +990,17 @@ Proof.
pose proof (REL r) as RELr.
rewrite RELatr in RELr.
simpl in RELr.
- destruct eval_addressing; congruence.
+ destruct eval_addressing.
+ { destruct Mem.loadv.
+ congruence.
+ destruct RELr; congruence.
+ }
+ destruct RELr; congruence.
}
apply REC; auto.
Qed.
+
Lemma find_load_sound' :
forall rel : RELATION.t,
forall chunk : memory_chunk,
@@ -991,14 +1009,61 @@ Lemma find_load_sound' :
forall args: list reg,
forall rs : regset,
forall a,
+ forall v,
sem_rel rel rs ->
find_load rel chunk addr args = Some src ->
eval_addressing genv sp addr rs##args = Some a ->
- (Mem.loadv chunk m a) = Some (rs # src).
+ Mem.loadv chunk m a = Some v ->
+ v = rs # src.
Proof.
- intros until a. intros REL LOAD ADDR.
- pose proof (find_load_sound rel chunk addr src args rs REL LOAD) as Z.
- destruct eval_addressing in *; congruence.
+ intros until v. intros REL FINDLOAD ADDR LOAD.
+ pose proof (find_load_sound rel chunk addr src args rs REL FINDLOAD) as Z.
+ destruct eval_addressing in *.
+ {
+ replace a with v0 in * by congruence.
+ destruct Mem.loadv in * ; congruence.
+ }
+ discriminate.
+Qed.
+
+Lemma find_load_notrap1_sound' :
+ forall rel : RELATION.t,
+ forall chunk : memory_chunk,
+ forall addr : addressing,
+ forall src : reg,
+ forall args: list reg,
+ forall rs : regset,
+ sem_rel rel rs ->
+ find_load rel chunk addr args = Some src ->
+ eval_addressing genv sp addr rs##args = None ->
+ rs # src = (default_notrap_load_value chunk).
+Proof.
+ intros until rs. intros REL FINDLOAD ADDR.
+ pose proof (find_load_sound rel chunk addr src args rs REL FINDLOAD) as Z.
+ rewrite ADDR in Z.
+ assumption.
+Qed.
+
+Lemma find_load_notrap2_sound' :
+ forall rel : RELATION.t,
+ forall chunk : memory_chunk,
+ forall addr : addressing,
+ forall src : reg,
+ forall args: list reg,
+ forall rs : regset,
+ forall a,
+ sem_rel rel rs ->
+ find_load rel chunk addr args = Some src ->
+ eval_addressing genv sp addr rs##args = Some a ->
+ Mem.loadv chunk m a = None ->
+ rs # src = (default_notrap_load_value chunk).
+Proof.
+ intros until a. intros REL FINDLOAD ADDR LOAD.
+ pose proof (find_load_sound rel chunk addr src args rs REL FINDLOAD) as Z.
+ rewrite ADDR in Z.
+ destruct Mem.loadv.
+ discriminate.
+ assumption.
Qed.
Lemma forward_move_map:
@@ -1100,10 +1165,87 @@ Proof.
rewrite Regmap.gss.
simpl.
rewrite args_replace_dst by auto.
- destruct eval_addressing; congruence.
+ destruct eval_addressing.
+ {
+ replace a with v0 in * by congruence.
+ destruct Mem.loadv; congruence.
+ }
+ discriminate.
}
rewrite Regmap.gso by congruence.
- unfold sem_reg.
+ unfold sem_reg. simpl.
+ rewrite PTree.gso by congruence.
+ rewrite Regmap.gso in KILL by congruence.
+ exact KILL.
+Qed.
+
+Lemma load2_notrap1_sound :
+ forall rel : RELATION.t,
+ forall chunk : memory_chunk,
+ forall addr : addressing,
+ forall dst : reg,
+ forall args: list reg,
+ forall rs : regset,
+ sem_rel rel rs ->
+ not (In dst args) ->
+ eval_addressing genv sp addr (rs ## args) = None ->
+ sem_rel (load2 chunk addr dst args rel) (rs # dst <- (default_notrap_load_value chunk)).
+Proof.
+ intros until rs.
+ intros REL NOT_IN ADDR x.
+ pose proof (kill_reg_sound rel dst rs (default_notrap_load_value chunk) REL x) as KILL.
+ unfold load2.
+ destruct (peq x dst).
+ {
+ subst x.
+ unfold sem_reg. simpl.
+ rewrite PTree.gss.
+ rewrite Regmap.gss.
+ simpl.
+ rewrite args_replace_dst by auto.
+ rewrite ADDR.
+ right.
+ trivial.
+ }
+ rewrite Regmap.gso by congruence.
+ unfold sem_reg. simpl.
+ rewrite PTree.gso by congruence.
+ rewrite Regmap.gso in KILL by congruence.
+ exact KILL.
+Qed.
+
+Lemma load2_notrap2_sound :
+ forall rel : RELATION.t,
+ forall chunk : memory_chunk,
+ forall addr : addressing,
+ forall dst : reg,
+ forall args: list reg,
+ forall rs : regset,
+ forall a,
+ sem_rel rel rs ->
+ not (In dst args) ->
+ eval_addressing genv sp addr (rs ## args) = Some a ->
+ Mem.loadv chunk m a = None ->
+ sem_rel (load2 chunk addr dst args rel) (rs # dst <- (default_notrap_load_value chunk)).
+Proof.
+ intros until a.
+ intros REL NOT_IN ADDR LOAD x.
+ pose proof (kill_reg_sound rel dst rs (default_notrap_load_value chunk) REL x) as KILL.
+ unfold load2.
+ destruct (peq x dst).
+ {
+ subst x.
+ unfold sem_reg. simpl.
+ rewrite PTree.gss.
+ rewrite Regmap.gss.
+ simpl.
+ rewrite args_replace_dst by auto.
+ rewrite ADDR.
+ rewrite LOAD.
+ right; trivial.
+ }
+ rewrite Regmap.gso by congruence.
+ unfold sem_reg. simpl.
simpl.
rewrite PTree.gso by congruence.
rewrite Regmap.gso in KILL by congruence.
@@ -1134,6 +1276,50 @@ Proof.
apply load2_sound with (a := a); auto.
Qed.
+Lemma load1_notrap1_sound :
+ forall rel : RELATION.t,
+ forall chunk : memory_chunk,
+ forall addr : addressing,
+ forall dst : reg,
+ forall args: list reg,
+ forall rs : regset,
+ sem_rel rel rs ->
+ eval_addressing genv sp addr (rs ## args) = None ->
+ sem_rel (load1 chunk addr dst args rel) (rs # dst <- (default_notrap_load_value chunk)).
+Proof.
+ intros until rs.
+ intros REL ADDR LOAD.
+ unfold load1.
+ destruct in_dec.
+ {
+ apply kill_reg_sound; auto.
+ }
+ apply load2_notrap1_sound; auto.
+Qed.
+
+Lemma load1_notrap2_sound :
+ forall rel : RELATION.t,
+ forall chunk : memory_chunk,
+ forall addr : addressing,
+ forall dst : reg,
+ forall args: list reg,
+ forall rs : regset,
+ forall a,
+ sem_rel rel rs ->
+ eval_addressing genv sp addr (rs ## args) = Some a ->
+ Mem.loadv chunk m a = None ->
+ sem_rel (load1 chunk addr dst args rel) (rs # dst <- (default_notrap_load_value chunk)).
+Proof.
+ intros until a.
+ intros REL ADDR LOAD.
+ unfold load1.
+ destruct in_dec.
+ {
+ apply kill_reg_sound; auto.
+ }
+ apply load2_notrap2_sound with (a := a); auto.
+Qed.
+
Lemma load_sound :
forall rel : RELATION.t,
forall chunk : memory_chunk,
@@ -1151,11 +1337,14 @@ Proof.
intros until v.
intros REL ADDR LOAD.
unfold load.
- destruct find_load eqn:FIND.
+ destruct find_load as [src | ] eqn:FIND.
{
- assert (match eval_addressing genv sp addr rs##(map (forward_move rel) args) with
- | Some a => (Mem.loadv chunk m a) = Some (rs # r)
- | None => True
+ assert (match eval_addressing genv sp addr rs## (map (forward_move rel) args) with
+ | Some a => match Mem.loadv chunk m a with
+ | Some dat => rs#src = dat
+ | None => rs#src = default_notrap_load_value chunk
+ end
+ | None => rs#src = default_notrap_load_value chunk
end) as FIND_LOAD.
{
apply (find_load_sound rel); trivial.
@@ -1163,12 +1352,88 @@ Proof.
rewrite forward_move_map in FIND_LOAD by assumption.
destruct eval_addressing in *.
2: discriminate.
- replace v with (rs # r) by congruence.
+ replace v0 with a in * by congruence.
+ destruct Mem.loadv in *.
+ 2: discriminate.
+ replace v with (rs # src) by congruence.
apply move_sound; auto.
}
apply load1_sound with (a := a); trivial.
Qed.
+Lemma load_notrap1_sound :
+ forall rel : RELATION.t,
+ forall chunk : memory_chunk,
+ forall addr : addressing,
+ forall dst : reg,
+ forall args: list reg,
+ forall rs : regset,
+ sem_rel rel rs ->
+ eval_addressing genv sp addr (rs ## args) = None ->
+ sem_rel (load chunk addr dst args rel) (rs # dst <- (default_notrap_load_value chunk)).
+Proof.
+ intros until rs.
+ intros REL ADDR.
+ unfold load.
+ destruct find_load as [src | ] eqn:FIND.
+ {
+ assert (match eval_addressing genv sp addr rs## (map (forward_move rel) args) with
+ | Some a => match Mem.loadv chunk m a with
+ | Some dat => rs#src = dat
+ | None => rs#src = default_notrap_load_value chunk
+ end
+ | None => rs#src = default_notrap_load_value chunk
+ end) as FIND_LOAD.
+ {
+ apply (find_load_sound rel); trivial.
+ }
+ rewrite forward_move_map in FIND_LOAD by assumption.
+ destruct eval_addressing in *.
+ discriminate.
+ rewrite <- FIND_LOAD.
+ apply move_sound; auto.
+ }
+ apply load1_notrap1_sound; trivial.
+Qed.
+
+Lemma load_notrap2_sound :
+ forall rel : RELATION.t,
+ forall chunk : memory_chunk,
+ forall addr : addressing,
+ forall dst : reg,
+ forall args: list reg,
+ forall rs : regset,
+ forall a,
+ sem_rel rel rs ->
+ eval_addressing genv sp addr (rs ## args) = Some a ->
+ Mem.loadv chunk m a = None ->
+ sem_rel (load chunk addr dst args rel) (rs # dst <- (default_notrap_load_value chunk)).
+Proof.
+ intros until a.
+ intros REL ADDR.
+ unfold load.
+ destruct find_load as [src | ] eqn:FIND.
+ {
+ assert (match eval_addressing genv sp addr rs## (map (forward_move rel) args) with
+ | Some a => match Mem.loadv chunk m a with
+ | Some dat => rs#src = dat
+ | None => rs#src = default_notrap_load_value chunk
+ end
+ | None => rs#src = default_notrap_load_value chunk
+ end) as FIND_LOAD.
+ {
+ apply (find_load_sound rel); trivial.
+ }
+ rewrite forward_move_map in FIND_LOAD by assumption.
+ rewrite ADDR in FIND_LOAD.
+ destruct Mem.loadv; intro.
+ discriminate.
+ rewrite <- FIND_LOAD.
+ apply move_sound; auto.
+ }
+ apply load1_notrap2_sound; trivial.
+Qed.
+
Lemma kill_reg_weaken:
forall res mpc rs,
sem_rel mpc rs ->
@@ -1536,7 +1801,9 @@ Proof.
simpl.
rewrite <- subst_args_ok with (genv := ge) (f := f) (pc := pc) (sp := sp) (m := m) in H0.
{
- rewrite find_load_sound' with (genv := ge) (sp := sp) (addr := addr) (args := subst_args (Some map) pc args) (rel := mpc) (src := r) (rs := rs) in H1; trivial.
+ f_equal.
+ symmetry.
+ apply find_load_sound' with (chunk := chunk) (m := m) (a := a) (genv := ge) (sp := sp) (addr := addr) (args := subst_args (Some map) pc args) (rel := mpc) (src := r) (rs := rs); trivial.
rewrite MAP in H0.
assumption.
}
@@ -1563,79 +1830,164 @@ Proof.
apply load_sound with (a := a); auto.
}
{
- econstructor; split.
- assert (eval_addressing tge sp addr rs ## args = Some a).
- rewrite <- H0.
- apply eval_addressing_preserved. exact symbols_preserved.
- eapply exec_Iload; eauto.
- rewrite (subst_args_ok' sp m); assumption.
- constructor; auto.
-
- simpl in *.
- unfold fmap_sem', fmap_sem in *.
- destruct (forward_map _) as [map |] eqn:MAP in *; trivial.
- destruct (map # pc) as [mpc |] eqn:MPC in *; try contradiction.
- apply sem_rel_b_ge with (rb2 := Some (load chunk addr dst args mpc)).
- {
- replace (Some (load chunk addr dst args mpc)) with (apply_instr' (fn_code f) pc (map # pc)).
+ econstructor; split.
+ assert (eval_addressing tge sp addr rs ## args = Some a).
+ rewrite <- H0.
+ apply eval_addressing_preserved. exact symbols_preserved.
+ eapply exec_Iload; eauto.
+ rewrite (subst_args_ok' sp m); assumption.
+ constructor; auto.
+
+ simpl in *.
+ unfold fmap_sem', fmap_sem in *.
+ destruct (forward_map _) as [map |] eqn:MAP in *; trivial.
+ destruct (map # pc) as [mpc |] eqn:MPC in *; try contradiction.
+ apply sem_rel_b_ge with (rb2 := Some (load chunk addr dst args mpc)).
{
- eapply DS.fixpoint_solution with (code := fn_code f) (successors := successors_instr); try eassumption.
- 2: apply apply_instr'_bot.
- simpl. tauto.
+ replace (Some (load chunk addr dst args mpc)) with (apply_instr' (fn_code f) pc (map # pc)).
+ {
+ eapply DS.fixpoint_solution with (code := fn_code f) (successors := successors_instr); try eassumption.
+ 2: apply apply_instr'_bot.
+ simpl. tauto.
+ }
+ unfold apply_instr'.
+ rewrite H.
+ rewrite MPC.
+ simpl.
+ reflexivity.
}
- unfold apply_instr'.
- rewrite H.
- rewrite MPC.
- simpl.
- reflexivity.
- }
- apply load_sound with (a := a); assumption.
+ apply load_sound with (a := a); assumption.
}
- (* NOT IN THIS VERSION
-- (* load notrap1 *)
- econstructor; split.
- assert (eval_addressing tge sp addr rs ## args = None).
- rewrite <- H0. apply eval_addressing_preserved. exact symbols_preserved.
- eapply exec_Iload_notrap1; eauto.
- rewrite subst_args_ok; assumption.
- constructor; auto.
+- unfold transf_instr in *.
+ destruct find_load_in_fmap eqn:FIND_LOAD.
+ {
+ unfold find_load_in_fmap, fmap_sem', fmap_sem in *.
+ destruct (forward_map f) as [map |] eqn:MAP.
+ 2: discriminate.
+ change (@PMap.get (option RELATION.t) pc map) with (map # pc) in *.
+ destruct (map # pc) as [mpc | ] eqn:MPC.
+ 2: discriminate.
- simpl in *.
- unfold fmap_sem in *.
- destruct (forward_map _) as [map |] eqn:MAP in *; trivial.
- destruct (map # pc) as [mpc |] eqn:MPC in *; try contradiction.
- apply sem_rel_b_ge with (rb2 := Some (kill dst mpc)).
+ econstructor; split.
+ {
+ eapply exec_Iop with (v := (default_notrap_load_value chunk)); eauto.
+ rewrite <- subst_args_ok with (genv := ge) (f := f) (pc := pc) (sp := sp) (m := m) in H0.
+ { simpl.
+ f_equal.
+ apply find_load_notrap1_sound' with (chunk := chunk) (m := m) (genv := ge) (sp := sp) (addr := addr) (args := subst_args (Some map) pc args) (rel := mpc) (src := r) (rs := rs); trivial.
+ rewrite MAP in H0.
+ assumption.
+ }
+ unfold fmap_sem. rewrite MAP. rewrite MPC. assumption.
+ }
+ constructor; eauto.
+ unfold fmap_sem', fmap_sem in *.
+ rewrite MAP.
+ apply sem_rel_b_ge with (rb2 := Some (load chunk addr dst args mpc)).
+ {
+ replace (Some (load chunk addr dst args mpc)) with (apply_instr' (fn_code f) pc (map # pc)).
+ {
+ eapply DS.fixpoint_solution with (code := fn_code f) (successors := successors_instr); try eassumption.
+ 2: apply apply_instr'_bot.
+ simpl. tauto.
+ }
+ unfold apply_instr'.
+ rewrite H.
+ rewrite MPC.
+ simpl.
+ reflexivity.
+ }
+ unfold sem_rel_b', sem_rel_b.
+ apply load_notrap1_sound; auto.
+ }
{
- replace (Some (kill dst mpc)) with (apply_instr' (fn_code f) pc (map # pc)).
+ econstructor; split.
+ assert (eval_addressing tge sp addr rs ## args = None).
+ rewrite <- H0. apply eval_addressing_preserved. exact symbols_preserved.
+ eapply exec_Iload_notrap1; eauto.
+ rewrite subst_args_ok with (genv := ge) (sp := sp) (m := m) ; assumption.
+ constructor; auto.
+
+ simpl in *.
+ unfold fmap_sem', fmap_sem in *.
+ destruct (forward_map _) as [map |] eqn:MAP in *; trivial.
+ destruct (map # pc) as [mpc |] eqn:MPC in *; try contradiction.
+ apply sem_rel_b_ge with (rb2 := Some (load chunk addr dst args mpc)).
{
- eapply DS.fixpoint_solution with (code := fn_code f) (successors := successors_instr); try eassumption.
- 2: apply apply_instr'_bot.
- simpl. tauto.
+ replace (Some (load chunk addr dst args mpc)) with (apply_instr' (fn_code f) pc (map # pc)).
+ {
+ eapply DS.fixpoint_solution with (code := fn_code f) (successors := successors_instr); try eassumption.
+ 2: apply apply_instr'_bot.
+ simpl. tauto.
+ }
+ unfold apply_instr'.
+ rewrite H.
+ rewrite MPC.
+ simpl.
+ reflexivity.
}
- unfold apply_instr'.
- rewrite H.
- rewrite MPC.
- reflexivity.
+ apply load_notrap1_sound; trivial.
}
- apply kill_ok.
- assumption.
- (* load notrap2 *)
+ unfold transf_instr in *.
+ destruct find_load_in_fmap eqn:FIND_LOAD.
+ {
+ unfold find_load_in_fmap, fmap_sem', fmap_sem in *.
+ destruct (forward_map f) as [map |] eqn:MAP.
+ 2: discriminate.
+ change (@PMap.get (option RELATION.t) pc map) with (map # pc) in *.
+ destruct (map # pc) as [mpc | ] eqn:MPC.
+ 2: discriminate.
+ econstructor; split.
+ {
+ eapply exec_Iop with (v := (default_notrap_load_value chunk)); eauto.
+ simpl.
+ rewrite <- subst_args_ok with (genv := ge) (f := f) (pc := pc) (sp := sp) (m := m) in H0.
+ {
+ f_equal.
+ apply find_load_notrap2_sound' with (chunk := chunk) (m := m) (a := a) (genv := ge) (sp := sp) (addr := addr) (args := subst_args (Some map) pc args) (rel := mpc) (src := r) (rs := rs); trivial.
+ rewrite MAP in H0.
+ assumption.
+ }
+ unfold fmap_sem. rewrite MAP. rewrite MPC. assumption.
+ }
+ constructor; eauto.
+ unfold fmap_sem', fmap_sem in *.
+ rewrite MAP.
+ apply sem_rel_b_ge with (rb2 := Some (load chunk addr dst args mpc)).
+ {
+ replace (Some (load chunk addr dst args mpc)) with (apply_instr' (fn_code f) pc (map # pc)).
+ {
+ eapply DS.fixpoint_solution with (code := fn_code f) (successors := successors_instr); try eassumption.
+ 2: apply apply_instr'_bot.
+ simpl. tauto.
+ }
+ unfold apply_instr'.
+ rewrite H.
+ rewrite MPC.
+ simpl.
+ reflexivity.
+ }
+ unfold sem_rel_b', sem_rel_b.
+ apply load_notrap2_sound with (a := a); auto.
+ }
+ {
econstructor; split.
assert (eval_addressing tge sp addr rs ## args = Some a).
rewrite <- H0. apply eval_addressing_preserved. exact symbols_preserved.
eapply exec_Iload_notrap2; eauto.
- rewrite subst_args_ok; assumption.
+ rewrite subst_args_ok with (genv := ge) (sp := sp) (m := m); assumption.
constructor; auto.
simpl in *.
- unfold fmap_sem in *.
+ unfold fmap_sem', fmap_sem in *.
destruct (forward_map _) as [map |] eqn:MAP in *; trivial.
destruct (map # pc) as [mpc |] eqn:MPC in *; try contradiction.
- apply sem_rel_b_ge with (rb2 := Some (kill dst mpc)).
+ apply sem_rel_b_ge with (rb2 := Some (load chunk addr dst args mpc)).
{
- replace (Some (kill dst mpc)) with (apply_instr' (fn_code f) pc (map # pc)).
+ replace (Some (load chunk addr dst args mpc)) with (apply_instr' (fn_code f) pc (map # pc)).
{
eapply DS.fixpoint_solution with (code := fn_code f) (successors := successors_instr); try eassumption.
2: apply apply_instr'_bot.
@@ -1644,11 +1996,11 @@ Proof.
unfold apply_instr'.
rewrite H.
rewrite MPC.
+ simpl.
reflexivity.
}
- apply kill_ok.
- assumption.
- *)
+ apply load_notrap2_sound with (a := a); assumption.
+ }
- (* store *)
econstructor. split.
diff --git a/backend/CSEdomain.v b/backend/CSEdomain.v
index 9b1243c8..34ec0118 100644
--- a/backend/CSEdomain.v
+++ b/backend/CSEdomain.v
@@ -43,7 +43,7 @@ Definition eq_list_valnum: forall (x y: list valnum), {x=y}+{x<>y} := list_eq_de
Definition eq_rhs (x y: rhs) : {x=y}+{x<>y}.
Proof.
- generalize chunk_eq eq_operation eq_addressing eq_valnum eq_list_valnum.
+ generalize trapping_mode_eq chunk_eq eq_operation eq_addressing eq_valnum eq_list_valnum.
decide equality.
Defined.
@@ -109,7 +109,16 @@ Inductive rhs_eval_to (valu: valuation) (ge: genv) (sp: val) (m: mem):
| load_eval_to: forall chunk addr vl a v,
eval_addressing ge sp addr (map valu vl) = Some a ->
Mem.loadv chunk m a = Some v ->
- rhs_eval_to valu ge sp m (Load chunk addr vl) v.
+ rhs_eval_to valu ge sp m (Load chunk addr vl) v
+(* | load_notrap1_eval_to: forall chunk addr vl,
+ eval_addressing ge sp addr (map valu vl) = None ->
+ rhs_eval_to valu ge sp m (Load NOTRAP chunk addr vl)
+ (default_notrap_load_value chunk)
+ | load_notrap2_eval_to: forall chunk addr vl a,
+ eval_addressing ge sp addr (map valu vl) = Some a ->
+ Mem.loadv chunk m a = None ->
+ rhs_eval_to valu ge sp m (Load NOTRAP chunk addr vl)
+ (default_notrap_load_value chunk) *).
Inductive equation_holds (valu: valuation) (ge: genv) (sp: val) (m: mem):
equation -> Prop :=
diff --git a/backend/CSEproof.v b/backend/CSEproof.v
index 03c7ecfc..5bbb7508 100644
--- a/backend/CSEproof.v
+++ b/backend/CSEproof.v
@@ -71,7 +71,11 @@ Lemma rhs_eval_to_exten:
Proof.
intros. inv H; simpl in *.
- constructor. rewrite valnums_val_exten by assumption. auto.
-- econstructor; eauto. rewrite valnums_val_exten by assumption. auto.
+- eapply load_eval_to; eauto. rewrite valnums_val_exten by assumption. auto.
+(*
+- apply load_notrap1_eval_to; auto. rewrite valnums_val_exten by assumption. assumption.
+- eapply load_notrap2_eval_to; eauto. rewrite valnums_val_exten by assumption. assumption.
+*)
Qed.
Lemma equation_holds_exten:
@@ -393,6 +397,39 @@ Proof.
+ intros. apply Regmap.gso; auto.
Qed.
+(*
+Lemma add_load_holds_none1:
+ forall valu1 ge sp rs m n addr (args: list reg) chunk dst,
+ numbering_holds valu1 ge sp rs m n ->
+ eval_addressing ge sp addr rs##args = None ->
+ exists valu2, numbering_holds valu2 ge sp (rs#dst <- (default_notrap_load_value chunk)) m (add_load n dst chunk addr args).
+Proof.
+ unfold add_load; intros.
+ destruct (valnum_regs n args) as [n1 vl] eqn:VN.
+ exploit valnum_regs_holds; eauto.
+ intros (valu2 & A & B & C & D & E).
+ eapply add_rhs_holds; eauto.
++ rewrite Regmap.gss; auto. eapply load_notrap1_eval_to. rewrite <- B; eauto.
++ intros. apply Regmap.gso; auto.
+Qed.
+
+Lemma add_load_holds_none2:
+ forall valu1 ge sp rs m n addr (args: list reg) a chunk dst,
+ numbering_holds valu1 ge sp rs m n ->
+ eval_addressing ge sp addr rs##args = Some a ->
+ Mem.loadv chunk m a = None ->
+ exists valu2, numbering_holds valu2 ge sp (rs#dst <- (default_notrap_load_value chunk)) m (add_load n dst NOTRAP chunk addr args).
+Proof.
+ unfold add_load; intros.
+ destruct (valnum_regs n args) as [n1 vl] eqn:VN.
+ exploit valnum_regs_holds; eauto.
+ intros (valu2 & A & B & C & D & E).
+ eapply add_rhs_holds; eauto.
++ rewrite Regmap.gss; auto. eapply load_notrap2_eval_to. rewrite <- B; eauto. assumption.
++ intros. apply Regmap.gso; auto.
+Qed.
+ *)
+
Lemma set_unknown_holds:
forall valu ge sp rs m n r v,
numbering_holds valu ge sp rs m n ->
@@ -456,8 +493,8 @@ Lemma kill_all_loads_hold:
Proof.
intros. eapply kill_equations_hold; eauto.
unfold filter_loads; intros. inv H1.
- constructor. rewrite <- H2. apply op_depends_on_memory_correct; auto.
- discriminate.
+ 1: constructor; rewrite <- H2; apply op_depends_on_memory_correct; auto.
+ all: discriminate.
Qed.
Lemma kill_loads_after_store_holds:
@@ -486,6 +523,20 @@ Proof.
apply match_aptr_of_aval. eapply eval_static_addressing_sound; eauto.
erewrite <- regs_valnums_sound by eauto. eauto with va.
apply match_aptr_of_aval. eapply eval_static_addressing_sound; eauto with va.
+(*
+- eapply load_notrap1_eval_to; assumption.
+- destruct (regs_valnums n vl) as [rl|] eqn:RV; try discriminate.
+ eapply load_notrap2_eval_to; eauto.
+ rewrite <- H9.
+ destruct a; simpl in H1; try discriminate.
+ destruct a0; simpl in H9; try discriminate; simpl; trivial.
+ rewrite negb_false_iff in H6. unfold aaddressing in H6.
+ eapply Mem.load_store_other. eauto.
+ eapply pdisjoint_sound; eauto.
+ apply match_aptr_of_aval. eapply eval_static_addressing_sound; eauto.
+ erewrite <- regs_valnums_sound by eauto. eauto with va.
+ apply match_aptr_of_aval. eapply eval_static_addressing_sound; eauto with va.
+*)
Qed.
Lemma store_normalized_range_sound:
@@ -562,6 +613,19 @@ Proof.
unfold aaddressing. apply match_aptr_of_aval. eapply eval_static_addressing_sound; eauto.
erewrite <- regs_valnums_sound by eauto. eauto with va.
auto.
+(*
+- eapply load_notrap1_eval_to; assumption.
+- destruct (regs_valnums n vl) as [rl|] eqn:RV; try discriminate.
+ eapply load_notrap2_eval_to; eauto. rewrite <- H11.
+ destruct a; simpl in H10; try discriminate; simpl; trivial.
+ rewrite negb_false_iff in H8.
+ eapply Mem.load_storebytes_other. eauto.
+ rewrite H6. rewrite Z2Nat.id by omega.
+ eapply pdisjoint_sound. eauto.
+ unfold aaddressing. apply match_aptr_of_aval. eapply eval_static_addressing_sound; eauto.
+ erewrite <- regs_valnums_sound by eauto. eauto with va.
+ auto.
+*)
Qed.
Lemma load_memcpy:
@@ -1034,6 +1098,10 @@ Proof.
destruct (valnum_regs approx!!pc args) as [n1 vl] eqn:?.
destruct SAT as [valu1 NH1].
exploit valnum_regs_holds; eauto. intros (valu2 & NH2 & EQ & AG & P & Q).
+ destruct trap.
+
+ (* TRAP *)
+ {
destruct (find_rhs n1 (Load chunk addr vl)) as [r|] eqn:?.
+ (* replaced by move *)
exploit find_rhs_sound; eauto. intros (v' & EV & LD).
@@ -1063,7 +1131,103 @@ Proof.
unfold transfer; rewrite H.
eapply add_load_holds; eauto.
apply set_reg_lessdef; auto.
+ }
+
+ (* NOTRAP *)
+ {
+ assert (exists a' : val,
+ eval_addressing ge sp addr rs' ## args = Some a' /\ Val.lessdef a a')
+ as Haa'.
+ apply eval_addressing_lessdef with (vl1 := rs ## args).
+ apply regs_lessdef_regs; assumption.
+ assumption.
+ destruct Haa' as [a' [Ha'1 Ha'2]].
+
+ assert (
+ exists v' : val,
+ Mem.loadv chunk m' a' = Some v' /\ Val.lessdef v v') as Hload' by
+ (apply Mem.loadv_extends with (m1 := m) (addr1 := a); assumption).
+ destruct Hload' as [v' [Hv'1 Hv'2]].
+
+ econstructor. split.
+ eapply exec_Iload; eauto.
+ try (rewrite eval_addressing_preserved with (ge1 := ge); auto; exact symbols_preserved).
+
+ econstructor; eauto.
+ eapply analysis_correct_1; eauto. simpl; eauto.
+ unfold transfer. rewrite H.
+ exists valu1.
+ apply set_unknown_holds.
+ assumption.
+ apply set_reg_lessdef; assumption.
+ }
+
+- (* Iload notrap 1*)
+ destruct (valnum_regs approx!!pc args) as [n1 vl] eqn:?.
+ destruct SAT as [valu1 NH1].
+ exploit valnum_regs_holds; eauto. intros (valu2 & NH2 & EQ & AG & P & Q).
+
+ econstructor. split.
+ eapply exec_Iload_notrap1; eauto.
+ rewrite eval_addressing_preserved with (ge1 := ge).
+ apply eval_addressing_lessdef_none with (vl1 := rs ## args).
+ apply regs_lessdef_regs; assumption.
+ assumption.
+ exact symbols_preserved.
+
+ econstructor; eauto.
+ eapply analysis_correct_1; eauto. simpl; eauto.
+ unfold transfer. rewrite H.
+ exists valu1.
+ apply set_unknown_holds.
+ assumption.
+ apply set_reg_lessdef.
+ constructor. assumption.
+
+- (* Iload notrap 2*)
+ destruct (valnum_regs approx!!pc args) as [n1 vl] eqn:?.
+ destruct SAT as [valu1 NH1].
+ exploit valnum_regs_holds; eauto. intros (valu2 & NH2 & EQ & AG & P & Q).
+ assert (exists a' : val,
+ eval_addressing ge sp addr rs' ## args = Some a' /\ Val.lessdef a a')
+ as Haa'.
+ apply eval_addressing_lessdef with (vl1 := rs ## args).
+ apply regs_lessdef_regs; assumption.
+ assumption.
+ destruct Haa' as [a' [Ha'1 Ha'2]].
+
+ destruct (Mem.loadv chunk m' a') eqn:Hload'.
+
+ {
+ econstructor. split.
+ eapply exec_Iload; eauto.
+ try (rewrite eval_addressing_preserved with (ge1 := ge); auto; exact symbols_preserved).
+
+ econstructor; eauto.
+ eapply analysis_correct_1; eauto. simpl; eauto.
+ unfold transfer. rewrite H.
+ exists valu1.
+ apply set_unknown_holds.
+ assumption.
+ unfold default_notrap_load_value.
+ apply set_reg_lessdef; eauto.
+ }
+ {
+ econstructor. split.
+ eapply exec_Iload_notrap2; eauto.
+ try (rewrite eval_addressing_preserved with (ge1 := ge); auto; exact symbols_preserved).
+
+ econstructor; eauto.
+ eapply analysis_correct_1; eauto. simpl; eauto.
+ unfold transfer. rewrite H.
+ exists valu1.
+ apply set_unknown_holds.
+ assumption.
+ apply set_reg_lessdef.
+ constructor. assumption.
+ }
+
- (* Istore *)
destruct (valnum_regs approx!!pc args) as [n1 vl] eqn:?.
destruct SAT as [valu1 NH1].
diff --git a/backend/CleanupLabelsproof.v b/backend/CleanupLabelsproof.v
index e92be2b4..84ca403e 100644
--- a/backend/CleanupLabelsproof.v
+++ b/backend/CleanupLabelsproof.v
@@ -255,6 +255,18 @@ Proof.
left; econstructor; split.
econstructor; eauto.
econstructor; eauto with coqlib.
+(* Lload notrap1 *)
+ assert (eval_addressing tge sp addr (LTL.reglist rs args) = None).
+ rewrite <- H. apply eval_addressing_preserved. exact symbols_preserved.
+ left; econstructor; split.
+ eapply exec_Lload_notrap1; eauto.
+ econstructor; eauto with coqlib.
+(* Lload notrap2 *)
+ assert (eval_addressing tge sp addr (LTL.reglist rs args) = Some a).
+ rewrite <- H. apply eval_addressing_preserved. exact symbols_preserved.
+ left; econstructor; split.
+ eapply exec_Lload_notrap2; eauto.
+ econstructor; eauto with coqlib.
(* Lstore *)
assert (eval_addressing tge sp addr (LTL.reglist rs args) = Some a).
rewrite <- H. apply eval_addressing_preserved. exact symbols_preserved.
diff --git a/backend/Constprop.v b/backend/Constprop.v
index 4aab7677..eda41b39 100644
--- a/backend/Constprop.v
+++ b/backend/Constprop.v
@@ -181,7 +181,7 @@ Definition transf_instr (f: function) (an: PMap.t VA.t) (rm: romem)
let (op', args') := op_strength_reduction op args aargs in
Iop op' args' res s'
end
- | Iload chunk addr args dst s =>
+ | Iload TRAP chunk addr args dst s =>
let aargs := aregs ae args in
let a := ValueDomain.loadv chunk rm am (eval_static_addressing addr aargs) in
match const_for_result a with
@@ -189,7 +189,7 @@ Definition transf_instr (f: function) (an: PMap.t VA.t) (rm: romem)
Iop cop nil dst s
| None =>
let (addr', args') := addr_strength_reduction addr args aargs in
- Iload chunk addr' args' dst s
+ Iload TRAP chunk addr' args' dst s
end
| Istore chunk addr args src s =>
let aargs := aregs ae args in
diff --git a/backend/Constpropproof.v b/backend/Constpropproof.v
index a5d08a0f..63cfee24 100644
--- a/backend/Constpropproof.v
+++ b/backend/Constpropproof.v
@@ -406,6 +406,8 @@ Proof.
assert (VM1: vmatch bc a aa) by (eapply eval_static_addressing_sound; eauto with va).
set (av := loadv chunk (romem_for cu) am aa).
assert (VM2: vmatch bc v av) by (eapply loadv_sound; eauto).
+ destruct trap.
+ {
destruct (const_for_result av) as [cop|] eqn:?; intros.
+ (* constant-propagated *)
exploit const_for_result_correct; eauto. intros (v' & A & B).
@@ -431,6 +433,59 @@ Proof.
left; econstructor; econstructor; split.
eapply exec_Iload; eauto.
eapply match_states_succ; eauto. apply set_reg_lessdef; auto.
+ }
+ {
+ assert (exists v2 : val,
+ eval_addressing ge (Vptr sp0 Ptrofs.zero) addr (rs' ## args) = Some v2 /\ Val.lessdef a v2) as Hexist2.
+ apply eval_addressing_lessdef with (vl1 := rs ## args).
+ apply regs_lessdef_regs; assumption.
+ assumption.
+ destruct Hexist2 as [v2 [Heval2 Hlessdef2]].
+ destruct (Mem.loadv_extends chunk m m' a v2 v MEM H1 Hlessdef2) as [vX [Hvx1 Hvx2]].
+ left; econstructor; econstructor; split.
+ eapply exec_Iload with (a := v2); eauto.
+ try (erewrite eval_addressing_preserved with (ge1:=ge); auto;
+ exact symbols_preserved).
+ eapply match_states_succ; eauto. apply set_reg_lessdef; auto.
+
+ }
+
+- (* Iload notrap1 *)
+ rename pc'0 into pc. TransfInstr.
+ assert (eval_addressing tge (Vptr sp0 Ptrofs.zero) addr (rs' ## args) = None).
+ rewrite eval_addressing_preserved with (ge1 := ge); eauto.
+ apply eval_addressing_lessdef_none with (vl1 := rs ## args).
+ apply regs_lessdef_regs; assumption.
+ assumption.
+ exact symbols_preserved.
+
+ left; econstructor; econstructor; split.
+ eapply exec_Iload_notrap1; eauto.
+ eapply match_states_succ; eauto. apply set_reg_lessdef; auto.
+
+- (* Iload notrap2 *)
+ rename pc'0 into pc. TransfInstr.
+ assert (exists v2 : val,
+ eval_addressing ge (Vptr sp0 Ptrofs.zero) addr (rs' ## args) = Some v2 /\ Val.lessdef a v2) as Hexist2.
+ apply eval_addressing_lessdef with (vl1 := rs ## args).
+ apply regs_lessdef_regs; assumption.
+ assumption.
+ destruct Hexist2 as [a' [Heval' Hlessdef']].
+ destruct (Mem.loadv chunk m' a') eqn:Hload'.
+ {
+ left; econstructor; econstructor; split.
+ eapply exec_Iload; eauto.
+
+ try (rewrite eval_addressing_preserved with (ge1 := ge); auto; exact symbols_preserved).
+ eapply match_states_succ; eauto. apply set_reg_lessdef; auto.
+ }
+ {
+ left; econstructor; econstructor; split.
+ eapply exec_Iload_notrap2; eauto.
+
+ try (rewrite eval_addressing_preserved with (ge1 := ge); auto; exact symbols_preserved).
+ eapply match_states_succ; eauto. apply set_reg_lessdef; auto.
+ }
- (* Istore *)
rename pc'0 into pc. TransfInstr.
diff --git a/backend/Deadcode.v b/backend/Deadcode.v
index 2286876e..1f208a91 100644
--- a/backend/Deadcode.v
+++ b/backend/Deadcode.v
@@ -123,7 +123,7 @@ Definition transfer (f: function) (approx: PMap.t VA.t)
if is_dead nres then after
else if is_int_zero nres then (kill res ne, nm)
else (add_needs args (needs_of_operation op nres) (kill res ne), nm)
- | Some (Iload chunk addr args dst s) =>
+ | Some (Iload trap chunk addr args dst s) =>
let ndst := nreg ne dst in
if is_dead ndst then after
else if is_int_zero ndst then (kill dst ne, nm)
@@ -175,7 +175,7 @@ Definition transf_instr (approx: PMap.t VA.t) (an: PMap.t NA.t)
end
else
instr
- | Iload chunk addr args dst s =>
+ | Iload trap chunk addr args dst s =>
let ndst := nreg (fst an!!pc) dst in
if is_dead ndst then
Inop s
diff --git a/backend/Deadcodeproof.v b/backend/Deadcodeproof.v
index 2edc0395..6919fe78 100644
--- a/backend/Deadcodeproof.v
+++ b/backend/Deadcodeproof.v
@@ -829,6 +829,83 @@ Ltac UseTransfer :=
apply eagree_update; eauto 2 with na.
eapply magree_monotone; eauto. intros. apply incl_nmem_add; auto.
+- (* load notrap1 *)
+ TransfInstr; UseTransfer.
+ destruct (is_dead (nreg ne dst)) eqn:DEAD;
+ [idtac|destruct (is_int_zero (nreg ne dst)) eqn:INTZERO];
+ simpl in *.
++ (* dead instruction, turned into a nop *)
+ econstructor; split.
+ eapply exec_Inop; eauto.
+ eapply match_succ_states; eauto. simpl; auto.
+ apply eagree_update_dead; auto with na.
++ (* instruction with needs = [I Int.zero], turned into a load immediate of zero. *)
+ econstructor; split.
+ eapply exec_Iop with (v := Vint Int.zero); eauto.
+ eapply match_succ_states; eauto. simpl; auto.
+ apply eagree_update; auto.
+ rewrite is_int_zero_sound by auto.
+ unfold default_notrap_load_value.
+ constructor.
++ (* preserved *)
+ exploit eval_addressing_lessdef_none. eapply add_needs_all_lessdef; eauto. eassumption.
+ intro Hnone'.
+ assert (eval_addressing tge (Vptr sp0 Ptrofs.zero) addr te ## args = None) as Hnone2'.
+ erewrite eval_addressing_preserved with (ge1 := ge).
+ assumption.
+ exact symbols_preserved.
+
+ econstructor; split.
+ eapply exec_Iload_notrap1; eauto.
+ eapply match_succ_states; eauto. simpl; auto.
+ apply eagree_update; eauto 2 with na.
+ eapply magree_monotone; eauto. intros. apply incl_nmem_add; auto.
+
+- (* load notrap2 *)
+ TransfInstr; UseTransfer.
+
+ destruct (is_dead (nreg ne dst)) eqn:DEAD;
+ [idtac|destruct (is_int_zero (nreg ne dst)) eqn:INTZERO];
+ simpl in *.
++ (* dead instruction, turned into a nop *)
+ econstructor; split.
+ eapply exec_Inop; eauto.
+ eapply match_succ_states; eauto. simpl; auto.
+ apply eagree_update_dead; auto with na.
++ (* instruction with needs = [I Int.zero], turned into a load immediate of zero. *)
+ econstructor; split.
+ eapply exec_Iop with (v := Vint Int.zero); eauto.
+ eapply match_succ_states; eauto. simpl; auto.
+ apply eagree_update; auto.
+ rewrite is_int_zero_sound by auto.
+ unfold default_notrap_load_value.
+ constructor.
++ (* preserved *)
+ exploit eval_addressing_lessdef. eapply add_needs_all_lessdef; eauto. eauto.
+ intros (ta & U & V).
+ destruct (Mem.loadv chunk tm ta) eqn:Hchunk2.
+ {
+ econstructor; split.
+ eapply exec_Iload. eauto.
+ erewrite eval_addressing_preserved with (ge1 := ge).
+ eassumption.
+ exact symbols_preserved.
+ eassumption.
+ eapply match_succ_states; eauto. simpl; auto.
+ apply eagree_update; eauto 2 with na.
+ eapply magree_monotone; eauto. intros. apply incl_nmem_add; auto.
+ }
+ {
+ econstructor; split.
+ eapply exec_Iload_notrap2. eauto.
+ erewrite eval_addressing_preserved with (ge1 := ge).
+ eassumption.
+ exact symbols_preserved.
+ eassumption.
+ eapply match_succ_states; eauto. simpl; auto.
+ apply eagree_update; eauto 2 with na.
+ eapply magree_monotone; eauto. intros. apply incl_nmem_add; auto.
+ }
- (* store *)
TransfInstr; UseTransfer.
destruct (nmem_contains nm (aaddressing (vanalyze cu f) # pc addr args)
diff --git a/backend/Debugvar.v b/backend/Debugvar.v
index 1f361030..56908855 100644
--- a/backend/Debugvar.v
+++ b/backend/Debugvar.v
@@ -233,7 +233,7 @@ Definition transfer (lm: labelmap) (before: option avail) (i: instruction):
(lm, Some (kill (S sl ofs ty) s))
| Lop op args dst =>
(lm, Some (kill (R dst) s))
- | Lload chunk addr args dst =>
+ | Lload trap chunk addr args dst =>
(lm, Some (kill (R dst) s))
| Lstore chunk addr args src =>
(lm, before)
diff --git a/backend/Debugvarproof.v b/backend/Debugvarproof.v
index d31c63ec..95020637 100644
--- a/backend/Debugvarproof.v
+++ b/backend/Debugvarproof.v
@@ -449,6 +449,22 @@ Proof.
eauto. eauto.
apply eval_add_delta_ranges. traceEq.
constructor; auto.
+- (* load notrap1 *)
+ econstructor; split.
+ eapply plus_left.
+ eapply exec_Lload_notrap1.
+ rewrite <- H; apply eval_addressing_preserved; exact symbols_preserved.
+ eauto. eauto.
+ apply eval_add_delta_ranges. traceEq.
+ constructor; auto.
+- (* load notrap2 *)
+ econstructor; split.
+ eapply plus_left.
+ eapply exec_Lload_notrap2.
+ rewrite <- H; apply eval_addressing_preserved; exact symbols_preserved.
+ eauto. eauto.
+ apply eval_add_delta_ranges. traceEq.
+ constructor; auto.
- (* store *)
econstructor; split.
eapply plus_left.
diff --git a/backend/Duplicate.v b/backend/Duplicate.v
new file mode 100644
index 00000000..82c17367
--- /dev/null
+++ b/backend/Duplicate.v
@@ -0,0 +1,203 @@
+(** 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 tm m a lr r n => match tinst with
+ | Iload tm' m' a' lr' r' n' =>
+ do u <- verify_is_copy dupmap n n';
+ if (trapping_mode_eq tm tm') then
+ 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")
+ else Error (msg "Different trapping_mode 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' =>
+ if (list_eq_dec Pos.eq_dec lr lr') then
+ if (eq_condition cond cond') then
+ do u1 <- verify_is_copy dupmap n1 n1';
+ do u2 <- verify_is_copy dupmap n2 n2'; OK tt
+ else if (eq_condition (negate_condition cond) cond') then
+ do u1 <- verify_is_copy dupmap n1 n2';
+ do u2 <- verify_is_copy dupmap n2 n1'; OK tt
+ else Error (msg "Incompatible conditions in Icond")
+ else Error (msg "Different lr 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.
diff --git a/backend/Duplicateaux.ml b/backend/Duplicateaux.ml
new file mode 100644
index 00000000..d0b7129e
--- /dev/null
+++ b/backend/Duplicateaux.ml
@@ -0,0 +1,572 @@
+open RTL
+open Maps
+open Camlcoq
+
+(* TTL : IR emphasizing the preferred next node *)
+module TTL = struct
+ type instruction =
+ | Tleaf of RTL.instruction
+ | Tnext of node * RTL.instruction
+
+ type code = instruction PTree.t
+end;;
+
+open TTL
+
+(** RTL to TTL *)
+
+let get_some = function
+| None -> failwith "Did not get some"
+| Some thing -> thing
+
+let bfs code entrypoint =
+ let visited = ref (PTree.map (fun n i -> false) code)
+ and bfs_list = ref []
+ and to_visit = Queue.create ()
+ and node = ref entrypoint
+ in begin
+ Queue.add entrypoint to_visit;
+ while not (Queue.is_empty to_visit) do
+ node := Queue.pop to_visit;
+ if not (get_some @@ PTree.get !node !visited) then begin
+ visited := PTree.set !node true !visited;
+ match PTree.get !node code with
+ | None -> failwith "No such node"
+ | Some i ->
+ bfs_list := !bfs_list @ [!node];
+ match i with
+ | Icall(_, _, _, _, n) -> Queue.add n to_visit
+ | Ibuiltin(_, _, _, n) -> Queue.add n to_visit
+ | Ijumptable(_, ln) -> List.iter (fun n -> Queue.add n to_visit) ln
+ | Itailcall _ | Ireturn _ -> ()
+ | Icond (_, _, n1, n2) -> Queue.add n1 to_visit; Queue.add n2 to_visit
+ | Inop n | Iop (_, _, _, n) | Iload (_, _, _, _, _, n) | Istore (_, _, _, _, n) -> Queue.add n to_visit
+ end
+ done;
+ !bfs_list
+ end
+
+let optbool o = match o with Some _ -> true | None -> false
+
+let ptree_get_some n ptree = get_some @@ PTree.get n ptree
+
+let get_predecessors_rtl code =
+ let preds = ref (PTree.map (fun n i -> []) code) in
+ let process_inst (node, i) =
+ let succ = match i with
+ | Inop n | Iop (_,_,_,n) | Iload (_, _,_,_,_,n) | Istore (_,_,_,_,n)
+ | Icall (_,_,_,_,n) | Ibuiltin (_, _, _, n) -> [n]
+ | Icond (_,_,n1,n2) -> [n1;n2]
+ | Ijumptable (_,ln) -> ln
+ | Itailcall _ | Ireturn _ -> []
+ in List.iter (fun s ->
+ let previous_preds = ptree_get_some s !preds in
+ if optbool @@ List.find_opt (fun e -> e == node) previous_preds then ()
+ else preds := PTree.set s (node::previous_preds) !preds) succ
+ in begin
+ List.iter process_inst (PTree.elements code);
+ !preds
+ end
+
+module PInt = struct
+ type t = P.t
+ let compare x y = compare (P.to_int x) (P.to_int y)
+end
+
+module PSet = Set.Make(PInt)
+
+let print_intlist l =
+ let rec f = function
+ | [] -> ()
+ | n::ln -> (Printf.printf "%d " (P.to_int n); f ln)
+ in begin
+ Printf.printf "[";
+ f l;
+ Printf.printf "]"
+ end
+
+let print_intset s =
+ let seq = PSet.to_seq s
+ in begin
+ Printf.printf "{";
+ Seq.iter (fun n ->
+ Printf.printf "%d " (P.to_int n)
+ ) seq;
+ Printf.printf "}"
+ end
+
+(* FIXME - dominators not working well because the order of dataflow update isn't right *)
+ (*
+let get_dominators code entrypoint =
+ let bfs_order = bfs code entrypoint
+ and predecessors = get_predecessors_rtl code
+ in let doms = ref (PTree.map (fun n i -> PSet.of_list bfs_order) code)
+ in begin
+ Printf.printf "BFS: ";
+ print_intlist bfs_order;
+ Printf.printf "\n";
+ List.iter (fun n ->
+ let preds = get_some @@ PTree.get n predecessors
+ and single = PSet.singleton n
+ in match preds with
+ | [] -> doms := PTree.set n single !doms
+ | p::lp ->
+ let set_p = get_some @@ PTree.get p !doms
+ and set_lp = List.map (fun p -> get_some @@ PTree.get p !doms) lp
+ in let inter = List.fold_left PSet.inter set_p set_lp
+ in let union = PSet.union inter single
+ in begin
+ Printf.printf "----------------------------------------\n";
+ Printf.printf "n = %d\n" (P.to_int n);
+ Printf.printf "set_p = "; print_intset set_p; Printf.printf "\n";
+ Printf.printf "set_lp = ["; List.iter (fun s -> print_intset s; Printf.printf ", ") set_lp; Printf.printf "]\n";
+ Printf.printf "=> inter = "; print_intset inter; Printf.printf "\n";
+ Printf.printf "=> union = "; print_intset union; Printf.printf "\n";
+ doms := PTree.set n union !doms
+ end
+ ) bfs_order;
+ !doms
+ end
+*)
+
+let print_dominators dominators =
+ let domlist = PTree.elements dominators
+ in begin
+ Printf.printf "{\n";
+ List.iter (fun (n, doms) ->
+ Printf.printf "\t";
+ Printf.printf "%d:" (P.to_int n);
+ print_intset doms;
+ Printf.printf "\n"
+ ) domlist
+ end
+
+type vstate = Unvisited | Processed | Visited
+
+(** Getting loop branches with a DFS visit :
+ * Each node is either Unvisited, Visited, or Processed
+ * pre-order: node becomes Processed
+ * post-order: node becomes Visited
+ *
+ * If we come accross an edge to a Processed node, it's a loop!
+ *)
+let get_loop_headers code entrypoint =
+ let visited = ref (PTree.map (fun n i -> Unvisited) code)
+ and is_loop_header = ref (PTree.map (fun n i -> false) code)
+ in let rec dfs_visit code = function
+ | [] -> ()
+ | node :: ln ->
+ match (get_some @@ PTree.get node !visited) with
+ | Visited -> ()
+ | Processed -> begin
+ is_loop_header := PTree.set node true !is_loop_header;
+ visited := PTree.set node Visited !visited
+ end
+ | Unvisited -> begin
+ visited := PTree.set node Processed !visited;
+ match PTree.get node code with
+ | None -> failwith "No such node"
+ | Some i -> let next_visits = (match i with
+ | Icall (_, _, _, _, n) | Ibuiltin (_, _, _, n) | Inop n | Iop (_, _, _, n)
+ | Iload (_, _, _, _, _, n) | Istore (_, _, _, _, n) -> [n]
+ | Icond (_, _, n1, n2) -> [n1; n2]
+ | Itailcall _ | Ireturn _ -> []
+ | Ijumptable (_, ln) -> ln
+ ) in dfs_visit code next_visits;
+ visited := PTree.set node Visited !visited;
+ dfs_visit code ln
+ end
+ in begin
+ dfs_visit code [entrypoint];
+ !is_loop_header
+ end
+
+let ptree_printbool pt =
+ let elements = PTree.elements pt
+ in begin
+ Printf.printf "[";
+ List.iter (fun (n, b) ->
+ if b then Printf.printf "%d, " (P.to_int n) else ()
+ ) elements;
+ Printf.printf "]"
+ end
+
+(* Looks ahead (until a branch) to see if a node further down verifies
+ * the given predicate *)
+let rec look_ahead code node is_loop_header predicate =
+ if (predicate node) then true
+ else match (get_some @@ PTree.get node code) with
+ | Ireturn _ | Itailcall _ | Icond _ | Ijumptable _ -> false
+ | Inop n | Iop (_, _, _, n) | Iload (_, _, _, _, _, n)
+ | Istore (_, _, _, _, n) | Icall (_, _, _, _, n)
+ | Ibuiltin (_, _, _, n) ->
+ if (predicate n) then true
+ else (
+ if (get_some @@ PTree.get n is_loop_header) then false
+ else look_ahead code n is_loop_header predicate
+ )
+
+exception HeuristicSucceeded
+
+let do_call_heuristic code ifso ifnot is_loop_header preferred =
+ let predicate n = (function
+ | Icall _ -> true
+ | _ -> false) @@ get_some @@ PTree.get n code
+ in if (look_ahead code ifso is_loop_header predicate) then
+ (preferred := false; raise HeuristicSucceeded)
+ else if (look_ahead code ifnot is_loop_header predicate) then
+ (preferred := true; raise HeuristicSucceeded)
+ else ()
+
+let do_opcode_heuristic code cond ifso ifnot preferred = DuplicateOpcodeHeuristic.opcode_heuristic code cond ifso ifnot preferred
+
+let do_return_heuristic code ifso ifnot is_loop_header preferred =
+ let predicate n = (function
+ | Ireturn _ -> true
+ | _ -> false) @@ get_some @@ PTree.get n code
+ in if (look_ahead code ifso is_loop_header predicate) then
+ (preferred := false; raise HeuristicSucceeded)
+ else if (look_ahead code ifnot is_loop_header predicate) then
+ (preferred := true; raise HeuristicSucceeded)
+ else ()
+
+let do_store_heuristic code ifso ifnot is_loop_header preferred =
+ let predicate n = (function
+ | Istore _ -> true
+ | _ -> false) @@ get_some @@ PTree.get n code
+ in if (look_ahead code ifso is_loop_header predicate) then
+ (preferred := false; raise HeuristicSucceeded)
+ else if (look_ahead code ifnot is_loop_header predicate) then
+ (preferred := true; raise HeuristicSucceeded)
+ else ()
+
+let do_loop_heuristic code ifso ifnot is_loop_header preferred =
+ let predicate n = get_some @@ PTree.get n is_loop_header
+ in if (look_ahead code ifso is_loop_header predicate) then
+ (preferred := true; raise HeuristicSucceeded)
+ else if (look_ahead code ifnot is_loop_header predicate) then
+ (preferred := false; raise HeuristicSucceeded)
+ else ()
+
+let get_directions code entrypoint =
+ let bfs_order = bfs code entrypoint
+ and is_loop_header = get_loop_headers code entrypoint
+ and directions = ref (PTree.map (fun n i -> false) code) (* false <=> fallthru *)
+ in begin
+ Printf.printf "Loop headers: ";
+ ptree_printbool is_loop_header;
+ Printf.printf "\n";
+ List.iter (fun n ->
+ match (get_some @@ PTree.get n code) with
+ | Icond (cond, lr, ifso, ifnot) ->
+ Printf.printf "Analyzing %d.." (P.to_int n);
+ let preferred = ref false
+ in (try
+ Printf.printf " call..";
+ do_call_heuristic code ifso ifnot is_loop_header preferred;
+ Printf.printf " opcode..";
+ do_opcode_heuristic code cond ifso ifnot preferred;
+ Printf.printf " return..";
+ do_return_heuristic code ifso ifnot is_loop_header preferred;
+ Printf.printf " store..";
+ do_store_heuristic code ifso ifnot is_loop_header preferred;
+ Printf.printf " loop..";
+ do_loop_heuristic code ifso ifnot is_loop_header preferred;
+ Printf.printf "Random choice for %d\n" (P.to_int n);
+ preferred := Random.bool ()
+ with HeuristicSucceeded | DuplicateOpcodeHeuristic.HeuristicSucceeded
+ -> Printf.printf " %s\n" (match !preferred with true -> "BRANCH"
+ | false -> "FALLTHROUGH")
+ ); directions := PTree.set n !preferred !directions
+ | _ -> ()
+ ) bfs_order;
+ !directions
+ end
+
+let to_ttl_inst direction = function
+| Ireturn o -> Tleaf (Ireturn o)
+| Inop n -> Tnext (n, Inop n)
+| Iop (op, lr, r, n) -> Tnext (n, Iop(op, lr, r, n))
+| Iload (tm, m, a, lr, r, n) -> Tnext (n, Iload(tm, m, a, lr, r, n))
+| Istore (m, a, lr, r, n) -> Tnext (n, Istore(m, a, lr, r, n))
+| Icall (s, ri, lr, r, n) -> Tleaf (Icall(s, ri, lr, r, n))
+| Itailcall (s, ri, lr) -> Tleaf (Itailcall(s, ri, lr))
+| Ibuiltin (ef, lbr, br, n) -> Tleaf (Ibuiltin(ef, lbr, br, n))
+| Icond (cond, lr, n, n') -> (match direction with
+ | false -> Tnext (n', Icond(cond, lr, n, n'))
+ | true -> Tnext (n, Icond(cond, lr, n, n')))
+| Ijumptable (r, ln) -> Tleaf (Ijumptable(r, ln))
+
+let rec to_ttl_code_rec directions = function
+| [] -> PTree.empty
+| m::lm -> let (n, i) = m
+ in let direction = get_some @@ PTree.get n directions
+ in PTree.set n (to_ttl_inst direction i) (to_ttl_code_rec directions lm)
+
+let to_ttl_code code entrypoint =
+ let directions = get_directions code entrypoint
+ in begin
+ Printf.printf "Ifso directions: ";
+ ptree_printbool directions;
+ Printf.printf "\n";
+ Random.init(0); (* using same seed to make it deterministic *)
+ to_ttl_code_rec directions (PTree.elements code)
+ end
+
+(** Trace selection on TTL *)
+
+let rec exists_false_rec = function
+ | [] -> false
+ | m::lm -> let (_, b) = m in if b then exists_false_rec lm else true
+
+let exists_false boolmap = exists_false_rec (PTree.elements boolmap)
+
+(* DFS on TTL to guide the exploration *)
+let dfs code entrypoint =
+ let visited = ref (PTree.map (fun n i -> false) code) in
+ let rec dfs_list code = function
+ | [] -> []
+ | node :: ln ->
+ let node_dfs =
+ if not (get_some @@ PTree.get node !visited) then begin
+ visited := PTree.set node true !visited;
+ match PTree.get node code with
+ | None -> failwith "No such node"
+ | Some ti -> [node] @ match ti with
+ | Tleaf i -> (match i with
+ | Icall(_, _, _, _, n) -> dfs_list code [n]
+ | Ibuiltin(_, _, _, n) -> dfs_list code [n]
+ | Ijumptable(_, ln) -> dfs_list code ln
+ | Itailcall _ | Ireturn _ -> []
+ | _ -> failwith "Tleaf case not handled in dfs" )
+ | Tnext (n,i) -> (dfs_list code [n]) @ match i with
+ | Icond (_, _, n1, n2) -> dfs_list code [n1; n2]
+ | Inop _ | Iop _ | Iload _ | Istore _ -> []
+ | _ -> failwith "Tnext case not handled in dfs"
+ end
+ else []
+ in node_dfs @ (dfs_list code ln)
+ in dfs_list code [entrypoint]
+
+let get_predecessors_ttl code =
+ let preds = ref (PTree.map (fun n i -> []) code) in
+ let process_inst (node, ti) = match ti with
+ | Tleaf _ -> ()
+ | Tnext (_, i) -> let succ = match i with
+ | Inop n | Iop (_,_,_,n) | Iload (_, _,_,_,_,n) | Istore (_,_,_,_,n)
+ | Icall (_,_,_,_,n) | Ibuiltin (_, _, _, n) -> [n]
+ | Icond (_,_,n1,n2) -> [n1;n2]
+ | Ijumptable (_,ln) -> ln
+ | _ -> []
+ in List.iter (fun s -> preds := PTree.set s (node::(get_some @@ PTree.get s !preds)) !preds) succ
+ in begin
+ List.iter process_inst (PTree.elements code);
+ !preds
+ end
+
+let rtl_proj code = PTree.map (fun n ti -> match ti with Tleaf i | Tnext(_, i) -> i) code
+
+let rec select_unvisited_node is_visited = function
+| [] -> failwith "Empty list"
+| n :: ln -> if not (ptree_get_some n is_visited) then n else select_unvisited_node is_visited ln
+
+let best_successor_of node code is_visited =
+ match (PTree.get node code) with
+ | None -> failwith "No such node in the code"
+ | Some ti -> match ti with
+ | Tleaf _ -> None
+ | Tnext (n,_) -> if not (ptree_get_some n is_visited) then Some n
+ else None
+
+let best_predecessor_of node predecessors order is_visited =
+ match (PTree.get node predecessors) with
+ | None -> failwith "No predecessor list found"
+ | Some lp -> try Some (List.find (fun n -> (List.mem n lp) && (not (ptree_get_some n is_visited))) order)
+ with Not_found -> None
+
+(* Algorithm mostly inspired from Chang and Hwu 1988
+ * "Trace Selection for Compiling Large C Application Programs to Microcode" *)
+let select_traces code entrypoint =
+ let order = dfs code entrypoint in
+ let predecessors = get_predecessors_ttl code in
+ let traces = ref [] in
+ let is_visited = ref (PTree.map (fun n i -> false) code) in begin (* mark all nodes visited *)
+ while exists_false !is_visited do (* while (there are unvisited nodes) *)
+ let seed = select_unvisited_node !is_visited order in
+ let trace = ref [seed] in
+ let current = ref seed in begin
+ is_visited := PTree.set seed true !is_visited; (* mark seed visited *)
+ let quit_loop = ref false in begin
+ while not !quit_loop do
+ let s = best_successor_of !current code !is_visited in
+ match s with
+ | None -> quit_loop := true (* if (s==0) exit loop *)
+ | Some succ -> begin
+ trace := !trace @ [succ];
+ is_visited := PTree.set succ true !is_visited; (* mark s visited *)
+ current := succ
+ end
+ done;
+ current := seed;
+ quit_loop := false;
+ while not !quit_loop do
+ let s = best_predecessor_of !current predecessors order !is_visited in
+ match s with
+ | None -> quit_loop := true (* if (s==0) exit loop *)
+ | Some pred -> begin
+ trace := pred :: !trace;
+ is_visited := PTree.set pred true !is_visited; (* mark s visited *)
+ current := pred
+ end
+ done;
+ traces := !trace :: !traces;
+ end
+ end
+ done;
+ Printf.printf "DFS: \t"; print_intlist order; Printf.printf "\n";
+ !traces
+ end
+
+let print_trace t = print_intlist t
+
+let print_traces traces =
+ let rec f = function
+ | [] -> ()
+ | t::lt -> Printf.printf "\n\t"; print_trace t; Printf.printf ",\n"; f lt
+ in begin
+ Printf.printf "Traces: {";
+ f traces;
+ Printf.printf "}\n";
+ end
+
+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 code = make_identity_ptree_rec (PTree.elements code)
+
+(* Change the pointers of preds nodes to point to n' instead of n *)
+let rec change_pointers code n n' = function
+ | [] -> code
+ | pred :: preds ->
+ let new_pred_inst = match ptree_get_some pred code with
+ | Icall(a, b, c, d, n0) -> assert (n0 == n); Icall(a, b, c, d, n')
+ | Ibuiltin(a, b, c, n0) -> assert (n0 == n); Ibuiltin(a, b, c, n')
+ | Ijumptable(a, ln) -> assert (optbool @@ List.find_opt (fun e -> e == n) ln);
+ Ijumptable(a, List.map (fun e -> if (e == n) then n' else e) ln)
+ | Icond(a, b, n1, n2) -> assert (n1 == n || n2 == n);
+ let n1' = if (n1 == n) then n' else n1
+ in let n2' = if (n2 == n) then n' else n2
+ in Icond(a, b, n1', n2')
+ | Inop n0 -> assert (n0 == n); Inop n'
+ | Iop (a, b, c, n0) -> assert (n0 == n); Iop (a, b, c, n')
+ | Iload (a, b, c, d, e, n0) -> assert (n0 == n); Iload (a, b, c, d, e, n')
+ | Istore (a, b, c, d, n0) -> assert (n0 == n); Istore (a, b, c, d, n')
+ | Itailcall _ | Ireturn _ -> failwith "That instruction cannot be a predecessor"
+ in let new_code = PTree.set pred new_pred_inst code
+ in change_pointers new_code n n' preds
+
+(* parent: parent of n to keep as parent
+ * preds: all the other parents of n
+ * n': the integer which should contain the duplicate of n
+ * returns: new code, new ptree *)
+let duplicate code ptree parent n preds n' =
+ Printf.printf "Duplicating node %d into %d..\n" (P.to_int n) (P.to_int n');
+ match PTree.get n' code with
+ | Some _ -> failwith "The PTree already has a node n'"
+ | None ->
+ let c' = change_pointers code n n' preds
+ in let new_code = PTree.set n' (ptree_get_some n code) c'
+ and new_ptree = PTree.set n' n ptree
+ in (new_code, new_ptree)
+
+let rec maxint = function
+ | [] -> 0
+ | i :: l -> assert (i >= 0); let m = maxint l in if i > m then i else m
+
+let is_empty = function
+ | [] -> true
+ | _ -> false
+
+(* code: RTL code
+ * preds: mapping node -> predecessors
+ * ptree: the revmap
+ * trace: the trace to follow tail duplication on *)
+let tail_duplicate code preds ptree trace =
+ (* next_int: unused integer that can be used for the next duplication *)
+ let next_int = ref (maxint (List.map (fun e -> let (n, _) = e in P.to_int n) (PTree.elements code)) + 1)
+ (* last_node and last_duplicate store resp. the last processed node of the trace, and its duplication *)
+ in let last_node = ref None
+ in let last_duplicate = ref None
+ in let nb_duplicated = ref 0
+ (* recursive function on a trace *)
+ in let rec f code ptree is_first = function
+ | [] -> (code, ptree)
+ | n :: t ->
+ let (new_code, new_ptree) =
+ if is_first then (code, ptree) (* first node is never duplicated regardless of its inputs *)
+ else
+ let node_preds = ptree_get_some n preds
+ in let node_preds_nolast = List.filter (fun e -> e <> get_some !last_node) node_preds
+ in let final_node_preds = match !last_duplicate with
+ | None -> node_preds_nolast
+ | Some n' -> n' :: node_preds_nolast
+ in if not (is_empty final_node_preds) then
+ let n' = !next_int
+ in let (newc, newp) = duplicate code ptree !last_node n final_node_preds (P.of_int n')
+ in begin
+ next_int := !next_int + 1;
+ nb_duplicated := !nb_duplicated + 1;
+ last_duplicate := Some (P.of_int n');
+ (newc, newp)
+ end
+ else (code, ptree)
+ in begin
+ last_node := Some n;
+ f new_code new_ptree false t
+ end
+ in let new_code, new_ptree = f code ptree true trace
+ in (new_code, new_ptree, !nb_duplicated)
+
+let superblockify_traces code preds traces =
+ let max_nb_duplicated = 1 (* FIXME - should be architecture dependent *)
+ in let ptree = make_identity_ptree code
+ in let rec f code ptree = function
+ | [] -> (code, ptree, 0)
+ | trace :: traces ->
+ let new_code, new_ptree, nb_duplicated = tail_duplicate code preds ptree trace
+ in if (nb_duplicated < max_nb_duplicated) then f new_code new_ptree traces
+ else (Printf.printf "Too many duplicated nodes, aborting tail duplication\n"; (code, ptree, 0))
+ in let new_code, new_ptree, _ = f code ptree traces
+ in (new_code, new_ptree)
+
+let rec invert_iconds_trace code = function
+ | [] -> code
+ | n::[] -> code
+ | n :: n' :: t ->
+ let code' = match ptree_get_some n code with
+ | Icond (c, lr, ifso, ifnot) ->
+ assert (n' == ifso || n' == ifnot);
+ if (n' == ifso) then (
+ Printf.printf "Reversing ifso/ifnot for node %d\n" (P.to_int n);
+ PTree.set n (Icond (Op.negate_condition c, lr, ifnot, ifso)) code )
+ else code
+ | _ -> code
+ in invert_iconds_trace code' (n'::t)
+
+let rec invert_iconds code = function
+ | [] -> code
+ | t :: ts ->
+ let code' = if !Clflags.option_finvertcond then invert_iconds_trace code t
+ else code
+ in invert_iconds code' ts
+
+(* For now, identity function *)
+let duplicate_aux f =
+ let entrypoint = f.fn_entrypoint in
+ let code = f.fn_code in
+ let traces = select_traces (to_ttl_code code entrypoint) entrypoint in
+ let icond_code = invert_iconds code traces in
+ let preds = get_predecessors_rtl icond_code in
+ let (new_code, pTreeId) = (print_traces traces; superblockify_traces icond_code preds traces) in
+ ((new_code, f.fn_entrypoint), pTreeId)
diff --git a/backend/Duplicateproof.v b/backend/Duplicateproof.v
new file mode 100644
index 00000000..a8e9b16b
--- /dev/null
+++ b/backend/Duplicateproof.v
@@ -0,0 +1,523 @@
+(** 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' tm m a lr r,
+ dupmap!n' = (Some n) -> match_inst dupmap (Iload tm m a lr r n) (Iload tm 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_revcond: forall ifso ifso' ifnot ifnot' c lr,
+ dupmap!ifso' = (Some ifso) -> dupmap!ifnot' = (Some ifnot) ->
+ match_inst dupmap (Icond c lr ifso ifnot) (Icond (negate_condition c) lr ifnot' ifso')
+ | 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 (trapping_mode_eq _ _); try discriminate.
+ 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).
+ destruct (list_eq_dec _ _ _); try discriminate. subst.
+ destruct (eq_condition _ _); try discriminate.
+ + monadInv H. destruct x. eapply verify_is_copy_correct in EQ.
+ destruct x0. eapply verify_is_copy_correct in EQ1.
+ constructor; assumption.
+ + destruct (eq_condition _ _); try discriminate.
+ monadInv H. destruct x. eapply verify_is_copy_correct in EQ.
+ destruct x0. eapply verify_is_copy_correct in EQ1.
+ 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; (* is the follow still needed?*) erewrite eval_addressing_preserved; eauto.
+ + econstructor; eauto.
+(* Iload notrap1 *)
+ - eapply dupmap_correct in DUPLIC; eauto.
+ destruct DUPLIC as (i' & H2 & H3). inv H3.
+ pose symbols_preserved as SYMPRES.
+ eexists. split.
+ + eapply exec_Iload_notrap1; eauto; erewrite eval_addressing_preserved; eauto.
+ + econstructor; eauto.
+(* Iload notrap2 *)
+ - eapply dupmap_correct in DUPLIC; eauto.
+ destruct DUPLIC as (i' & H2 & H3). inv H3.
+ pose symbols_preserved as SYMPRES.
+ eexists. split.
+ + eapply exec_Iload_notrap2; 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.
+ * (* match_inst_cond *)
+ pose symbols_preserved as SYMPRES.
+ eexists. split.
+ + eapply exec_Icond; eauto.
+ + econstructor; eauto. destruct b; auto.
+ * (* match_inst_revcond *)
+ pose symbols_preserved as SYMPRES.
+ eexists. split.
+ + eapply exec_Icond; eauto. rewrite eval_negate_condition. rewrite H0. simpl. 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/ForwardMoves.v b/backend/ForwardMoves.v
new file mode 100644
index 00000000..c73b0213
--- /dev/null
+++ b/backend/ForwardMoves.v
@@ -0,0 +1,333 @@
+Require Import Coqlib Maps Errors Integers Floats Lattice Kildall.
+Require Import AST Linking.
+Require Import Memory Registers Op RTL Maps.
+
+(* Static analysis *)
+
+Module RELATION.
+
+Definition t := (PTree.t reg).
+Definition eq (r1 r2 : t) :=
+ forall x, (PTree.get x r1) = (PTree.get x r2).
+
+Definition top : t := PTree.empty reg.
+
+Lemma eq_refl: forall x, eq x x.
+Proof.
+ unfold eq.
+ intros; reflexivity.
+Qed.
+
+Lemma eq_sym: forall x y, eq x y -> eq y x.
+Proof.
+ unfold eq.
+ intros; eauto.
+Qed.
+
+Lemma eq_trans: forall x y z, eq x y -> eq y z -> eq x z.
+Proof.
+ unfold eq.
+ intros; congruence.
+Qed.
+
+Definition reg_beq (x y : reg) :=
+ if Pos.eq_dec x y then true else false.
+
+Definition beq (r1 r2 : t) := PTree.beq reg_beq r1 r2.
+
+Lemma beq_correct: forall r1 r2, beq r1 r2 = true -> eq r1 r2.
+Proof.
+ unfold beq, eq. intros r1 r2 EQ x.
+ pose proof (PTree.beq_correct reg_beq r1 r2) as CORRECT.
+ destruct CORRECT as [CORRECTF CORRECTB].
+ pose proof (CORRECTF EQ x) as EQx.
+ clear CORRECTF CORRECTB EQ.
+ unfold reg_beq in *.
+ destruct (r1 ! x) as [R1x | ] in *;
+ destruct (r2 ! x) as [R2x | ] in *;
+ trivial; try contradiction.
+ destruct (Pos.eq_dec R1x R2x) in *; congruence.
+Qed.
+
+Definition ge (r1 r2 : t) :=
+ forall x,
+ match PTree.get x r1 with
+ | None => True
+ | Some v => (PTree.get x r2) = Some v
+ end.
+
+Lemma ge_refl: forall r1 r2, eq r1 r2 -> ge r1 r2.
+Proof.
+ unfold eq, ge.
+ intros r1 r2 EQ x.
+ pose proof (EQ x) as EQx.
+ clear EQ.
+ destruct (r1 ! x).
+ - congruence.
+ - trivial.
+Qed.
+
+Lemma ge_trans: forall x y z, ge x y -> ge y z -> ge x z.
+Proof.
+ unfold ge.
+ intros r1 r2 r3 GE12 GE23 x.
+ pose proof (GE12 x) as GE12x; clear GE12.
+ pose proof (GE23 x) as GE23x; clear GE23.
+ destruct (r1 ! x); trivial.
+ destruct (r2 ! x); congruence.
+Qed.
+
+Definition lub (r1 r2 : t) :=
+ PTree.combine
+ (fun ov1 ov2 =>
+ match ov1, ov2 with
+ | (Some v1), (Some v2) =>
+ if Pos.eq_dec v1 v2
+ then ov1
+ else None
+ | None, _
+ | _, None => None
+ end)
+ r1 r2.
+
+Lemma ge_lub_left: forall x y, ge (lub x y) x.
+Proof.
+ unfold ge, lub.
+ intros r1 r2 x.
+ rewrite PTree.gcombine by reflexivity.
+ destruct (_ ! _); trivial.
+ destruct (_ ! _); trivial.
+ destruct (Pos.eq_dec _ _); trivial.
+Qed.
+
+Lemma ge_lub_right: forall x y, ge (lub x y) y.
+Proof.
+ unfold ge, lub.
+ intros r1 r2 x.
+ rewrite PTree.gcombine by reflexivity.
+ destruct (_ ! _); trivial.
+ destruct (_ ! _); trivial.
+ destruct (Pos.eq_dec _ _); trivial.
+ congruence.
+Qed.
+
+End RELATION.
+
+Module Type SEMILATTICE_WITHOUT_BOTTOM.
+
+ Parameter t: Type.
+ Parameter eq: t -> t -> Prop.
+ Axiom eq_refl: forall x, eq x x.
+ Axiom eq_sym: forall x y, eq x y -> eq y x.
+ Axiom eq_trans: forall x y z, eq x y -> eq y z -> eq x z.
+ Parameter beq: t -> t -> bool.
+ Axiom beq_correct: forall x y, beq x y = true -> eq x y.
+ Parameter ge: t -> t -> Prop.
+ Axiom ge_refl: forall x y, eq x y -> ge x y.
+ Axiom ge_trans: forall x y z, ge x y -> ge y z -> ge x z.
+ Parameter lub: t -> t -> t.
+ Axiom ge_lub_left: forall x y, ge (lub x y) x.
+ Axiom ge_lub_right: forall x y, ge (lub x y) y.
+
+End SEMILATTICE_WITHOUT_BOTTOM.
+
+Module ADD_BOTTOM(L : SEMILATTICE_WITHOUT_BOTTOM).
+ Definition t := option L.t.
+ Definition eq (a b : t) :=
+ match a, b with
+ | None, None => True
+ | Some x, Some y => L.eq x y
+ | Some _, None | None, Some _ => False
+ end.
+
+ Lemma eq_refl: forall x, eq x x.
+ Proof.
+ unfold eq; destruct x; trivial.
+ apply L.eq_refl.
+ Qed.
+
+ Lemma eq_sym: forall x y, eq x y -> eq y x.
+ Proof.
+ unfold eq; destruct x; destruct y; trivial.
+ apply L.eq_sym.
+ Qed.
+
+ Lemma eq_trans: forall x y z, eq x y -> eq y z -> eq x z.
+ Proof.
+ unfold eq; destruct x; destruct y; destruct z; trivial.
+ - apply L.eq_trans.
+ - contradiction.
+ Qed.
+
+ Definition beq (x y : t) :=
+ match x, y with
+ | None, None => true
+ | Some x, Some y => L.beq x y
+ | Some _, None | None, Some _ => false
+ end.
+
+ Lemma beq_correct: forall x y, beq x y = true -> eq x y.
+ Proof.
+ unfold beq, eq.
+ destruct x; destruct y; trivial; try congruence.
+ apply L.beq_correct.
+ Qed.
+
+ Definition ge (x y : t) :=
+ match x, y with
+ | None, Some _ => False
+ | _, None => True
+ | Some a, Some b => L.ge a b
+ end.
+
+ Lemma ge_refl: forall x y, eq x y -> ge x y.
+ Proof.
+ unfold eq, ge.
+ destruct x; destruct y; trivial.
+ apply L.ge_refl.
+ Qed.
+
+ Lemma ge_trans: forall x y z, ge x y -> ge y z -> ge x z.
+ Proof.
+ unfold ge.
+ destruct x; destruct y; destruct z; trivial; try contradiction.
+ apply L.ge_trans.
+ Qed.
+
+ Definition bot: t := None.
+ Lemma ge_bot: forall x, ge x bot.
+ Proof.
+ unfold ge, bot.
+ destruct x; trivial.
+ Qed.
+
+ Definition lub (a b : t) :=
+ match a, b with
+ | None, _ => b
+ | _, None => a
+ | (Some x), (Some y) => Some (L.lub x y)
+ end.
+
+ Lemma ge_lub_left: forall x y, ge (lub x y) x.
+ Proof.
+ unfold ge, lub.
+ destruct x; destruct y; trivial.
+ - apply L.ge_lub_left.
+ - apply L.ge_refl.
+ apply L.eq_refl.
+ Qed.
+
+ Lemma ge_lub_right: forall x y, ge (lub x y) y.
+ Proof.
+ unfold ge, lub.
+ destruct x; destruct y; trivial.
+ - apply L.ge_lub_right.
+ - apply L.ge_refl.
+ apply L.eq_refl.
+ Qed.
+End ADD_BOTTOM.
+
+Module RB := ADD_BOTTOM(RELATION).
+Module DS := Dataflow_Solver(RB)(NodeSetForward).
+
+Definition kill (dst : reg) (rel : RELATION.t) :=
+ PTree.filter1 (fun x => if Pos.eq_dec dst x then false else true)
+ (PTree.remove dst rel).
+
+Definition move (src dst : reg) (rel : RELATION.t) :=
+ PTree.set dst (match PTree.get src rel with
+ | Some src' => src'
+ | None => src
+ end) (kill dst rel).
+
+Fixpoint kill_builtin_res (res : builtin_res reg) (rel : RELATION.t) :=
+ match res with
+ | BR z => kill z rel
+ | BR_none => rel
+ | BR_splitlong hi lo => kill_builtin_res hi (kill_builtin_res lo rel)
+ end.
+
+Definition apply_instr instr x :=
+ match instr with
+ | Inop _
+ | Icond _ _ _ _
+ | Ijumptable _ _
+ | Istore _ _ _ _ _ => Some x
+ | Iop Omove (src :: nil) dst _ => Some (move src dst x)
+ | Iop _ _ dst _
+ | Iload _ _ _ _ dst _
+ | Icall _ _ _ dst _ => Some (kill dst x)
+ | Ibuiltin _ _ res _ => Some (RELATION.top) (* TODO (kill_builtin_res res x) *)
+ | Itailcall _ _ _ | Ireturn _ => RB.bot
+ end.
+
+Definition apply_instr' code (pc : node) (ro : RB.t) : RB.t :=
+ match ro with
+ | None => None
+ | Some x =>
+ match code ! pc with
+ | None => RB.bot
+ | Some instr => apply_instr instr x
+ end
+ end.
+
+Definition forward_map (f : RTL.function) := DS.fixpoint
+ (RTL.fn_code f) RTL.successors_instr
+ (apply_instr' (RTL.fn_code f)) (RTL.fn_entrypoint f) (Some RELATION.top).
+
+Definition get_r (rel : RELATION.t) (x : reg) :=
+ match PTree.get x rel with
+ | None => x
+ | Some src => src
+ end.
+
+Definition get_rb (rb : RB.t) (x : reg) :=
+ match rb with
+ | None => x
+ | Some rel => get_r rel x
+ end.
+
+Definition subst_arg (fmap : option (PMap.t RB.t)) (pc : node) (x : reg) : reg :=
+ match fmap with
+ | None => x
+ | Some inv => get_rb (PMap.get pc inv) x
+ end.
+
+Definition subst_args fmap pc := List.map (subst_arg fmap pc).
+
+(* Transform *)
+Definition transf_instr (fmap : option (PMap.t RB.t))
+ (pc: node) (instr: instruction) :=
+ match instr with
+ | Iop op args dst s =>
+ Iop op (subst_args fmap pc args) dst s
+ | Iload trap chunk addr args dst s =>
+ Iload trap chunk addr (subst_args fmap pc args) dst s
+ | Istore chunk addr args src s =>
+ Istore chunk addr (subst_args fmap pc args) src s
+ | Icall sig ros args dst s =>
+ Icall sig ros (subst_args fmap pc args) dst s
+ | Itailcall sig ros args =>
+ Itailcall sig ros (subst_args fmap pc args)
+ | Icond cond args s1 s2 =>
+ Icond cond (subst_args fmap pc args) s1 s2
+ | Ijumptable arg tbl =>
+ Ijumptable (subst_arg fmap pc arg) tbl
+ | Ireturn (Some arg) =>
+ Ireturn (Some (subst_arg fmap pc arg))
+ | _ => instr
+ end.
+
+Definition transf_function (f: function) : function :=
+ {| fn_sig := f.(fn_sig);
+ fn_params := f.(fn_params);
+ fn_stacksize := f.(fn_stacksize);
+ fn_code := PTree.map (transf_instr (forward_map f)) f.(fn_code);
+ fn_entrypoint := f.(fn_entrypoint) |}.
+
+
+Definition transf_fundef (fd: fundef) : fundef :=
+ AST.transf_fundef transf_function fd.
+
+Definition transf_program (p: program) : program :=
+ transform_program transf_fundef p.
diff --git a/backend/ForwardMovesproof.v b/backend/ForwardMovesproof.v
new file mode 100644
index 00000000..826d4250
--- /dev/null
+++ b/backend/ForwardMovesproof.v
@@ -0,0 +1,801 @@
+Require Import FunInd.
+Require Import Coqlib Maps Errors Integers Floats Lattice Kildall.
+Require Import AST Linking.
+Require Import Values Memory Globalenvs Events Smallstep.
+Require Import Registers Op RTL.
+Require Import ForwardMoves.
+
+
+Definition match_prog (p tp: RTL.program) :=
+ match_program (fun ctx f tf => tf = transf_fundef f) eq p tp.
+
+Lemma transf_program_match:
+ forall p, match_prog p (transf_program p).
+Proof.
+ intros. eapply match_transform_program; eauto.
+Qed.
+
+Section PRESERVATION.
+
+Variables prog tprog: program.
+Hypothesis TRANSL: match_prog prog tprog.
+Let ge := Genv.globalenv prog.
+Let tge := Genv.globalenv tprog.
+
+Lemma functions_translated:
+ forall v f,
+ Genv.find_funct ge v = Some f ->
+ Genv.find_funct tge v = Some (transf_fundef f).
+Proof (Genv.find_funct_transf TRANSL).
+
+Lemma function_ptr_translated:
+ forall v f,
+ Genv.find_funct_ptr ge v = Some f ->
+ Genv.find_funct_ptr tge v = Some (transf_fundef f).
+Proof (Genv.find_funct_ptr_transf TRANSL).
+
+Lemma symbols_preserved:
+ forall id,
+ Genv.find_symbol tge id = Genv.find_symbol ge id.
+Proof (Genv.find_symbol_transf TRANSL).
+
+Lemma senv_preserved:
+ Senv.equiv ge tge.
+Proof (Genv.senv_transf TRANSL).
+
+Lemma sig_preserved:
+ forall f, funsig (transf_fundef f) = funsig f.
+Proof.
+ destruct f; trivial.
+Qed.
+
+Lemma find_function_translated:
+ forall ros rs fd,
+ find_function ge ros rs = Some fd ->
+ find_function tge ros rs = Some (transf_fundef fd).
+Proof.
+ unfold find_function; intros. destruct ros as [r|id].
+ eapply functions_translated; eauto.
+ rewrite symbols_preserved. destruct (Genv.find_symbol ge id); try congruence.
+ eapply function_ptr_translated; eauto.
+Qed.
+
+Lemma transf_function_at:
+ forall f pc i,
+ f.(fn_code)!pc = Some i ->
+ (transf_function f).(fn_code)!pc =
+ Some(transf_instr (forward_map f) pc i).
+Proof.
+ intros until i. intro CODE.
+ unfold transf_function; simpl.
+ rewrite PTree.gmap.
+ unfold option_map.
+ rewrite CODE.
+ reflexivity.
+Qed.
+
+(*
+Definition fmap_sem (fmap : option (PMap.t RB.t)) (pc : node) (rs : regset) :=
+ forall x : reg,
+ (rs # (subst_arg fmap pc x)) = (rs # x).
+ *)
+
+Lemma apply_instr'_bot :
+ forall code,
+ forall pc,
+ RB.eq (apply_instr' code pc RB.bot) RB.bot.
+Proof.
+ reflexivity.
+Qed.
+
+Definition get_rb_sem (rb : RB.t) (rs : regset) :=
+ match rb with
+ | None => False
+ | Some rel =>
+ forall x : reg,
+ (rs # (get_r rel x)) = (rs # x)
+ end.
+
+Lemma get_rb_sem_ge:
+ forall rb1 rb2 : RB.t,
+ (RB.ge rb1 rb2) ->
+ forall rs : regset,
+ (get_rb_sem rb2 rs) -> (get_rb_sem rb1 rs).
+Proof.
+ destruct rb1 as [r1 | ];
+ destruct rb2 as [r2 | ];
+ unfold get_rb_sem;
+ simpl;
+ intros GE rs RB2RS;
+ try contradiction.
+ unfold RELATION.ge in GE.
+ unfold get_r in *.
+ intro x.
+ pose proof (GE x) as GEx.
+ pose proof (RB2RS x) as RB2RSx.
+ destruct (r1 ! x) as [r1x | ] in *;
+ destruct (r2 ! x) as [r2x | ] in *;
+ congruence.
+Qed.
+
+Definition fmap_sem (fmap : option (PMap.t RB.t))
+ (pc : node) (rs : regset) :=
+ match fmap with
+ | None => True
+ | Some m => get_rb_sem (PMap.get pc m) rs
+ end.
+
+Lemma subst_arg_ok:
+ forall f,
+ forall pc,
+ forall rs,
+ forall arg,
+ fmap_sem (forward_map f) pc rs ->
+ rs # (subst_arg (forward_map f) pc arg) = rs # arg.
+Proof.
+ intros until arg.
+ intro SEM.
+ unfold fmap_sem in SEM.
+ destruct (forward_map f) as [map |]in *; trivial.
+ simpl.
+ unfold get_rb_sem in *.
+ destruct (map # pc).
+ 2: contradiction.
+ apply SEM.
+Qed.
+
+Lemma subst_args_ok:
+ forall f,
+ forall pc,
+ forall rs,
+ fmap_sem (forward_map f) pc rs ->
+ forall args,
+ rs ## (subst_args (forward_map f) pc args) = rs ## args.
+Proof.
+ induction args; trivial.
+ simpl.
+ f_equal.
+ apply subst_arg_ok; assumption.
+ assumption.
+Qed.
+
+Lemma kill_ok:
+ forall dst,
+ forall mpc,
+ forall rs,
+ forall v,
+ get_rb_sem (Some mpc) rs ->
+ get_rb_sem (Some (kill dst mpc)) rs # dst <- v.
+Proof.
+ unfold get_rb_sem.
+ intros until v.
+ intros SEM x.
+ destruct (Pos.eq_dec x dst) as [EQ | NEQ].
+ {
+ subst dst.
+ rewrite Regmap.gss.
+ unfold kill, get_r.
+ rewrite PTree.gfilter1.
+ rewrite PTree.grs.
+ apply Regmap.gss.
+ }
+ rewrite (Regmap.gso v rs NEQ).
+ unfold kill, get_r in *.
+ rewrite PTree.gfilter1.
+ rewrite PTree.gro by assumption.
+ pose proof (SEM x) as SEMx.
+ destruct (mpc ! x).
+ {
+ destruct (Pos.eq_dec dst r).
+ {
+ subst dst.
+ rewrite Regmap.gso by assumption.
+ reflexivity.
+ }
+ rewrite Regmap.gso by congruence.
+ assumption.
+ }
+ rewrite Regmap.gso by assumption.
+ reflexivity.
+Qed.
+
+Lemma kill_weaken:
+ forall dst,
+ forall mpc,
+ forall rs,
+ get_rb_sem (Some mpc) rs ->
+ get_rb_sem (Some (kill dst mpc)) rs.
+Proof.
+ unfold get_rb_sem.
+ intros until rs.
+ intros SEM x.
+ destruct (Pos.eq_dec x dst) as [EQ | NEQ].
+ {
+ subst dst.
+ unfold kill, get_r.
+ rewrite PTree.gfilter1.
+ rewrite PTree.grs.
+ reflexivity.
+ }
+ unfold kill, get_r in *.
+ rewrite PTree.gfilter1.
+ rewrite PTree.gro by assumption.
+ pose proof (SEM x) as SEMx.
+ destruct (mpc ! x).
+ {
+ destruct (Pos.eq_dec dst r).
+ {
+ reflexivity.
+ }
+ assumption.
+ }
+ reflexivity.
+Qed.
+
+Lemma top_ok :
+ forall rs, get_rb_sem (Some RELATION.top) rs.
+Proof.
+ unfold get_rb_sem, RELATION.top.
+ intros.
+ unfold get_r.
+ rewrite PTree.gempty.
+ reflexivity.
+Qed.
+
+Lemma move_ok:
+ forall mpc : RELATION.t,
+ forall src res : reg,
+ forall rs : regset,
+ get_rb_sem (Some mpc) rs ->
+ get_rb_sem (Some (move src res mpc)) (rs # res <- (rs # src)).
+Proof.
+ unfold get_rb_sem, move.
+ intros until rs.
+ intros SEM x.
+ unfold get_r in *.
+ destruct (Pos.eq_dec res x).
+ {
+ subst res.
+ rewrite PTree.gss.
+ rewrite Regmap.gss.
+ pose proof (SEM src) as SEMsrc.
+ destruct (mpc ! src) as [mpcsrc | ] in *.
+ {
+ destruct (Pos.eq_dec x mpcsrc).
+ {
+ subst mpcsrc.
+ rewrite Regmap.gss.
+ reflexivity.
+ }
+ rewrite Regmap.gso by congruence.
+ assumption.
+ }
+ destruct (Pos.eq_dec x src).
+ {
+ subst src.
+ rewrite Regmap.gss.
+ reflexivity.
+ }
+ rewrite Regmap.gso by congruence.
+ reflexivity.
+ }
+ rewrite PTree.gso by congruence.
+ rewrite Regmap.gso with (i := x) by congruence.
+ unfold kill.
+ rewrite PTree.gfilter1.
+ rewrite PTree.gro by congruence.
+ pose proof (SEM x) as SEMx.
+ destruct (mpc ! x) as [ r |].
+ {
+ destruct (Pos.eq_dec res r).
+ {
+ subst r.
+ rewrite Regmap.gso by congruence.
+ trivial.
+ }
+ rewrite Regmap.gso by congruence.
+ assumption.
+ }
+ rewrite Regmap.gso by congruence.
+ reflexivity.
+Qed.
+
+Ltac TR_AT :=
+ match goal with
+ | [ A: (fn_code _)!_ = Some _ |- _ ] =>
+ generalize (transf_function_at _ _ _ A); intros
+ end.
+
+Definition is_killed_in_map (map : PMap.t RB.t) pc res :=
+ match PMap.get pc map with
+ | None => True
+ | Some rel => exists rel', RELATION.ge rel (kill res rel')
+ end.
+
+Definition is_killed_in_fmap fmap pc res :=
+ match fmap with
+ | None => True
+ | Some map => is_killed_in_map map pc res
+ end.
+
+Definition killed_twice:
+ forall rel : RELATION.t,
+ forall res,
+ RELATION.eq (kill res rel) (kill res (kill res rel)).
+Proof.
+ unfold kill, RELATION.eq.
+ intros.
+ rewrite PTree.gfilter1.
+ rewrite PTree.gfilter1.
+ destruct (Pos.eq_dec res x).
+ {
+ subst res.
+ rewrite PTree.grs.
+ rewrite PTree.grs.
+ reflexivity.
+ }
+ rewrite PTree.gro by congruence.
+ rewrite PTree.gro by congruence.
+ rewrite PTree.gfilter1.
+ rewrite PTree.gro by congruence.
+ destruct (rel ! x) as [relx | ]; trivial.
+ destruct (Pos.eq_dec res relx); trivial.
+ destruct (Pos.eq_dec res relx); congruence.
+Qed.
+
+Lemma get_rb_killed:
+ forall mpc,
+ forall rs,
+ forall rel,
+ forall res,
+ forall vres,
+ (get_rb_sem (Some mpc) rs) ->
+ (RELATION.ge mpc (kill res rel)) ->
+ (get_rb_sem (Some mpc) rs # res <- vres).
+Proof.
+ simpl.
+ intros until vres.
+ intros SEM GE x.
+ pose proof (GE x) as GEx.
+ pose proof (SEM x) as SEMx.
+ unfold get_r in *.
+ destruct (mpc ! x) as [mpcx | ] in *; trivial.
+ unfold kill in GEx.
+ rewrite PTree.gfilter1 in GEx.
+ destruct (Pos.eq_dec res x) as [ | res_NE_x].
+ {
+ subst res.
+ rewrite PTree.grs in GEx.
+ discriminate.
+ }
+ rewrite PTree.gro in GEx by congruence.
+ rewrite Regmap.gso with (i := x) by congruence.
+ destruct (rel ! x) as [relx | ]; try discriminate.
+ destruct (Pos.eq_dec res relx) as [ res_EQ_relx | res_NE_relx] in *; try discriminate.
+ rewrite Regmap.gso by congruence.
+ congruence.
+Qed.
+
+Inductive match_frames: RTL.stackframe -> RTL.stackframe -> Prop :=
+| match_frames_intro: forall res f sp pc rs,
+ (fmap_sem (forward_map f) pc rs) ->
+ (is_killed_in_fmap (forward_map f) pc res) ->
+ match_frames (Stackframe res f sp pc rs)
+ (Stackframe res (transf_function f) sp pc rs).
+
+Inductive match_states: RTL.state -> RTL.state -> Prop :=
+ | match_regular_states: forall stk f sp pc rs m stk'
+ (STACKS: list_forall2 match_frames stk stk'),
+ (fmap_sem (forward_map f) pc rs) ->
+ match_states (State stk f sp pc rs m)
+ (State stk' (transf_function f) sp pc rs m)
+ | match_callstates: forall stk f args m stk'
+ (STACKS: list_forall2 match_frames stk stk'),
+ match_states (Callstate stk f args m)
+ (Callstate stk' (transf_fundef f) args m)
+ | match_returnstates: forall stk v m stk'
+ (STACKS: list_forall2 match_frames stk stk'),
+ match_states (Returnstate stk v m)
+ (Returnstate stk' v m).
+
+Lemma op_cases:
+ forall op,
+ forall args,
+ forall dst,
+ forall s,
+ forall x,
+ (exists src, op=Omove /\ args = src :: nil /\
+ (apply_instr (Iop op args dst s) x) = Some (move src dst x))
+ \/
+ (apply_instr (Iop op args dst s) x) = Some (kill dst x).
+Proof.
+ destruct op; try (right; simpl; reflexivity).
+ destruct args as [| arg0 args0t]; try (right; simpl; reflexivity).
+ destruct args0t as [| arg1 args1t]; try (right; simpl; reflexivity).
+ left.
+ eauto.
+Qed.
+
+Lemma step_simulation:
+ forall S1 t S2, RTL.step ge S1 t S2 ->
+ forall S1', match_states S1 S1' ->
+ exists S2', RTL.step tge S1' t S2' /\ match_states S2 S2'.
+Proof.
+ induction 1; intros S1' MS; inv MS; try TR_AT.
+- (* nop *)
+ econstructor; split. eapply exec_Inop; eauto.
+ constructor; auto.
+
+ simpl in *.
+ unfold fmap_sem in *.
+ destruct (forward_map _) as [map |] eqn:MAP in *; trivial.
+ apply get_rb_sem_ge with (rb2 := map # pc); trivial.
+ replace (map # pc) with (apply_instr' (fn_code f) pc (map # pc)).
+ {
+ eapply DS.fixpoint_solution with (code := fn_code f) (successors := successors_instr); try eassumption.
+ 2: apply apply_instr'_bot.
+ simpl. tauto.
+ }
+ unfold apply_instr'.
+ unfold get_rb_sem in *.
+ destruct (map # pc) in *; try contradiction.
+ rewrite H.
+ reflexivity.
+- (* op *)
+ econstructor; split.
+ eapply exec_Iop with (v := v); eauto.
+ rewrite <- H0.
+ rewrite subst_args_ok by assumption.
+ apply eval_operation_preserved. exact symbols_preserved.
+ constructor; auto.
+
+ unfold fmap_sem in *.
+ destruct (forward_map _) as [map |] eqn:MAP in *; trivial.
+ destruct (map # pc) as [mpc |] eqn:MPC in *; try contradiction.
+ assert (RB.ge (map # pc') (apply_instr' (fn_code f) pc (map # pc))) as GE.
+ {
+ eapply DS.fixpoint_solution with (code := fn_code f) (successors := successors_instr); try eassumption.
+ 2: apply apply_instr'_bot.
+ simpl. tauto.
+ }
+ unfold apply_instr' in GE.
+ rewrite MPC in GE.
+ rewrite H in GE.
+
+ destruct (op_cases op args res pc' mpc) as [[src [OP [ARGS MOVE]]] | KILL].
+ {
+ subst op.
+ subst args.
+ rewrite MOVE in GE.
+ simpl in H0.
+ simpl in GE.
+ apply get_rb_sem_ge with (rb2 := Some (move src res mpc)).
+ assumption.
+ replace v with (rs # src) by congruence.
+ apply move_ok.
+ assumption.
+ }
+ rewrite KILL in GE.
+ apply get_rb_sem_ge with (rb2 := Some (kill res mpc)).
+ assumption.
+ apply kill_ok.
+ assumption.
+
+(* load *)
+- econstructor; split.
+ assert (eval_addressing tge sp addr rs ## args = Some a).
+ rewrite <- H0.
+ apply eval_addressing_preserved. exact symbols_preserved.
+ eapply exec_Iload; eauto.
+ rewrite subst_args_ok; assumption.
+ constructor; auto.
+
+ simpl in *.
+ unfold fmap_sem in *.
+ destruct (forward_map _) as [map |] eqn:MAP in *; trivial.
+ destruct (map # pc) as [mpc |] eqn:MPC in *; try contradiction.
+ apply get_rb_sem_ge with (rb2 := Some (kill dst mpc)).
+ {
+ replace (Some (kill dst mpc)) with (apply_instr' (fn_code f) pc (map # pc)).
+ {
+ eapply DS.fixpoint_solution with (code := fn_code f) (successors := successors_instr); try eassumption.
+ 2: apply apply_instr'_bot.
+ simpl. tauto.
+ }
+ unfold apply_instr'.
+ rewrite H.
+ rewrite MPC.
+ reflexivity.
+ }
+ apply kill_ok.
+ assumption.
+
+- (* load notrap1 *)
+ econstructor; split.
+ assert (eval_addressing tge sp addr rs ## args = None).
+ rewrite <- H0. apply eval_addressing_preserved. exact symbols_preserved.
+ eapply exec_Iload_notrap1; eauto.
+ rewrite subst_args_ok; assumption.
+ constructor; auto.
+
+ simpl in *.
+ unfold fmap_sem in *.
+ destruct (forward_map _) as [map |] eqn:MAP in *; trivial.
+ destruct (map # pc) as [mpc |] eqn:MPC in *; try contradiction.
+ apply get_rb_sem_ge with (rb2 := Some (kill dst mpc)).
+ {
+ replace (Some (kill dst mpc)) with (apply_instr' (fn_code f) pc (map # pc)).
+ {
+ eapply DS.fixpoint_solution with (code := fn_code f) (successors := successors_instr); try eassumption.
+ 2: apply apply_instr'_bot.
+ simpl. tauto.
+ }
+ unfold apply_instr'.
+ rewrite H.
+ rewrite MPC.
+ reflexivity.
+ }
+ apply kill_ok.
+ assumption.
+
+- (* load notrap2 *)
+ econstructor; split.
+ assert (eval_addressing tge sp addr rs ## args = Some a).
+ rewrite <- H0. apply eval_addressing_preserved. exact symbols_preserved.
+ eapply exec_Iload_notrap2; eauto.
+ rewrite subst_args_ok; assumption.
+ constructor; auto.
+
+ simpl in *.
+ unfold fmap_sem in *.
+ destruct (forward_map _) as [map |] eqn:MAP in *; trivial.
+ destruct (map # pc) as [mpc |] eqn:MPC in *; try contradiction.
+ apply get_rb_sem_ge with (rb2 := Some (kill dst mpc)).
+ {
+ replace (Some (kill dst mpc)) with (apply_instr' (fn_code f) pc (map # pc)).
+ {
+ eapply DS.fixpoint_solution with (code := fn_code f) (successors := successors_instr); try eassumption.
+ 2: apply apply_instr'_bot.
+ simpl. tauto.
+ }
+ unfold apply_instr'.
+ rewrite H.
+ rewrite MPC.
+ reflexivity.
+ }
+ apply kill_ok.
+ assumption.
+
+- (* store *)
+ econstructor; split.
+ assert (eval_addressing tge sp addr rs ## args = Some a).
+ rewrite <- H0. apply eval_addressing_preserved. exact symbols_preserved.
+ eapply exec_Istore; eauto.
+ rewrite subst_args_ok; assumption.
+ constructor; auto.
+
+ simpl in *.
+ unfold fmap_sem in *.
+ destruct (forward_map _) as [map |] eqn:MAP in *; trivial.
+ apply get_rb_sem_ge with (rb2 := map # pc); trivial.
+ replace (map # pc) with (apply_instr' (fn_code f) pc (map # pc)).
+ {
+ eapply DS.fixpoint_solution with (code := fn_code f) (successors := successors_instr); try eassumption.
+ 2: apply apply_instr'_bot.
+ simpl. tauto.
+ }
+ unfold apply_instr'.
+ unfold get_rb_sem in *.
+ destruct (map # pc) in *; try contradiction.
+ rewrite H.
+ reflexivity.
+
+(* call *)
+- econstructor; split.
+ eapply exec_Icall with (fd := transf_fundef fd); eauto.
+ eapply find_function_translated; eauto.
+ apply sig_preserved.
+ rewrite subst_args_ok by assumption.
+ constructor. constructor; auto. constructor.
+
+ {
+ simpl in *.
+ unfold fmap_sem in *.
+ destruct (forward_map _) as [map |] eqn:MAP in *; trivial.
+ destruct (map # pc) as [mpc |] eqn:MPC in *; try contradiction.
+ apply get_rb_sem_ge with (rb2 := Some (kill res mpc)).
+ {
+ replace (Some (kill res mpc)) with (apply_instr' (fn_code f) pc (map # pc)).
+ {
+ eapply DS.fixpoint_solution with (code := fn_code f) (successors := successors_instr); try eassumption.
+ 2: apply apply_instr'_bot.
+ simpl. tauto.
+ }
+ unfold apply_instr'.
+ rewrite H.
+ rewrite MPC.
+ reflexivity.
+ }
+ apply kill_weaken.
+ assumption.
+ }
+ destruct (forward_map _) as [map |] eqn:MAP in *; trivial.
+ assert (RB.ge (map # pc') (apply_instr' (fn_code f) pc (map # pc))) as GE.
+ {
+ eapply DS.fixpoint_solution with (code := fn_code f) (successors := successors_instr); try eassumption.
+ 2: apply apply_instr'_bot.
+ simpl. tauto.
+ }
+ unfold apply_instr' in GE.
+ unfold fmap_sem in *.
+ destruct (map # pc) as [mpc |] in *; try contradiction.
+ rewrite H in GE.
+ simpl in GE.
+ unfold is_killed_in_fmap, is_killed_in_map.
+ unfold RB.ge in GE.
+ destruct (map # pc') as [mpc'|] eqn:MPC' in *; trivial.
+ eauto.
+
+(* tailcall *)
+- econstructor; split.
+ eapply exec_Itailcall with (fd := transf_fundef fd); eauto.
+ eapply find_function_translated; eauto.
+ apply sig_preserved.
+ rewrite subst_args_ok by assumption.
+ constructor. auto.
+
+(* builtin *)
+- econstructor; split.
+ eapply exec_Ibuiltin; eauto.
+ eapply eval_builtin_args_preserved with (ge1 := ge); eauto. exact symbols_preserved.
+ eapply external_call_symbols_preserved; eauto. apply senv_preserved.
+ constructor; auto.
+
+ simpl in *.
+ unfold fmap_sem in *.
+ destruct (forward_map _) as [map |] eqn:MAP in *; trivial.
+ destruct (map # pc) as [mpc |] eqn:MPC in *; try contradiction.
+
+ apply get_rb_sem_ge with (rb2 := Some RELATION.top).
+ {
+ replace (Some RELATION.top) with (apply_instr' (fn_code f) pc (map # pc)).
+ {
+ eapply DS.fixpoint_solution with (code := fn_code f) (successors := successors_instr); try eassumption.
+ 2: apply apply_instr'_bot.
+ simpl. tauto.
+ }
+ unfold apply_instr'.
+ rewrite H.
+ rewrite MPC.
+ reflexivity.
+ }
+ apply top_ok.
+
+(* cond *)
+- econstructor; split.
+ eapply exec_Icond; eauto.
+ rewrite subst_args_ok; eassumption.
+ constructor; auto.
+
+ simpl in *.
+ unfold fmap_sem in *.
+ destruct (forward_map _) as [map |] eqn:MAP in *; trivial.
+ apply get_rb_sem_ge with (rb2 := map # pc); trivial.
+ replace (map # pc) with (apply_instr' (fn_code f) pc (map # pc)).
+ {
+ eapply DS.fixpoint_solution with (code := fn_code f) (successors := successors_instr); try eassumption.
+ 2: apply apply_instr'_bot.
+ simpl.
+ destruct b; tauto.
+ }
+ unfold apply_instr'.
+ unfold get_rb_sem in *.
+ destruct (map # pc) in *; try contradiction.
+ rewrite H.
+ reflexivity.
+
+(* jumptbl *)
+- econstructor; split.
+ eapply exec_Ijumptable; eauto.
+ rewrite subst_arg_ok; eassumption.
+ constructor; auto.
+
+ simpl in *.
+ unfold fmap_sem in *.
+ destruct (forward_map _) as [map |] eqn:MAP in *; trivial.
+ apply get_rb_sem_ge with (rb2 := map # pc); trivial.
+ replace (map # pc) with (apply_instr' (fn_code f) pc (map # pc)).
+ {
+ eapply DS.fixpoint_solution with (code := fn_code f) (successors := successors_instr); try eassumption.
+ 2: apply apply_instr'_bot.
+ simpl.
+ apply list_nth_z_in with (n := Int.unsigned n).
+ assumption.
+ }
+ unfold apply_instr'.
+ unfold get_rb_sem in *.
+ destruct (map # pc) in *; try contradiction.
+ rewrite H.
+ reflexivity.
+
+(* return *)
+- destruct or as [arg | ].
+ {
+ econstructor; split.
+ eapply exec_Ireturn; eauto.
+ unfold regmap_optget.
+ rewrite subst_arg_ok by eassumption.
+ constructor; auto.
+ }
+ econstructor; split.
+ eapply exec_Ireturn; eauto.
+ constructor; auto.
+
+
+(* internal function *)
+- simpl. econstructor; split.
+ eapply exec_function_internal; eauto.
+ constructor; auto.
+
+ simpl in *.
+ unfold fmap_sem in *.
+ destruct (forward_map _) as [map |] eqn:MAP in *; trivial.
+ apply get_rb_sem_ge with (rb2 := Some RELATION.top).
+ {
+ eapply DS.fixpoint_entry with (code := fn_code f) (successors := successors_instr); try eassumption.
+ }
+ apply top_ok.
+
+(* external function *)
+- econstructor; split.
+ eapply exec_function_external; eauto.
+ eapply external_call_symbols_preserved; eauto. apply senv_preserved.
+ constructor; auto.
+
+(* return *)
+- inv STACKS. inv H1.
+ econstructor; split.
+ eapply exec_return; eauto.
+ constructor; auto.
+
+ simpl in *.
+ unfold fmap_sem in *.
+ destruct (forward_map _) as [map |] eqn:MAP in *; trivial.
+ unfold is_killed_in_fmap in H8.
+ unfold is_killed_in_map in H8.
+ destruct (map # pc) as [mpc |] in *; try contradiction.
+ destruct H8 as [rel' RGE].
+ eapply get_rb_killed; eauto.
+Qed.
+
+
+Lemma transf_initial_states:
+ forall S1, RTL.initial_state prog S1 ->
+ exists S2, RTL.initial_state tprog S2 /\ match_states S1 S2.
+Proof.
+ intros. inv H. econstructor; split.
+ econstructor.
+ eapply (Genv.init_mem_transf TRANSL); eauto.
+ rewrite symbols_preserved. rewrite (match_program_main TRANSL). eauto.
+ eapply function_ptr_translated; eauto.
+ rewrite <- H3; apply sig_preserved.
+ constructor. constructor.
+Qed.
+
+Lemma transf_final_states:
+ forall S1 S2 r, match_states S1 S2 -> RTL.final_state S1 r -> RTL.final_state S2 r.
+Proof.
+ intros. inv H0. inv H. inv STACKS. constructor.
+Qed.
+
+Theorem transf_program_correct:
+ forward_simulation (RTL.semantics prog) (RTL.semantics tprog).
+Proof.
+ eapply forward_simulation_step.
+ apply senv_preserved.
+ eexact transf_initial_states.
+ eexact transf_final_states.
+ exact step_simulation.
+Qed.
+
+End PRESERVATION.
diff --git a/backend/IRC.ml b/backend/IRC.ml
index 43955897..67da47da 100644
--- a/backend/IRC.ml
+++ b/backend/IRC.ml
@@ -15,6 +15,7 @@ open Camlcoq
open AST
open Registers
open Machregs
+open Machregsaux
open Locations
open Conventions1
open XTL
@@ -237,10 +238,6 @@ type graph = {
according to their types. A variable can be forced into class 2
by giving it a negative spill cost. *)
-let class_of_type = function
- | Tint | Tlong -> 0
- | Tfloat | Tsingle -> 1
- | Tany32 | Tany64 -> assert false
let class_of_reg r =
if Conventions1.is_float_reg r then 1 else 0
diff --git a/backend/IRC.mli b/backend/IRC.mli
index 30b6d5c1..f7bbf9c5 100644
--- a/backend/IRC.mli
+++ b/backend/IRC.mli
@@ -43,5 +43,4 @@ val coloring: graph -> (var -> loc)
val reserved_registers: mreg list ref
(* Auxiliaries to deal with register classes *)
-val class_of_type: AST.typ -> int
val class_of_loc: loc -> int
diff --git a/backend/Inlining.v b/backend/Inlining.v
index f7ee4166..9cf535b9 100644
--- a/backend/Inlining.v
+++ b/backend/Inlining.v
@@ -364,9 +364,9 @@ Definition expand_instr (ctx: context) (pc: node) (i: instruction): mon unit :=
| Iop op args res s =>
set_instr (spc ctx pc)
(Iop (sop ctx op) (sregs ctx args) (sreg ctx res) (spc ctx s))
- | Iload chunk addr args dst s =>
+ | Iload trap chunk addr args dst s =>
set_instr (spc ctx pc)
- (Iload chunk (saddr ctx addr) (sregs ctx args) (sreg ctx dst) (spc ctx s))
+ (Iload trap chunk (saddr ctx addr) (sregs ctx args) (sreg ctx dst) (spc ctx s))
| Istore chunk addr args src s =>
set_instr (spc ctx pc)
(Istore chunk (saddr ctx addr) (sregs ctx args) (sreg ctx src) (spc ctx s))
diff --git a/backend/Inliningaux.ml b/backend/Inliningaux.ml
index 2e83eb0c..d58704ca 100644
--- a/backend/Inliningaux.ml
+++ b/backend/Inliningaux.ml
@@ -57,7 +57,7 @@ let used_in_globvar io gv =
let fun_inline_analysis id io fn =
let inst io nid = function
| Iop (op, args, dest, succ) -> used_id io (globals_operation op)
- | Iload (chunk, addr, args, dest, succ)
+ | Iload (_, chunk, addr, args, dest, succ)
| Istore (chunk, addr, args, dest, succ) -> used_id io (globals_addressing addr)
| Ibuiltin (ef, args, dest, succ) -> used_id io (globals_of_builtin_args args)
| Icall (_, Coq_inr cid, _, _, _)
diff --git a/backend/Inliningproof.v b/backend/Inliningproof.v
index cc84b1cc..c4efaf18 100644
--- a/backend/Inliningproof.v
+++ b/backend/Inliningproof.v
@@ -929,6 +929,15 @@ Proof.
intros. inv H. eauto.
Qed.
+Lemma eval_addressing_none:
+ forall sp' ctx addr rs,
+ eval_addressing ge (Vptr sp' (Ptrofs.repr (dstk ctx))) addr rs = None ->
+ eval_addressing ge (Vptr sp' Ptrofs.zero) (saddr ctx addr) rs = None.
+Proof.
+ intros until rs; intro Heval.
+ destruct addr; destruct rs as [| r0 rs1]; simpl in *; trivial; discriminate.
+Qed.
+
Theorem step_simulation:
forall S1 t S2,
step ge S1 t S2 ->
@@ -976,6 +985,51 @@ Proof.
apply match_stacks_inside_set_reg; auto.
apply agree_set_reg; auto.
+- (* load notrap1 *)
+ exploit tr_funbody_inv; eauto. intros TR; inv TR.
+ left; econstructor; split.
+ eapply plus_one. eapply exec_Iload_notrap1. eassumption.
+ rewrite eval_addressing_preserved with (ge1:=ge) (ge2:=tge).
+ exploit eval_addressing_inj_none.
+ 4: eassumption.
+ intros. eapply symbol_address_inject.
+ eapply match_stacks_inside_globals; eauto.
+ eauto.
+ instantiate (1 := rs'##(sregs ctx args)). eapply agree_val_regs; eauto.
+ rewrite Ptrofs.add_zero_l.
+ apply eval_addressing_none.
+ exact symbols_preserved.
+ econstructor; eauto.
+ apply match_stacks_inside_set_reg; auto.
+ apply agree_set_reg; auto.
+
+- (* load notrap2 *)
+ exploit tr_funbody_inv; eauto. intros TR; inv TR.
+
+ exploit eval_addressing_inject.
+ eapply match_stacks_inside_globals; eauto.
+ eexact SP.
+ instantiate (2 := rs##args). instantiate (1 := rs'##(sregs ctx args)). eapply agree_val_regs; eauto.
+ eauto.
+ fold (saddr ctx addr). intros [a' [P Q]].
+
+ destruct (Mem.loadv chunk m' a') eqn:Hload'.
+ + left; econstructor; split.
+ eapply plus_one.
+ eapply exec_Iload; eauto.
+ try (rewrite <- P; apply eval_addressing_preserved; exact symbols_preserved).
+ econstructor; eauto.
+ apply match_stacks_inside_set_reg; auto.
+ apply agree_set_reg; auto.
+
+ + left; econstructor; split.
+ eapply plus_one.
+ eapply exec_Iload_notrap2; eauto.
+ try (rewrite <- P; apply eval_addressing_preserved; exact symbols_preserved).
+ econstructor; eauto.
+ apply match_stacks_inside_set_reg; auto.
+ apply agree_set_reg; auto.
+
- (* store *)
exploit tr_funbody_inv; eauto. intros TR; inv TR.
exploit eval_addressing_inject.
diff --git a/backend/Inliningspec.v b/backend/Inliningspec.v
index c345c942..e20fb373 100644
--- a/backend/Inliningspec.v
+++ b/backend/Inliningspec.v
@@ -270,10 +270,10 @@ Inductive tr_instr: context -> node -> instruction -> code -> Prop :=
Ple res ctx.(mreg) ->
c!(spc ctx pc) = Some (Iop (sop ctx op) (sregs ctx args) (sreg ctx res) (spc ctx s)) ->
tr_instr ctx pc (Iop op args res s) c
- | tr_load: forall ctx pc c chunk addr args res s,
+ | tr_load: forall ctx pc c trap chunk addr args res s,
Ple res ctx.(mreg) ->
- c!(spc ctx pc) = Some (Iload chunk (saddr ctx addr) (sregs ctx args) (sreg ctx res) (spc ctx s)) ->
- tr_instr ctx pc (Iload chunk addr args res s) c
+ c!(spc ctx pc) = Some (Iload trap chunk (saddr ctx addr) (sregs ctx args) (sreg ctx res) (spc ctx s)) ->
+ tr_instr ctx pc (Iload trap chunk addr args res s) c
| tr_store: forall ctx pc c chunk addr args src s,
c!(spc ctx pc) = Some (Istore chunk (saddr ctx addr) (sregs ctx args) (sreg ctx src) (spc ctx s)) ->
tr_instr ctx pc (Istore chunk addr args src s) c
diff --git a/backend/LTL.v b/backend/LTL.v
index 5e7eec8c..ee8b4826 100644
--- a/backend/LTL.v
+++ b/backend/LTL.v
@@ -29,7 +29,7 @@ Definition node := positive.
Inductive instruction: Type :=
| Lop (op: operation) (args: list mreg) (res: mreg)
- | Lload (chunk: memory_chunk) (addr: addressing) (args: list mreg) (dst: mreg)
+ | Lload (trap : trapping_mode) (chunk: memory_chunk) (addr: addressing) (args: list mreg) (dst: mreg)
| Lgetstack (sl: slot) (ofs: Z) (ty: typ) (dst: mreg)
| Lsetstack (src: mreg) (sl: slot) (ofs: Z) (ty: typ)
| Lstore (chunk: memory_chunk) (addr: addressing) (args: list mreg) (src: mreg)
@@ -209,11 +209,24 @@ Inductive step: state -> trace -> state -> Prop :=
rs' = Locmap.set (R res) v (undef_regs (destroyed_by_op op) rs) ->
step (Block s f sp (Lop op args res :: bb) rs m)
E0 (Block s f sp bb rs' m)
- | exec_Lload: forall s f sp chunk addr args dst bb rs m a v rs',
+ | exec_Lload: forall s f sp trap chunk addr args dst bb rs m a v rs',
eval_addressing ge sp addr (reglist rs args) = Some a ->
Mem.loadv chunk m a = Some v ->
rs' = Locmap.set (R dst) v (undef_regs (destroyed_by_load chunk addr) rs) ->
- step (Block s f sp (Lload chunk addr args dst :: bb) rs m)
+ step (Block s f sp (Lload trap chunk addr args dst :: bb) rs m)
+ E0 (Block s f sp bb rs' m)
+ | exec_Lload_notrap1: forall s f sp chunk addr args dst bb rs m rs',
+ eval_addressing ge sp addr (reglist rs args) = None ->
+ rs' = Locmap.set (R dst) (default_notrap_load_value chunk)
+ (undef_regs (destroyed_by_load chunk addr) rs) ->
+ step (Block s f sp (Lload NOTRAP chunk addr args dst :: bb) rs m)
+ E0 (Block s f sp bb rs' m)
+ | exec_Lload_notrap2: forall s f sp chunk addr args dst bb rs m a rs',
+ eval_addressing ge sp addr (reglist rs args) = Some a ->
+ Mem.loadv chunk m a = None ->
+ rs' = Locmap.set (R dst) (default_notrap_load_value chunk)
+ (undef_regs (destroyed_by_load chunk addr) rs) ->
+ step (Block s f sp (Lload NOTRAP chunk addr args dst :: bb) rs m)
E0 (Block s f sp bb rs' m)
| exec_Lgetstack: forall s f sp sl ofs ty dst bb rs m rs',
rs' = Locmap.set (R dst) (rs (S sl ofs ty)) (undef_regs (destroyed_by_getstack sl) rs) ->
diff --git a/backend/Linear.v b/backend/Linear.v
index 447c6ba6..1443f795 100644
--- a/backend/Linear.v
+++ b/backend/Linear.v
@@ -28,7 +28,7 @@ Inductive instruction: Type :=
| Lgetstack: slot -> Z -> typ -> mreg -> instruction
| Lsetstack: mreg -> slot -> Z -> typ -> instruction
| Lop: operation -> list mreg -> mreg -> instruction
- | Lload: memory_chunk -> addressing -> list mreg -> mreg -> instruction
+ | Lload: trapping_mode -> memory_chunk -> addressing -> list mreg -> mreg -> instruction
| Lstore: memory_chunk -> addressing -> list mreg -> mreg -> instruction
| Lcall: signature -> mreg + ident -> instruction
| Ltailcall: signature -> mreg + ident -> instruction
@@ -160,11 +160,28 @@ Inductive step: state -> trace -> state -> Prop :=
step (State s f sp (Lop op args res :: b) rs m)
E0 (State s f sp b rs' m)
| exec_Lload:
- forall s f sp chunk addr args dst b rs m a v rs',
+ forall s f sp trap chunk addr args dst b rs m a v rs',
eval_addressing ge sp addr (reglist rs args) = Some a ->
Mem.loadv chunk m a = Some v ->
rs' = Locmap.set (R dst) v (undef_regs (destroyed_by_load chunk addr) rs) ->
- step (State s f sp (Lload chunk addr args dst :: b) rs m)
+ step (State s f sp (Lload trap chunk addr args dst :: b) rs m)
+ E0 (State s f sp b rs' m)
+ | exec_Lload_notrap1:
+ forall s f sp chunk addr args dst b rs m rs',
+ eval_addressing ge sp addr (reglist rs args) = None ->
+ rs' = Locmap.set (R dst)
+ (default_notrap_load_value chunk)
+ (undef_regs (destroyed_by_load chunk addr) rs) ->
+ step (State s f sp (Lload NOTRAP chunk addr args dst :: b) rs m)
+ E0 (State s f sp b rs' m)
+ | exec_Lload_notrap2:
+ forall s f sp chunk addr args dst b rs m a rs',
+ eval_addressing ge sp addr (reglist rs args) = Some a ->
+ Mem.loadv chunk m a = None ->
+ rs' = Locmap.set (R dst)
+ (default_notrap_load_value chunk)
+ (undef_regs (destroyed_by_load chunk addr) rs) ->
+ step (State s f sp (Lload NOTRAP chunk addr args dst :: b) rs m)
E0 (State s f sp b rs' m)
| exec_Lstore:
forall s f sp chunk addr args src b rs m m' a rs',
diff --git a/backend/Linearize.v b/backend/Linearize.v
index 2cfa4d3c..4216958c 100644
--- a/backend/Linearize.v
+++ b/backend/Linearize.v
@@ -163,8 +163,8 @@ Fixpoint linearize_block (b: LTL.bblock) (k: code) : code :=
| nil => k
| LTL.Lop op args res :: b' =>
Lop op args res :: linearize_block b' k
- | LTL.Lload chunk addr args dst :: b' =>
- Lload chunk addr args dst :: linearize_block b' k
+ | LTL.Lload trap chunk addr args dst :: b' =>
+ Lload trap chunk addr args dst :: linearize_block b' k
| LTL.Lgetstack sl ofs ty dst :: b' =>
Lgetstack sl ofs ty dst :: linearize_block b' k
| LTL.Lsetstack src sl ofs ty :: b' =>
diff --git a/backend/Linearizeaux.ml b/backend/Linearizeaux.ml
index 902724e0..a6964233 100644
--- a/backend/Linearizeaux.ml
+++ b/backend/Linearizeaux.ml
@@ -1,4 +1,4 @@
-(* *********************************************************************)
+
(* *)
(* The Compcert verified compiler *)
(* *)
@@ -12,7 +12,6 @@
open LTL
open Maps
-open Camlcoq
(* Trivial enumeration, in decreasing order of PC *)
@@ -29,6 +28,8 @@ let enumerate_aux f reach =
(* More clever enumeration that flattens basic blocks *)
+open Camlcoq
+
module IntSet = Set.Make(struct type t = int let compare = compare end)
(* Determine join points: reachable nodes that have > 1 predecessor *)
@@ -110,5 +111,55 @@ let flatten_blocks blks =
(* Build the enumeration *)
-let enumerate_aux f reach =
+let enumerate_aux_flat f reach =
flatten_blocks (basic_blocks f (join_points f))
+
+(**
+ * Enumeration based on traces as identified by Duplicate.v
+ *
+ * The Duplicate phase heuristically identifies the most frequented paths. Each
+ * Icond is modified so that the preferred condition is a fallthrough (ifnot)
+ * rather than a branch (ifso).
+ *
+ * The enumeration below takes advantage of this - preferring to layout nodes
+ * following the fallthroughs of the Lcond branches
+ *)
+
+let get_some = function
+| None -> failwith "Did not get some"
+| Some thing -> thing
+
+exception EmptyList
+
+let rec last_element = function
+ | [] -> raise EmptyList
+ | e :: [] -> e
+ | e' :: e :: l -> last_element (e::l)
+
+let dfs code entrypoint =
+ let visited = ref (PTree.map (fun n i -> false) code) in
+ let rec dfs_list code = function
+ | [] -> []
+ | node :: ln ->
+ let node_dfs =
+ if not (get_some @@ PTree.get node !visited) then begin
+ visited := PTree.set node true !visited;
+ match PTree.get node code with
+ | None -> failwith "No such node"
+ | Some bb -> [node] @ match (last_element bb) with
+ | Lop _ | Lload _ | Lgetstack _ | Lsetstack _ | Lstore _ | Lcall _
+ | Lbuiltin _ -> assert false
+ | Ltailcall _ | Lreturn -> []
+ | Lbranch n -> dfs_list code [n]
+ | Lcond (_, _, ifso, ifnot) -> dfs_list code [ifnot; ifso]
+ | Ljumptable(_, ln) -> dfs_list code ln
+ end
+ else []
+ in node_dfs @ (dfs_list code ln)
+ in dfs_list code [entrypoint]
+
+let enumerate_aux_trace f reach = dfs f.fn_code f.fn_entrypoint
+
+let enumerate_aux f reach =
+ if !Clflags.option_ftracelinearize then enumerate_aux_trace f reach
+ else enumerate_aux_flat f reach
diff --git a/backend/Linearizeproof.v b/backend/Linearizeproof.v
index 10a3d8b2..18dc52a5 100644
--- a/backend/Linearizeproof.v
+++ b/backend/Linearizeproof.v
@@ -585,45 +585,61 @@ Proof.
intros; eapply reachable_successors; eauto.
eapply is_tail_lin_block; eauto. eapply is_tail_find_label; eauto.
- (* Lop *)
+- (* Lop *)
left; econstructor; split. simpl.
apply plus_one. econstructor; eauto.
instantiate (1 := v); rewrite <- H; apply eval_operation_preserved.
exact symbols_preserved.
econstructor; eauto.
- (* Lload *)
+- (* Lload *)
left; econstructor; split. simpl.
- apply plus_one. econstructor.
+ apply plus_one. eapply exec_Lload.
instantiate (1 := a). rewrite <- H; apply eval_addressing_preserved.
exact symbols_preserved. eauto. eauto.
econstructor; eauto.
- (* Lgetstack *)
+- (* Lload notrap1 *)
+ left; econstructor; split. simpl.
+ apply plus_one. eapply exec_Lload_notrap1.
+ rewrite <- H.
+ apply eval_addressing_preserved.
+ exact symbols_preserved. eauto.
+ econstructor; eauto.
+
+- (* Lload notrap2 *)
+ left; econstructor; split. simpl.
+ apply plus_one. eapply exec_Lload_notrap2.
+ rewrite <- H.
+ apply eval_addressing_preserved.
+ exact symbols_preserved. eauto. eauto.
+ econstructor; eauto.
+
+- (* Lgetstack *)
left; econstructor; split. simpl.
apply plus_one. econstructor; eauto.
econstructor; eauto.
- (* Lsetstack *)
+- (* Lsetstack *)
left; econstructor; split. simpl.
apply plus_one. econstructor; eauto.
econstructor; eauto.
- (* Lstore *)
+- (* Lstore *)
left; econstructor; split. simpl.
apply plus_one. econstructor.
instantiate (1 := a). rewrite <- H; apply eval_addressing_preserved.
exact symbols_preserved. eauto. eauto.
econstructor; eauto.
- (* Lcall *)
+- (* Lcall *)
exploit find_function_translated; eauto. intros [tfd [A B]].
left; econstructor; split. simpl.
apply plus_one. econstructor; eauto.
symmetry; eapply sig_preserved; eauto.
econstructor; eauto. constructor; auto. econstructor; eauto.
- (* Ltailcall *)
+- (* Ltailcall *)
exploit find_function_translated; eauto. intros [tfd [A B]].
left; econstructor; split. simpl.
apply plus_one. econstructor; eauto.
@@ -633,18 +649,18 @@ Proof.
rewrite (match_parent_locset _ _ STACKS).
econstructor; eauto.
- (* Lbuiltin *)
+- (* Lbuiltin *)
left; econstructor; split. simpl.
apply plus_one. eapply exec_Lbuiltin; eauto.
eapply eval_builtin_args_preserved with (ge1 := ge); eauto. exact symbols_preserved.
eapply external_call_symbols_preserved; eauto. apply senv_preserved.
econstructor; eauto.
- (* Lbranch *)
+- (* Lbranch *)
assert ((reachable f)!!pc = true). apply REACH; simpl; auto.
right; split. simpl; omega. split. auto. simpl. econstructor; eauto.
- (* Lcond *)
+- (* Lcond *)
assert (REACH1: (reachable f)!!pc1 = true) by (apply REACH; simpl; auto).
assert (REACH2: (reachable f)!!pc2 = true) by (apply REACH; simpl; auto).
simpl linearize_block.
@@ -670,18 +686,18 @@ Proof.
apply plus_one. eapply exec_Lcond_false. eauto. eauto.
econstructor; eauto.
- (* Ljumptable *)
+- (* Ljumptable *)
assert (REACH': (reachable f)!!pc = true).
apply REACH. simpl. eapply list_nth_z_in; eauto.
right; split. simpl; omega. split. auto. econstructor; eauto.
- (* Lreturn *)
+- (* Lreturn *)
left; econstructor; split.
simpl. apply plus_one. econstructor; eauto.
rewrite (stacksize_preserved _ _ TRF). eauto.
rewrite (match_parent_locset _ _ STACKS). econstructor; eauto.
- (* internal functions *)
+- (* internal functions *)
assert (REACH: (reachable f)!!(LTL.fn_entrypoint f) = true).
apply reachable_entrypoint.
monadInv H7.
@@ -691,13 +707,13 @@ Proof.
generalize EQ; intro EQ'; monadInv EQ'. simpl.
econstructor; eauto. simpl. eapply is_tail_add_branch. constructor.
- (* external function *)
+- (* external function *)
monadInv H8. left; econstructor; split.
apply plus_one. eapply exec_function_external; eauto.
eapply external_call_symbols_preserved; eauto. apply senv_preserved.
econstructor; eauto.
- (* return *)
+- (* return *)
inv H3. inv H1.
left; econstructor; split.
apply plus_one. econstructor.
diff --git a/backend/Lineartyping.v b/backend/Lineartyping.v
index 0e3b7c8e..3fe61470 100644
--- a/backend/Lineartyping.v
+++ b/backend/Lineartyping.v
@@ -76,7 +76,7 @@ Definition wt_instr (i: instruction) : bool :=
let (targs, tres) := type_of_operation op in
subtype tres (mreg_type res)
end
- | Lload chunk addr args dst =>
+ | Lload trap chunk addr args dst =>
subtype (type_of_chunk chunk) (mreg_type dst)
| Ltailcall sg ros =>
zeq (size_arguments sg) 0
@@ -321,17 +321,34 @@ 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.
- apply wt_undef_regs; auto.
+ (* no longer needed apply wt_undef_regs; auto. *)
- (* load *)
simpl in *; InvBooleans.
econstructor; eauto.
apply wt_setreg. eapply Val.has_subtype; eauto.
destruct a; simpl in H0; try discriminate. eapply Mem.load_type; eauto.
apply wt_undef_regs; auto.
+- (* load notrap1 *)
+ simpl in *; InvBooleans.
+ econstructor; eauto.
+ apply wt_setreg. eapply Val.has_subtype; eauto.
+ unfold default_notrap_load_value.
+ constructor.
+ apply wt_undef_regs; auto.
+- (* load notrap2 *)
+ simpl in *; InvBooleans.
+ econstructor; eauto.
+ apply wt_setreg. eapply Val.has_subtype; eauto.
+ unfold default_notrap_load_value.
+ constructor.
+ apply wt_undef_regs; auto.
- (* store *)
simpl in *; InvBooleans.
econstructor. eauto. eauto. eauto.
diff --git a/backend/Liveness.v b/backend/Liveness.v
index 16533158..afe11ae6 100644
--- a/backend/Liveness.v
+++ b/backend/Liveness.v
@@ -79,7 +79,7 @@ Definition transfer
reg_list_live args (reg_dead res after)
else
after
- | Iload chunk addr args dst s =>
+ | Iload trap chunk addr args dst s =>
if Regset.mem dst after then
reg_list_live args (reg_dead dst after)
else
diff --git a/backend/Mach.v b/backend/Mach.v
index 9fdee9eb..1c6fdb18 100644
--- a/backend/Mach.v
+++ b/backend/Mach.v
@@ -56,7 +56,7 @@ Inductive instruction: Type :=
| Msetstack: mreg -> ptrofs -> typ -> instruction
| Mgetparam: ptrofs -> typ -> mreg -> instruction
| Mop: operation -> list mreg -> mreg -> instruction
- | Mload: memory_chunk -> addressing -> list mreg -> mreg -> instruction
+ | Mload: trapping_mode -> memory_chunk -> addressing -> list mreg -> mreg -> instruction
| Mstore: memory_chunk -> addressing -> list mreg -> mreg -> instruction
| Mcall: signature -> mreg + ident -> instruction
| Mtailcall: signature -> mreg + ident -> instruction
@@ -321,11 +321,24 @@ Inductive step: state -> trace -> state -> Prop :=
step (State s f sp (Mop op args res :: c) rs m)
E0 (State s f sp c rs' m)
| exec_Mload:
- forall s f sp chunk addr args dst c rs m a v rs',
+ forall s f sp trap chunk addr args dst c rs m a v rs',
eval_addressing ge sp addr rs##args = Some a ->
Mem.loadv chunk m a = Some v ->
rs' = ((undef_regs (destroyed_by_load chunk addr) rs)#dst <- v) ->
- step (State s f sp (Mload chunk addr args dst :: c) rs m)
+ step (State s f sp (Mload trap chunk addr args dst :: c) rs m)
+ E0 (State s f sp c rs' m)
+ | exec_Mload_notrap1:
+ forall s f sp chunk addr args dst c rs m rs',
+ eval_addressing ge sp addr rs##args = None ->
+ rs' = ((undef_regs (destroyed_by_load chunk addr) rs)#dst <- (default_notrap_load_value chunk)) ->
+ step (State s f sp (Mload NOTRAP chunk addr args dst :: c) rs m)
+ E0 (State s f sp c rs' m)
+ | exec_Mload_notrap2:
+ forall s f sp chunk addr args dst c rs m a rs',
+ eval_addressing ge sp addr rs##args = Some a ->
+ Mem.loadv chunk m a = None ->
+ rs' = ((undef_regs (destroyed_by_load chunk addr) rs)#dst <- (default_notrap_load_value chunk)) ->
+ step (State s f sp (Mload NOTRAP chunk addr args dst :: c) rs m)
E0 (State s f sp c rs' m)
| exec_Mstore:
forall s f sp chunk addr args src c rs m m' a rs',
diff --git a/backend/OpHelpers.v b/backend/OpHelpers.v
new file mode 100644
index 00000000..b9b97903
--- /dev/null
+++ b/backend/OpHelpers.v
@@ -0,0 +1,42 @@
+Require Import Coqlib.
+Require Import AST Integers Floats.
+Require Import Op CminorSel.
+
+(** Some arithmetic operations are transformed into calls to
+ runtime library functions. The following type class collects
+ the names of these functions. *)
+
+Definition sig_l_l := mksignature (Tlong :: nil) Tlong cc_default.
+Definition sig_l_f := mksignature (Tlong :: nil) Tfloat cc_default.
+Definition sig_l_s := mksignature (Tlong :: nil) Tsingle cc_default.
+Definition sig_f_l := mksignature (Tfloat :: nil) Tlong cc_default.
+Definition sig_ll_l := mksignature (Tlong :: Tlong :: nil) Tlong cc_default.
+Definition sig_li_l := mksignature (Tlong :: Tint :: nil) Tlong cc_default.
+Definition sig_ii_l := mksignature (Tint :: Tint :: nil) Tlong cc_default.
+Definition sig_ii_i := mksignature (Tint :: Tint :: nil) Tint cc_default.
+Definition sig_ff_f := mksignature (Tfloat :: Tfloat :: nil) Tfloat cc_default.
+Definition sig_ss_s := mksignature (Tsingle :: Tsingle :: nil) Tsingle cc_default.
+
+Class helper_functions := mk_helper_functions {
+ i64_dtos: ident; (**r float64 -> signed long *)
+ i64_dtou: ident; (**r float64 -> unsigned long *)
+ i64_stod: ident; (**r signed long -> float64 *)
+ i64_utod: ident; (**r unsigned long -> float64 *)
+ i64_stof: ident; (**r signed long -> float32 *)
+ i64_utof: ident; (**r unsigned long -> float32 *)
+ i64_sdiv: ident; (**r signed division *)
+ i64_udiv: ident; (**r unsigned division *)
+ i64_smod: ident; (**r signed remainder *)
+ i64_umod: ident; (**r unsigned remainder *)
+ i64_shl: ident; (**r shift left *)
+ i64_shr: ident; (**r shift right unsigned *)
+ i64_sar: ident; (**r shift right signed *)
+ i64_umulh: ident; (**r unsigned multiply high *)
+ i64_smulh: ident; (**r signed multiply high *)
+ i32_sdiv: ident; (**r signed division *)
+ i32_udiv: ident; (**r unsigned division *)
+ i32_smod: ident; (**r signed remainder *)
+ i32_umod: ident; (**r unsigned remainder *)
+ f64_div: ident; (**float division*)
+ f32_div: ident; (**float division*)
+}.
diff --git a/backend/OpHelpersproof.v b/backend/OpHelpersproof.v
new file mode 100644
index 00000000..08da8a36
--- /dev/null
+++ b/backend/OpHelpersproof.v
@@ -0,0 +1,78 @@
+Require Import Coqlib.
+Require Import Maps.
+Require Import AST.
+Require Import Integers.
+Require Import Floats.
+Require Import Values.
+Require Import Memory.
+Require Import Globalenvs.
+Require Import Cminor.
+Require Import Op.
+Require Import CminorSel.
+Require Import Events.
+Require Import OpHelpers.
+
+(** * Axiomatization of the helper functions *)
+
+Definition external_implements (name: string) (sg: signature) (vargs: list val) (vres: val) : Prop :=
+ forall F V (ge: Genv.t F V) m,
+ external_call (EF_runtime name sg) ge vargs m E0 vres m.
+
+Definition builtin_implements (name: string) (sg: signature) (vargs: list val) (vres: val) : Prop :=
+ forall F V (ge: Genv.t F V) m,
+ external_call (EF_builtin name sg) ge vargs m E0 vres m.
+
+Axiom arith_helpers_correct :
+ (forall x z, Val.longoffloat x = Some z -> external_implements "__compcert_i64_dtos" sig_f_l (x::nil) z)
+ /\ (forall x z, Val.longuoffloat x = Some z -> external_implements "__compcert_i64_dtou" sig_f_l (x::nil) z)
+ /\ (forall x z, Val.floatoflong x = Some z -> external_implements "__compcert_i64_stod" sig_l_f (x::nil) z)
+ /\ (forall x z, Val.floatoflongu x = Some z -> external_implements "__compcert_i64_utod" sig_l_f (x::nil) z)
+ /\ (forall x z, Val.singleoflong x = Some z -> external_implements "__compcert_i64_stof" sig_l_s (x::nil) z)
+ /\ (forall x z, Val.singleoflongu x = Some z -> external_implements "__compcert_i64_utof" sig_l_s (x::nil) z)
+ /\ (forall x, builtin_implements "__builtin_negl" sig_l_l (x::nil) (Val.negl x))
+ /\ (forall x y, builtin_implements "__builtin_addl" sig_ll_l (x::y::nil) (Val.addl x y))
+ /\ (forall x y, builtin_implements "__builtin_subl" sig_ll_l (x::y::nil) (Val.subl x y))
+ /\ (forall x y, builtin_implements "__builtin_mull" sig_ii_l (x::y::nil) (Val.mull' x y))
+ /\ (forall x y z, Val.divls x y = Some z -> external_implements "__compcert_i64_sdiv" sig_ll_l (x::y::nil) z)
+ /\ (forall x y z, Val.divlu x y = Some z -> external_implements "__compcert_i64_udiv" sig_ll_l (x::y::nil) z)
+ /\ (forall x y z, Val.modls x y = Some z -> external_implements "__compcert_i64_smod" sig_ll_l (x::y::nil) z)
+ /\ (forall x y z, Val.modlu x y = Some z -> external_implements "__compcert_i64_umod" sig_ll_l (x::y::nil) z)
+ /\ (forall x y, external_implements "__compcert_i64_shl" sig_li_l (x::y::nil) (Val.shll x y))
+ /\ (forall x y, external_implements "__compcert_i64_shr" sig_li_l (x::y::nil) (Val.shrlu x y))
+ /\ (forall x y, external_implements "__compcert_i64_sar" sig_li_l (x::y::nil) (Val.shrl x y))
+ /\ (forall x y, external_implements "__compcert_i64_umulh" sig_ll_l (x::y::nil) (Val.mullhu x y))
+ /\ (forall x y, external_implements "__compcert_i64_smulh" sig_ll_l (x::y::nil) (Val.mullhs x y))
+ /\ (forall x y z, Val.divs x y = Some z -> external_implements "__compcert_i32_sdiv" sig_ii_i (x::y::nil) z)
+ /\ (forall x y z, Val.divu x y = Some z -> external_implements "__compcert_i32_udiv" sig_ii_i (x::y::nil) z)
+ /\ (forall x y z, Val.mods x y = Some z -> external_implements "__compcert_i32_smod" sig_ii_i (x::y::nil) z)
+ /\ (forall x y z, Val.modu x y = Some z -> external_implements "__compcert_i32_umod" sig_ii_i (x::y::nil) z)
+ /\ (forall x y z, Val.divfs x y = z -> external_implements "__compcert_f32_div" sig_ss_s (x::y::nil) z)
+ /\ (forall x y z, Val.divf x y = z -> external_implements "__compcert_f64_div" sig_ff_f (x::y::nil) z)
+.
+
+Definition helper_declared {F V: Type} (p: AST.program (AST.fundef F) V) (id: ident) (name: string) (sg: signature) : Prop :=
+ (prog_defmap p)!id = Some (Gfun (External (EF_runtime name sg))).
+
+Definition helper_functions_declared {F V: Type} (p: AST.program (AST.fundef F) V) (hf: helper_functions) : Prop :=
+ helper_declared p i64_dtos "__compcert_i64_dtos" sig_f_l
+ /\ helper_declared p i64_dtou "__compcert_i64_dtou" sig_f_l
+ /\ helper_declared p i64_stod "__compcert_i64_stod" sig_l_f
+ /\ helper_declared p i64_utod "__compcert_i64_utod" sig_l_f
+ /\ helper_declared p i64_stof "__compcert_i64_stof" sig_l_s
+ /\ helper_declared p i64_utof "__compcert_i64_utof" sig_l_s
+ /\ helper_declared p i64_sdiv "__compcert_i64_sdiv" sig_ll_l
+ /\ helper_declared p i64_udiv "__compcert_i64_udiv" sig_ll_l
+ /\ helper_declared p i64_smod "__compcert_i64_smod" sig_ll_l
+ /\ helper_declared p i64_umod "__compcert_i64_umod" sig_ll_l
+ /\ helper_declared p i64_shl "__compcert_i64_shl" sig_li_l
+ /\ helper_declared p i64_shr "__compcert_i64_shr" sig_li_l
+ /\ helper_declared p i64_sar "__compcert_i64_sar" sig_li_l
+ /\ helper_declared p i64_umulh "__compcert_i64_umulh" sig_ll_l
+ /\ helper_declared p i64_smulh "__compcert_i64_smulh" sig_ll_l
+ /\ helper_declared p i32_sdiv "__compcert_i32_sdiv" sig_ii_i
+ /\ helper_declared p i32_udiv "__compcert_i32_udiv" sig_ii_i
+ /\ helper_declared p i32_smod "__compcert_i32_smod" sig_ii_i
+ /\ helper_declared p i32_umod "__compcert_i32_umod" sig_ii_i
+ /\ helper_declared p f32_div "__compcert_f32_div" sig_ss_s
+ /\ helper_declared p f64_div "__compcert_f64_div" sig_ff_f
+. \ No newline at end of file
diff --git a/backend/PrintLTL.ml b/backend/PrintLTL.ml
index 1c449e74..b309a9f2 100644
--- a/backend/PrintLTL.ml
+++ b/backend/PrintLTL.ml
@@ -61,9 +61,10 @@ let print_succ pp s dfl =
let print_instruction pp succ = function
| Lop(op, args, res) ->
fprintf pp "%a = %a" mreg res (print_operation mreg) (op, args)
- | Lload(chunk, addr, args, dst) ->
- fprintf pp "%a = %s[%a]"
- mreg dst (name_of_chunk chunk) (print_addressing mreg) (addr, args)
+ | Lload(trap,chunk, addr, args, dst) ->
+ fprintf pp "%a = %s[%a]%a"
+ mreg dst (name_of_chunk chunk) (print_addressing mreg) (addr, args)
+ print_trapping_mode trap
| Lgetstack(sl, ofs, ty, dst) ->
fprintf pp "%a = %a" mreg dst slot (sl, ofs, ty)
| Lsetstack(src, sl, ofs, ty) ->
diff --git a/backend/PrintMach.ml b/backend/PrintMach.ml
index 517f3037..70e65832 100644
--- a/backend/PrintMach.ml
+++ b/backend/PrintMach.ml
@@ -48,10 +48,11 @@ let print_instruction pp i =
| Mop(op, args, res) ->
fprintf pp "\t%a = %a\n"
reg res (PrintOp.print_operation reg) (op, args)
- | Mload(chunk, addr, args, dst) ->
- fprintf pp "\t%a = %s[%a]\n"
+ | Mload(trap, chunk, addr, args, dst) ->
+ fprintf pp "\t%a = %s[%a]%a\n"
reg dst (name_of_chunk chunk)
(PrintOp.print_addressing reg) (addr, args)
+ print_trapping_mode trap
| Mstore(chunk, addr, args, src) ->
fprintf pp "\t%s[%a] = %a\n"
(name_of_chunk chunk)
diff --git a/backend/PrintRTL.ml b/backend/PrintRTL.ml
index 841540b6..c25773e5 100644
--- a/backend/PrintRTL.ml
+++ b/backend/PrintRTL.ml
@@ -50,10 +50,11 @@ let print_instruction pp (pc, i) =
fprintf pp "%a = %a\n"
reg res (PrintOp.print_operation reg) (op, args);
print_succ pp s (pc - 1)
- | Iload(chunk, addr, args, dst, s) ->
- fprintf pp "%a = %s[%a]\n"
+ | Iload(trap, chunk, addr, args, dst, s) ->
+ fprintf pp "%a = %s[%a]%a\n"
reg dst (name_of_chunk chunk)
- (PrintOp.print_addressing reg) (addr, args);
+ (PrintOp.print_addressing reg) (addr, args)
+ print_trapping_mode trap;
print_succ pp s (pc - 1)
| Istore(chunk, addr, args, src, s) ->
fprintf pp "%s[%a] = %a\n"
diff --git a/backend/PrintXTL.ml b/backend/PrintXTL.ml
index 6432682a..1c7655fb 100644
--- a/backend/PrintXTL.ml
+++ b/backend/PrintXTL.ml
@@ -86,9 +86,10 @@ let print_instruction pp succ = function
fprintf pp "(%a) = (%a) using %a, %a" vars dsts vars srcs var t1 var t2
| Xop(op, args, res) ->
fprintf pp "%a = %a" var res (print_operation var) (op, args)
- | Xload(chunk, addr, args, dst) ->
- fprintf pp "%a = %s[%a]"
- var dst (name_of_chunk chunk) (print_addressing var) (addr, args)
+ | Xload(trap, chunk, addr, args, dst) ->
+ fprintf pp "%a = %s[%a]%a"
+ var dst (name_of_chunk chunk) (print_addressing var) (addr, args)
+ print_trapping_mode trap
| Xstore(chunk, addr, args, src) ->
fprintf pp "%s[%a] = %a"
(name_of_chunk chunk) (print_addressing var) (addr, args) var src
diff --git a/backend/RTL.v b/backend/RTL.v
index 9599a24a..29a49311 100644
--- a/backend/RTL.v
+++ b/backend/RTL.v
@@ -43,11 +43,12 @@ Inductive instruction: Type :=
(** [Iop op args dest succ] performs the arithmetic operation [op]
over the values of registers [args], stores the result in [dest],
and branches to [succ]. *)
- | Iload: memory_chunk -> addressing -> list reg -> reg -> node -> instruction
- (** [Iload chunk addr args dest succ] loads a [chunk] quantity from
+ | Iload: trapping_mode -> memory_chunk -> addressing -> list reg -> reg -> node -> instruction
+ (** [Iload trap chunk addr args dest succ] loads a [chunk] quantity from
the address determined by the addressing mode [addr] and the
values of the [args] registers, stores the quantity just read
- into [dest], and branches to [succ]. *)
+ into [dest], and branches to [succ].
+ If trap=NOTRAP, then failures lead to a default value written to [dest]. *)
| Istore: memory_chunk -> addressing -> list reg -> reg -> node -> instruction
(** [Istore chunk addr args src succ] stores the value of register
[src] in the [chunk] quantity at the
@@ -212,12 +213,25 @@ Inductive step: state -> trace -> state -> Prop :=
step (State s f sp pc rs m)
E0 (State s f sp pc' (rs#res <- v) m)
| exec_Iload:
- forall s f sp pc rs m chunk addr args dst pc' a v,
- (fn_code f)!pc = Some(Iload chunk addr args dst pc') ->
+ forall s f sp pc rs m trap chunk addr args dst pc' a v,
+ (fn_code f)!pc = Some(Iload trap chunk addr args dst pc') ->
eval_addressing ge sp addr rs##args = Some a ->
Mem.loadv chunk m a = Some v ->
step (State s f sp pc rs m)
E0 (State s f sp pc' (rs#dst <- v) m)
+ | exec_Iload_notrap1:
+ forall s f sp pc rs m chunk addr args dst pc',
+ (fn_code f)!pc = Some(Iload NOTRAP chunk addr args dst pc') ->
+ eval_addressing ge sp addr rs##args = None ->
+ step (State s f sp pc rs m)
+ E0 (State s f sp pc' (rs#dst <- (default_notrap_load_value chunk)) m)
+ | exec_Iload_notrap2:
+ forall s f sp pc rs m chunk addr args dst pc' a,
+ (fn_code f)!pc = Some(Iload NOTRAP chunk addr args dst pc') ->
+ eval_addressing ge sp addr rs##args = Some a ->
+ Mem.loadv chunk m a = None->
+ step (State s f sp pc rs m)
+ E0 (State s f sp pc' (rs#dst <- (default_notrap_load_value chunk)) m)
| exec_Istore:
forall s f sp pc rs m chunk addr args src pc' a m',
(fn_code f)!pc = Some(Istore chunk addr args src pc') ->
@@ -299,8 +313,8 @@ Proof.
Qed.
Lemma exec_Iload':
- forall s f sp pc rs m chunk addr args dst pc' rs' a v,
- (fn_code f)!pc = Some(Iload chunk addr args dst pc') ->
+ forall s f sp pc rs m trap chunk addr args dst pc' rs' a v,
+ (fn_code f)!pc = Some(Iload trap chunk addr args dst pc') ->
eval_addressing ge sp addr rs##args = Some a ->
Mem.loadv chunk m a = Some v ->
rs' = (rs#dst <- v) ->
@@ -384,7 +398,7 @@ Definition successors_instr (i: instruction) : list node :=
match i with
| Inop s => s :: nil
| Iop op args res s => s :: nil
- | Iload chunk addr args dst s => s :: nil
+ | Iload trap chunk addr args dst s => s :: nil
| Istore chunk addr args src s => s :: nil
| Icall sig ros args res s => s :: nil
| Itailcall sig ros args => nil
@@ -403,7 +417,7 @@ Definition instr_uses (i: instruction) : list reg :=
match i with
| Inop s => nil
| Iop op args res s => args
- | Iload chunk addr args dst s => args
+ | Iload trap chunk addr args dst s => args
| Istore chunk addr args src s => src :: args
| Icall sig (inl r) args res s => r :: args
| Icall sig (inr id) args res s => args
@@ -422,7 +436,7 @@ Definition instr_defs (i: instruction) : option reg :=
match i with
| Inop s => None
| Iop op args res s => Some res
- | Iload chunk addr args dst s => Some dst
+ | Iload trap chunk addr args dst s => Some dst
| Istore chunk addr args src s => None
| Icall sig ros args res s => Some res
| Itailcall sig ros args => None
@@ -462,7 +476,7 @@ Definition max_reg_instr (m: positive) (pc: node) (i: instruction) :=
match i with
| Inop s => m
| Iop op args res s => fold_left Pos.max args (Pos.max res m)
- | Iload chunk addr args dst s => fold_left Pos.max args (Pos.max dst m)
+ | Iload trap chunk addr args dst s => fold_left Pos.max args (Pos.max dst m)
| Istore chunk addr args src s => fold_left Pos.max args (Pos.max src m)
| Icall sig (inl r) args res s => fold_left Pos.max args (Pos.max r (Pos.max res m))
| Icall sig (inr id) args res s => fold_left Pos.max args (Pos.max res m)
diff --git a/backend/RTLgen.v b/backend/RTLgen.v
index f7280c9e..2c27944a 100644
--- a/backend/RTLgen.v
+++ b/backend/RTLgen.v
@@ -435,7 +435,7 @@ Fixpoint transl_expr (map: mapping) (a: expr) (rd: reg) (nd: node)
transl_exprlist map al rl no
| Eload chunk addr al =>
do rl <- alloc_regs map al;
- do no <- add_instr (Iload chunk addr rl rd nd);
+ do no <- add_instr (Iload TRAP chunk addr rl rd nd);
transl_exprlist map al rl no
| Econdition a b c =>
do nfalse <- transl_expr map c rd nd;
diff --git a/backend/RTLgenspec.v b/backend/RTLgenspec.v
index 72693f63..92b48e2b 100644
--- a/backend/RTLgenspec.v
+++ b/backend/RTLgenspec.v
@@ -707,7 +707,7 @@ Inductive tr_expr (c: code):
tr_expr c map pr (Eop op al) ns nd rd dst
| tr_Eload: forall map pr chunk addr al ns nd rd n1 rl dst,
tr_exprlist c map pr al ns n1 rl ->
- c!n1 = Some (Iload chunk addr rl rd nd) ->
+ c!n1 = Some (Iload TRAP chunk addr rl rd nd) ->
reg_map_ok map rd dst -> ~In rd pr ->
tr_expr c map pr (Eload chunk addr al) ns nd rd dst
| tr_Econdition: forall map pr a ifso ifnot ns nd rd ntrue nfalse dst,
diff --git a/backend/RTLtyping.v b/backend/RTLtyping.v
index 5b8646ea..857f2211 100644
--- a/backend/RTLtyping.v
+++ b/backend/RTLtyping.v
@@ -104,11 +104,11 @@ Inductive wt_instr : instruction -> Prop :=
valid_successor s ->
wt_instr (Iop op args res s)
| wt_Iload:
- forall chunk addr args dst s,
+ forall trap chunk addr args dst s,
map env args = type_of_addressing addr ->
env dst = type_of_chunk chunk ->
valid_successor s ->
- wt_instr (Iload chunk addr args dst s)
+ wt_instr (Iload trap chunk addr args dst s)
| wt_Istore:
forall chunk addr args src s,
map env args = type_of_addressing addr ->
@@ -283,7 +283,7 @@ Definition type_instr (e: S.typenv) (i: instruction) : res S.typenv :=
else
(let (targs, tres) := type_of_operation op in
do e1 <- S.set_list e args targs; S.set e1 res tres)
- | Iload chunk addr args dst s =>
+ | Iload trap chunk addr args dst s =>
do x <- check_successor s;
do e1 <- S.set_list e args (type_of_addressing addr);
S.set e1 dst (type_of_chunk chunk)
@@ -844,14 +844,24 @@ Proof.
Qed.
Lemma wt_exec_Iload:
- forall env f chunk addr args dst s m a v rs,
- wt_instr f env (Iload chunk addr args dst s) ->
+ forall env f trap chunk addr args dst s m a v rs,
+ wt_instr f env (Iload trap chunk addr args dst s) ->
Mem.loadv chunk m a = Some v ->
wt_regset env rs ->
wt_regset env (rs#dst <- v).
Proof.
intros. destruct a; simpl in H0; try discriminate. inv H.
- eapply wt_regset_assign; eauto. rewrite H8; eapply Mem.load_type; eauto.
+ eapply wt_regset_assign; eauto. rewrite H9; eapply Mem.load_type; eauto.
+Qed.
+
+Lemma wt_exec_Iload_notrap:
+ forall env f chunk addr args dst s rs,
+ wt_instr f env (Iload NOTRAP chunk addr args dst s) ->
+ wt_regset env rs ->
+ wt_regset env (rs#dst <- (default_notrap_load_value chunk)).
+Proof.
+ intros.
+ eapply wt_regset_assign; eauto. simpl. trivial.
Qed.
Lemma wt_exec_Ibuiltin:
@@ -933,6 +943,10 @@ Proof.
econstructor; eauto. eapply wt_exec_Iop; eauto.
(* Iload *)
econstructor; eauto. eapply wt_exec_Iload; eauto.
+ (* Iload notrap1*)
+ econstructor; eauto. eapply wt_exec_Iload_notrap; eauto.
+ (* Iload notrap2*)
+ econstructor; eauto. eapply wt_exec_Iload_notrap; eauto.
(* Istore *)
econstructor; eauto.
(* Icall *)
diff --git a/backend/Regalloc.ml b/backend/Regalloc.ml
index 19aba4f6..f2658b04 100644
--- a/backend/Regalloc.ml
+++ b/backend/Regalloc.ml
@@ -249,18 +249,18 @@ let block_of_RTL_instr funsig tyenv = function
else
let t = new_temp (tyenv res) in (t :: args2', t) in
movelist args1 args3 (Xop(op, args3, res3) :: move res3 res1 [Xbranch s])
- | RTL.Iload(chunk, addr, args, dst, s) ->
+ | RTL.Iload(trap, chunk, addr, args, dst, s) ->
if Archi.splitlong && chunk = Mint64 then begin
match offset_addressing addr (coqint_of_camlint 4l) with
| None -> assert false
| Some addr' ->
- [Xload(Mint32, addr, vregs tyenv args,
+ [Xload(trap, Mint32, addr, vregs tyenv args,
V((if Archi.big_endian then dst else twin_reg dst), Tint));
- Xload(Mint32, addr', vregs tyenv args,
+ Xload(trap, Mint32, addr', vregs tyenv args,
V((if Archi.big_endian then twin_reg dst else dst), Tint));
Xbranch s]
end else
- [Xload(chunk, addr, vregs tyenv args, vreg tyenv dst); Xbranch s]
+ [Xload(trap, chunk, addr, vregs tyenv args, vreg tyenv dst); Xbranch s]
| RTL.Istore(chunk, addr, args, src, s) ->
if Archi.splitlong && chunk = Mint64 then begin
match offset_addressing addr (coqint_of_camlint 4l) with
@@ -364,7 +364,7 @@ let live_before instr after =
if VSet.mem res after
then vset_addlist args (VSet.remove res after)
else after
- | Xload(chunk, addr, args, dst) ->
+ | Xload(trap, chunk, addr, args, dst) ->
if VSet.mem dst after
then vset_addlist args (VSet.remove dst after)
else after
@@ -459,7 +459,7 @@ let dce_instr instr after k =
if VSet.mem res after
then instr :: k
else k
- | Xload(chunk, addr, args, dst) ->
+ | Xload(trap, chunk, addr, args, dst) ->
if VSet.mem dst after
then instr :: k
else k
@@ -550,7 +550,7 @@ let spill_costs f =
(* temps must not be spilled *)
| Xop(op, args, res) ->
charge_list 10 1 args; charge 10 1 res
- | Xload(chunk, addr, args, dst) ->
+ | Xload(trap, chunk, addr, args, dst) ->
charge_list 10 1 args; charge 10 1 dst
| Xstore(chunk, addr, args, src) ->
charge_list 10 1 args; charge 10 1 src
@@ -677,7 +677,7 @@ let add_interfs_instr g instr live =
(vset_addlist (res :: argl) (VSet.remove res live))
end;
add_interfs_destroyed g (VSet.remove res live) (destroyed_by_op op)
- | Xload(chunk, addr, args, dst) ->
+ | Xload(trap, chunk, addr, args, dst) ->
add_interfs_def g dst live;
add_interfs_destroyed g (VSet.remove dst live)
(destroyed_by_load chunk addr)
@@ -782,7 +782,7 @@ let tospill_instr alloc instr ts =
ts
| Xop(op, args, res) ->
addlist_tospill alloc args (add_tospill alloc res ts)
- | Xload(chunk, addr, args, dst) ->
+ | Xload(trap, chunk, addr, args, dst) ->
addlist_tospill alloc args (add_tospill alloc dst ts)
| Xstore(chunk, addr, args, src) ->
addlist_tospill alloc args (add_tospill alloc src ts)
@@ -964,10 +964,10 @@ let spill_instr tospill eqs instr =
add res tmp (kill tmp (kill res eqs2)))
end
end
- | Xload(chunk, addr, args, dst) ->
+ | Xload(trap, chunk, addr, args, dst) ->
let (args', c1, eqs1) = reload_vars tospill eqs args in
let (dst', c2, eqs2) = save_var tospill eqs1 dst in
- (c1 @ Xload(chunk, addr, args', dst') :: c2, eqs2)
+ (c1 @ Xload(trap, chunk, addr, args', dst') :: c2, eqs2)
| Xstore(chunk, addr, args, src) ->
let (args', c1, eqs1) = reload_vars tospill eqs args in
let (src', c2, eqs2) = reload_var tospill eqs1 src in
@@ -1067,7 +1067,7 @@ let make_parmove srcs dsts itmp ftmp k =
| Locations.S(sl, ofs, ty), R rd ->
code := LTL.Lgetstack(sl, ofs, ty, rd) :: !code
| Locations.S(sls, ofss, tys), Locations.S(sld, ofsd, tyd) ->
- let tmp = temp_for (class_of_type tys) in
+ let tmp = temp_for (Machregsaux.class_of_type tys) in
(* code will be reversed at the end *)
code := LTL.Lsetstack(tmp, sld, ofsd, tyd) ::
LTL.Lgetstack(sls, ofss, tys, tmp) :: !code
@@ -1115,8 +1115,8 @@ let transl_instr alloc instr k =
LTL.Lop(Omove, [rarg1], rres) ::
LTL.Lop(op, rres :: rargl, rres) :: k
end
- | Xload(chunk, addr, args, dst) ->
- LTL.Lload(chunk, addr, mregs_of alloc args, mreg_of alloc dst) :: k
+ | Xload(trap, chunk, addr, args, dst) ->
+ LTL.Lload(trap, chunk, addr, mregs_of alloc args, mreg_of alloc dst) :: k
| Xstore(chunk, addr, args, src) ->
LTL.Lstore(chunk, addr, mregs_of alloc args, mreg_of alloc src) :: k
| Xcall(sg, vos, args, res) ->
diff --git a/backend/Renumber.v b/backend/Renumber.v
index 10f58251..7ba16658 100644
--- a/backend/Renumber.v
+++ b/backend/Renumber.v
@@ -43,7 +43,7 @@ Definition renum_instr (i: instruction) : instruction :=
match i with
| Inop s => Inop (renum_pc s)
| Iop op args res s => Iop op args res (renum_pc s)
- | Iload chunk addr args res s => Iload chunk addr args res (renum_pc s)
+ | Iload trap chunk addr args res s => Iload trap chunk addr args res (renum_pc s)
| Istore chunk addr args src s => Istore chunk addr args src (renum_pc s)
| Icall sg ros args res s => Icall sg ros args res (renum_pc s)
| Itailcall sg ros args => i
diff --git a/backend/Renumberproof.v b/backend/Renumberproof.v
index 7cda9425..2e161965 100644
--- a/backend/Renumberproof.v
+++ b/backend/Renumberproof.v
@@ -175,6 +175,18 @@ Proof.
rewrite <- H0. apply eval_addressing_preserved. exact symbols_preserved.
eapply exec_Iload; eauto.
constructor; auto. eapply reach_succ; eauto. simpl; auto.
+ (* load notrap1 *)
+ econstructor; split.
+ assert (eval_addressing tge sp addr rs ## args = None).
+ rewrite <- H0. apply eval_addressing_preserved. exact symbols_preserved.
+ eapply exec_Iload_notrap1; eauto.
+ constructor; auto. eapply reach_succ; eauto. simpl; auto.
+ (* load notrap2 *)
+ econstructor; split.
+ assert (eval_addressing tge sp addr rs ## args = Some a).
+ rewrite <- H0. apply eval_addressing_preserved. exact symbols_preserved.
+ eapply exec_Iload_notrap2; eauto.
+ constructor; auto. eapply reach_succ; eauto. simpl; auto.
(* store *)
econstructor; split.
assert (eval_addressing tge sp addr rs ## args = Some a).
diff --git a/backend/SelectDiv.vp b/backend/SelectDiv.vp
index d91797c5..9f852616 100644
--- a/backend/SelectDiv.vp
+++ b/backend/SelectDiv.vp
@@ -15,10 +15,13 @@
Require Import Coqlib.
Require Import Compopts.
Require Import AST Integers Floats.
-Require Import Op CminorSel SelectOp SplitLong SelectLong.
+Require Import Op CminorSel OpHelpers SelectOp SplitLong SelectLong.
Local Open Scope cminorsel_scope.
+Section SELECT.
+Context {hf: helper_functions}.
+
Definition is_intconst (e: expr) : option int :=
match e with
| Eop (Ointconst n) _ => Some n
@@ -221,10 +224,6 @@ Definition mods (e1: expr) (e2: expr) :=
(** 64-bit integer divisions *)
-Section SELECT.
-
-Context {hf: helper_functions}.
-
Definition modl_from_divl (equo: expr) (n: int64) :=
subl (Eletvar O) (mullimm n equo).
@@ -241,8 +240,8 @@ Definition divlu (e1 e2: expr) :=
divlu_base e1 e2
else
match divlu_mul_params (Int64.unsigned n2) with
- | None => divlu_base e1 e2
- | Some(p, m) => Elet e1 (divlu_mull p m)
+ | _ => divlu_base e1 e2
+ (* | Some(p, m) => Elet e1 (divlu_mull p m) *) (* FIXME - hack K1 *)
end
end
| _, _ => divlu_base e1 e2
@@ -258,8 +257,8 @@ Definition modlu (e1 e2: expr) :=
modlu_base e1 e2
else
match divlu_mul_params (Int64.unsigned n2) with
- | None => modlu_base e1 e2
- | Some(p, m) => Elet e1 (modl_from_divl (divlu_mull p m) n2)
+ | _ => modlu_base e1 e2
+ (* | Some(p, m) => Elet e1 (modl_from_divl (divlu_mull p m) n2) *) (* FIXME - hack K1 *)
end
end
| _, _ => modlu_base e1 e2
@@ -285,8 +284,8 @@ Definition divls (e1 e2: expr) :=
divls_base e1 e2
else
match divls_mul_params (Int64.signed n2) with
- | None => divls_base e1 e2
- | Some(p, m) => Elet e1 (divls_mull p m)
+ | _ => divls_base e1 e2
+ (* | Some(p, m) => Elet e1 (divls_mull p m) *) (* FIXME - hack K1 *)
end
end
| _, _ => divls_base e1 e2
@@ -304,40 +303,38 @@ Definition modls (e1 e2: expr) :=
modls_base e1 e2
else
match divls_mul_params (Int64.signed n2) with
- | None => modls_base e1 e2
- | Some(p, m) => Elet e1 (modl_from_divl (divls_mull p m) n2)
+ | _ => modls_base e1 e2
+ (* | Some(p, m) => Elet e1 (modl_from_divl (divls_mull p m) n2) *) (* FIXME - hack K1 *)
end
end
| _, _ => modls_base e1 e2
end.
-
-End SELECT.
-
+
(** Floating-point division by a constant can also be turned into a FP
multiplication by the inverse constant, but only for powers of 2. *)
Definition divfimm (e: expr) (n: float) :=
match Float.exact_inverse n with
| Some n' => Eop Omulf (e ::: Eop (Ofloatconst n') Enil ::: Enil)
- | None => Eop Odivf (e ::: Eop (Ofloatconst n) Enil ::: Enil)
+ | None => divf_base e (Eop (Ofloatconst n) Enil)
end.
Nondetfunction divf (e1: expr) (e2: expr) :=
match e2 with
| Eop (Ofloatconst n2) Enil => divfimm e1 n2
- | _ => Eop Odivf (e1 ::: e2 ::: Enil)
+ | _ => divf_base e1 e2
end.
Definition divfsimm (e: expr) (n: float32) :=
match Float32.exact_inverse n with
| Some n' => Eop Omulfs (e ::: Eop (Osingleconst n') Enil ::: Enil)
- | None => Eop Odivfs (e ::: Eop (Osingleconst n) Enil ::: Enil)
+ | None => divfs_base e (Eop (Osingleconst n) Enil)
end.
Nondetfunction divfs (e1: expr) (e2: expr) :=
match e2 with
| Eop (Osingleconst n2) Enil => divfsimm e1 n2
- | _ => Eop Odivfs (e1 ::: e2 ::: Enil)
+ | _ => divfs_base e1 e2
end.
-
+End SELECT. \ No newline at end of file
diff --git a/backend/SelectDivproof.v b/backend/SelectDivproof.v
index c57d3652..1873da4d 100644
--- a/backend/SelectDivproof.v
+++ b/backend/SelectDivproof.v
@@ -15,6 +15,7 @@
Require Import Zquot Coqlib Zbits.
Require Import AST Integers Floats Values Memory Globalenvs Events.
Require Import Cminor Op CminorSel.
+Require Import OpHelpers OpHelpersproof.
Require Import SelectOp SelectOpproof SplitLong SplitLongproof SelectLong SelectLongproof SelectDiv.
Local Open Scope cminorsel_scope.
@@ -587,12 +588,12 @@ Proof.
- destruct (Compopts.optim_for_size tt).
+ eapply eval_modu_base; eauto. EvalOp.
+ destruct (divu_mul_params (Int.unsigned n2)) as [[p M] | ] eqn:PARAMS.
- * econstructor; split.
+ * econstructor; split.
econstructor; eauto. eapply eval_mod_from_div.
eapply eval_divu_mul; eauto. simpl; eauto. simpl; eauto.
rewrite Int.modu_divu. auto.
red; intros; subst n2; discriminate.
- * eapply eval_modu_base; eauto. EvalOp.
+ * eapply eval_modu_base; eauto. EvalOp.
Qed.
Theorem eval_modu:
@@ -704,7 +705,7 @@ Proof.
|| Int.eq i (Int.repr Int.min_signed) && Int.eq n2 Int.mone) eqn:Z2; inv DIV.
destruct (Int.is_power2 n2) as [l | ] eqn:P2.
- destruct (Int.ltu l (Int.repr 31)) eqn:LT31.
- + exploit (eval_shrximm ge sp e m (Vint i :: le) (Eletvar O)).
+ + exploit (eval_shrximm prog sp e m (Vint i :: le) (Eletvar O)).
constructor. simpl; eauto. eapply Val.divs_pow2; eauto.
intros [v1 [X LD]]. inv LD.
econstructor; split. econstructor. eauto.
@@ -788,10 +789,10 @@ Proof.
+ destruct (Int64.is_power2' n2) as [l|] eqn:POW.
* exploit Val.divlu_pow2; eauto. intros EQ; subst z. apply eval_shrluimm; auto.
* destruct (Compopts.optim_for_size tt). eapply eval_divlu_base; eauto.
- destruct (divlu_mul_params (Int64.unsigned n2)) as [[p M]|] eqn:PARAMS.
+ (* destruct (divlu_mul_params (Int64.unsigned n2)) as [[p M]|] eqn:PARAMS.
** destruct x; simpl in H1; try discriminate.
destruct (Int64.eq n2 Int64.zero); inv H1.
- econstructor; split; eauto. econstructor. eauto. eapply eval_divlu_mull; eauto.
+ econstructor; split; eauto. econstructor. eauto. eapply eval_divlu_mull; eauto. *) (* FIXME - K1 hack *)
** eapply eval_divlu_base; eauto.
- eapply eval_divlu_base; eauto.
Qed.
@@ -813,14 +814,14 @@ Proof.
+ destruct (Int64.is_power2 n2) as [l|] eqn:POW.
* exploit Val.modlu_pow2; eauto. intros EQ; subst z. eapply eval_andl; eauto. apply eval_longconst.
* destruct (Compopts.optim_for_size tt). eapply eval_modlu_base; eauto.
- destruct (divlu_mul_params (Int64.unsigned n2)) as [[p M]|] eqn:PARAMS.
+ (* destruct (divlu_mul_params (Int64.unsigned n2)) as [[p M]|] eqn:PARAMS.
** destruct x; simpl in H1; try discriminate.
destruct (Int64.eq n2 Int64.zero) eqn:Z; inv H1.
rewrite Int64.modu_divu.
econstructor; split; eauto. econstructor. eauto.
eapply eval_modl_from_divl; eauto.
eapply eval_divlu_mull; eauto.
- red; intros; subst n2; discriminate Z.
+ red; intros; subst n2; discriminate Z. *)
** eapply eval_modlu_base; eauto.
- eapply eval_modlu_base; eauto.
Qed.
@@ -883,12 +884,12 @@ Proof.
** exploit Val.divls_pow2; eauto. intros EQ. eapply eval_shrxlimm; eauto.
** eapply eval_divls_base; eauto.
* destruct (Compopts.optim_for_size tt). eapply eval_divls_base; eauto.
- destruct (divls_mul_params (Int64.signed n2)) as [[p M]|] eqn:PARAMS.
+ (* destruct (divls_mul_params (Int64.signed n2)) as [[p M]|] eqn:PARAMS.
** destruct x; simpl in H1; try discriminate.
destruct (Int64.eq n2 Int64.zero
|| Int64.eq i (Int64.repr Int64.min_signed) && Int64.eq n2 Int64.mone); inv H1.
econstructor; split; eauto. econstructor. eauto.
- eapply eval_divls_mull; eauto.
+ eapply eval_divls_mull; eauto. *)
** eapply eval_divls_base; eauto.
- eapply eval_divls_base; eauto.
Qed.
@@ -925,14 +926,14 @@ Proof.
rewrite Int64.mods_divs. auto.
**eapply eval_modls_base; eauto.
* destruct (Compopts.optim_for_size tt). eapply eval_modls_base; eauto.
- destruct (divls_mul_params (Int64.signed n2)) as [[p M]|] eqn:PARAMS.
+ (* destruct (divls_mul_params (Int64.signed n2)) as [[p M]|] eqn:PARAMS.
** destruct x; simpl in H1; try discriminate.
destruct (Int64.eq n2 Int64.zero
|| Int64.eq i (Int64.repr Int64.min_signed) && Int64.eq n2 Int64.mone); inv H1.
econstructor; split; eauto. econstructor. eauto.
rewrite Int64.mods_divs.
eapply eval_modl_from_divl; auto.
- eapply eval_divls_mull; eauto.
+ eapply eval_divls_mull; eauto. *)
** eapply eval_modls_base; eauto.
- eapply eval_modls_base; eauto.
Qed.
@@ -950,8 +951,8 @@ Proof.
+ inv H0. inv H4. simpl in H6. inv H6. econstructor; split.
repeat (econstructor; eauto).
destruct x; simpl; auto. erewrite Float.div_mul_inverse; eauto.
- + TrivialExists.
-- TrivialExists.
+ + apply eval_divf_base; trivial.
+- apply eval_divf_base; trivial.
Qed.
Theorem eval_divfs:
@@ -965,8 +966,8 @@ Proof.
+ inv H0. inv H4. simpl in H6. inv H6. econstructor; split.
repeat (econstructor; eauto).
destruct x; simpl; auto. erewrite Float32.div_mul_inverse; eauto.
- + TrivialExists.
-- TrivialExists.
+ + apply eval_divfs_base; trivial.
+- apply eval_divfs_base; trivial.
Qed.
End CMCONSTRS.
diff --git a/backend/Selection.v b/backend/Selection.v
index c9771d99..4ab3331e 100644
--- a/backend/Selection.v
+++ b/backend/Selection.v
@@ -26,7 +26,7 @@ Require String.
Require Import Coqlib Maps.
Require Import AST Errors Integers Globalenvs Builtins Switch.
Require Cminor.
-Require Import Op CminorSel Cminortyping.
+Require Import Op CminorSel OpHelpers Cminortyping.
Require Import SelectOp SplitLong SelectLong SelectDiv.
Require Machregs.
@@ -507,11 +507,19 @@ Definition get_helpers (defmap: PTree.t globdef) : res helper_functions :=
do i64_sar <- lookup_helper globs "__compcert_i64_sar" sig_li_l ;
do i64_umulh <- lookup_helper globs "__compcert_i64_umulh" sig_ll_l ;
do i64_smulh <- lookup_helper globs "__compcert_i64_smulh" sig_ll_l ;
+ do i32_sdiv <- lookup_helper globs "__compcert_i32_sdiv" sig_ii_i ;
+ do i32_udiv <- lookup_helper globs "__compcert_i32_udiv" sig_ii_i ;
+ do i32_smod <- lookup_helper globs "__compcert_i32_smod" sig_ii_i ;
+ do i32_umod <- lookup_helper globs "__compcert_i32_umod" sig_ii_i ;
+ do f64_div <- lookup_helper globs "__compcert_f64_div" sig_ff_f ;
+ do f32_div <- lookup_helper globs "__compcert_f32_div" sig_ss_s ;
OK (mk_helper_functions
i64_dtos i64_dtou i64_stod i64_utod i64_stof i64_utof
i64_sdiv i64_udiv i64_smod i64_umod
i64_shl i64_shr i64_sar
- i64_umulh i64_smulh).
+ i64_umulh i64_smulh
+ i32_sdiv i32_udiv i32_smod i32_umod
+ f64_div f32_div).
(** Conversion of programs. *)
diff --git a/backend/Selectionaux.ml b/backend/Selectionaux.ml
index 8acae8f2..26a79fd7 100644
--- a/backend/Selectionaux.ml
+++ b/backend/Selectionaux.ml
@@ -73,13 +73,13 @@ let fast_cmove ty =
| "arm", _ ->
(match ty with Tint | Tfloat | Tsingle -> true | _ -> false)
| "powerpc", "e5500" ->
- (match ty with Tint -> true | Tlong -> true | _ -> false)
+ (match ty with Tint | Tlong -> true | _ -> false)
| "powerpc", _ -> false
| "riscV", _ -> false
| "x86", _ ->
- (match ty with Tint -> true | Tlong -> Archi.ptr64 | _ -> false)
- | _, _ ->
- assert false
+ (match ty with Tint -> true | Tlong -> Archi.ptr64 | _ -> false)
+ | "mppa_k1c", _ -> true
+ | a, m -> failwith (Printf.sprintf "fast_cmove: unknown arch %s %s" a m)
(* The if-conversion heuristic depend on the
-fif-conversion and -Obranchless flags.
diff --git a/backend/Selectionproof.v b/backend/Selectionproof.v
index 8a3aaae6..aa53c9cb 100644
--- a/backend/Selectionproof.v
+++ b/backend/Selectionproof.v
@@ -17,6 +17,7 @@ Require Import Coqlib Maps.
Require Import AST Linking Errors Integers.
Require Import Values Memory Builtins Events Globalenvs Smallstep.
Require Import Switch Cminor Op CminorSel Cminortyping.
+Require Import OpHelpers OpHelpersproof.
Require Import SelectOp SelectDiv SplitLong SelectLong Selection.
Require Import SelectOpproof SelectDivproof SplitLongproof SelectLongproof.
@@ -87,7 +88,7 @@ Lemma get_helpers_correct:
forall p hf,
get_helpers (prog_defmap p) = OK hf -> helper_functions_declared p hf.
Proof.
- intros. monadInv H. red; simpl. auto 20 using lookup_helper_correct.
+ intros. monadInv H. red; simpl. auto 22 using lookup_helper_correct.
Qed.
Theorem transf_program_match:
@@ -107,7 +108,7 @@ Proof.
{ unfold helper_declared; intros.
destruct (prog_defmap_linkorder _ _ _ _ H0 H1) as (gd & P & Q).
inv Q. inv H3. auto. }
- red in H. decompose [Logic.and] H; clear H. red; auto 20.
+ red in H. decompose [Logic.and] H; clear H. red; auto 22.
Qed.
(** * Correctness of the instruction selection functions for expressions *)
@@ -175,7 +176,7 @@ Proof.
generalize (match_program_defmap _ _ _ _ _ TRANSF id).
unfold Cminor.fundef; rewrite H; intros R; inv R. inv H2.
destruct H4 as (cu & A & B). monadInv B. auto. }
- unfold helper_functions_declared; intros. decompose [Logic.and] H; clear H. auto 20.
+ unfold helper_functions_declared; intros. decompose [Logic.and] H; clear H. auto 22.
Qed.
Section CMCONSTR.
@@ -1186,21 +1187,21 @@ Remark find_label_commut:
Proof.
induction s; intros until k'; simpl; intros MC SE; try (monadInv SE); simpl; auto.
(* store *)
- unfold store. destruct (addressing m (sel_expr e)); simpl; auto.
+- unfold store. destruct (addressing m (sel_expr e)); simpl; auto.
(* call *)
- destruct (classify_call (prog_defmap cunit) e); simpl; auto.
+- destruct (classify_call (prog_defmap cunit) e); simpl; auto.
rewrite sel_builtin_nolabel; auto.
(* tailcall *)
- destruct (classify_call (prog_defmap cunit) e); simpl; auto.
+- destruct (classify_call (prog_defmap cunit) e); simpl; auto.
(* builtin *)
- rewrite sel_builtin_nolabel; auto.
+- rewrite sel_builtin_nolabel; auto.
(* seq *)
- exploit (IHs1 (Cminor.Kseq s2 k)). constructor; eauto. eauto.
+- exploit (IHs1 (Cminor.Kseq s2 k)). constructor; eauto. eauto.
destruct (Cminor.find_label lbl s1 (Cminor.Kseq s2 k)) as [[sx kx] | ];
destruct (find_label lbl x (Kseq x0 k')) as [[sy ky] | ];
intuition. apply IHs2; auto.
(* ifthenelse *)
- destruct (if_conversion ki env e s1 s2) as [s|] eqn:IFC.
+- destruct (if_conversion ki env e s1 s2) as [s|] eqn:IFC.
inv SE. exploit if_conversion_nolabel; eauto. intros (A & B & C).
rewrite A, B, C. auto.
monadInv SE; simpl.
@@ -1209,19 +1210,19 @@ Proof.
destruct (find_label lbl x k') as [[sy ky] | ];
intuition. apply IHs2; auto.
(* loop *)
- apply IHs. constructor; auto. simpl; rewrite EQ; auto. auto.
+- apply IHs. constructor; auto. simpl; rewrite EQ; auto. auto.
(* block *)
- apply IHs. constructor; auto. auto.
+- apply IHs. constructor; auto. auto.
(* switch *)
- destruct b.
+- destruct b.
destruct (validate_switch Int64.modulus n l (compile_switch Int64.modulus n l)); inv SE.
simpl; auto.
destruct (validate_switch Int.modulus n l (compile_switch Int.modulus n l)); inv SE.
simpl; auto.
(* return *)
- destruct o; inv SE; simpl; auto.
+- destruct o; inv SE; simpl; auto.
(* label *)
- destruct (ident_eq lbl l). auto. apply IHs; auto.
+- destruct (ident_eq lbl l). auto. apply IHs; auto.
Qed.
Definition measure (s: Cminor.state) : nat :=
diff --git a/backend/SplitLong.vp b/backend/SplitLong.vp
index 694bb0e2..dfe42df0 100644
--- a/backend/SplitLong.vp
+++ b/backend/SplitLong.vp
@@ -16,41 +16,12 @@ Require String.
Require Import Coqlib.
Require Import AST Integers Floats.
Require Import Op CminorSel.
+Require Import OpHelpers.
Require Import SelectOp.
Local Open Scope cminorsel_scope.
Local Open Scope string_scope.
-(** Some operations on 64-bit integers are transformed into calls to
- runtime library functions. The following type class collects
- the names of these functions. *)
-
-Class helper_functions := mk_helper_functions {
- i64_dtos: ident; (**r float64 -> signed long *)
- i64_dtou: ident; (**r float64 -> unsigned long *)
- i64_stod: ident; (**r signed long -> float64 *)
- i64_utod: ident; (**r unsigned long -> float64 *)
- i64_stof: ident; (**r signed long -> float32 *)
- i64_utof: ident; (**r unsigned long -> float32 *)
- i64_sdiv: ident; (**r signed division *)
- i64_udiv: ident; (**r unsigned division *)
- i64_smod: ident; (**r signed remainder *)
- i64_umod: ident; (**r unsigned remainder *)
- i64_shl: ident; (**r shift left *)
- i64_shr: ident; (**r shift right unsigned *)
- i64_sar: ident; (**r shift right signed *)
- i64_umulh: ident; (**r unsigned multiply high *)
- i64_smulh: ident; (**r signed multiply high *)
-}.
-
-Definition sig_l_l := mksignature (Tlong :: nil) Tlong cc_default.
-Definition sig_l_f := mksignature (Tlong :: nil) Tfloat cc_default.
-Definition sig_l_s := mksignature (Tlong :: nil) Tsingle cc_default.
-Definition sig_f_l := mksignature (Tfloat :: nil) Tlong cc_default.
-Definition sig_ll_l := mksignature (Tlong :: Tlong :: nil) Tlong cc_default.
-Definition sig_li_l := mksignature (Tlong :: Tint :: nil) Tlong cc_default.
-Definition sig_ii_l := mksignature (Tint :: Tint :: nil) Tlong cc_default.
-
Section SELECT.
Context {hf: helper_functions}.
diff --git a/backend/SplitLongproof.v b/backend/SplitLongproof.v
index 18c1f18d..c8e3b94c 100644
--- a/backend/SplitLongproof.v
+++ b/backend/SplitLongproof.v
@@ -16,6 +16,8 @@ Require Import String.
Require Import Coqlib Maps.
Require Import AST Errors Integers Floats.
Require Import Values Memory Globalenvs Builtins Events Cminor Op CminorSel.
+Require Import OpHelpers OpHelpersproof.
+Require Import Values Memory Globalenvs Builtins Events Cminor Op CminorSel.
Require Import SelectOp SelectOpproof SplitLong.
Local Open Scope cminorsel_scope.
@@ -23,26 +25,6 @@ Local Open Scope string_scope.
(** * Properties of the helper functions *)
-Definition helper_declared {F V: Type} (p: AST.program (AST.fundef F) V) (id: ident) (name: string) (sg: signature) : Prop :=
- (prog_defmap p)!id = Some (Gfun (External (EF_runtime name sg))).
-
-Definition helper_functions_declared {F V: Type} (p: AST.program (AST.fundef F) V) (hf: helper_functions) : Prop :=
- helper_declared p i64_dtos "__compcert_i64_dtos" sig_f_l
- /\ helper_declared p i64_dtou "__compcert_i64_dtou" sig_f_l
- /\ helper_declared p i64_stod "__compcert_i64_stod" sig_l_f
- /\ helper_declared p i64_utod "__compcert_i64_utod" sig_l_f
- /\ helper_declared p i64_stof "__compcert_i64_stof" sig_l_s
- /\ helper_declared p i64_utof "__compcert_i64_utof" sig_l_s
- /\ helper_declared p i64_sdiv "__compcert_i64_sdiv" sig_ll_l
- /\ helper_declared p i64_udiv "__compcert_i64_udiv" sig_ll_l
- /\ helper_declared p i64_smod "__compcert_i64_smod" sig_ll_l
- /\ helper_declared p i64_umod "__compcert_i64_umod" sig_ll_l
- /\ helper_declared p i64_shl "__compcert_i64_shl" sig_li_l
- /\ helper_declared p i64_shr "__compcert_i64_shr" sig_li_l
- /\ helper_declared p i64_sar "__compcert_i64_sar" sig_li_l
- /\ helper_declared p i64_umulh "__compcert_i64_umulh" sig_ll_l
- /\ helper_declared p i64_smulh "__compcert_i64_smulh" sig_ll_l.
-
(** * Correctness of the instruction selection functions for 64-bit operators *)
Section CMCONSTR.
@@ -55,6 +37,7 @@ Variable sp: val.
Variable e: env.
Variable m: mem.
+Ltac UseHelper := decompose [Logic.and] arith_helpers_correct; eauto.
Ltac DeclHelper := red in HELPERS; decompose [Logic.and] HELPERS; eauto.
Lemma eval_helper:
@@ -342,7 +325,7 @@ Theorem eval_longofint: unary_constructor_sound longofint Val.longofint.
Proof.
red; intros. unfold longofint. destruct (longofint_match a).
- InvEval. econstructor; split. apply eval_longconst. auto.
-- exploit (eval_shrimm ge sp e m (Int.repr 31) (x :: le) (Eletvar 0)). EvalOp.
+- exploit (eval_shrimm prog sp e m (Int.repr 31) (x :: le) (Eletvar 0)). EvalOp.
intros [v1 [A B]].
econstructor; split. EvalOp.
destruct x; simpl; auto.
diff --git a/backend/Splitting.ml b/backend/Splitting.ml
index 40f09c3d..78eb66a5 100644
--- a/backend/Splitting.ml
+++ b/backend/Splitting.ml
@@ -151,8 +151,8 @@ let ren_instr f maps pc i =
| Inop s -> Inop s
| Iop(op, args, res, s) ->
Iop(op, ren_regs before args, ren_reg after res, s)
- | Iload(chunk, addr, args, dst, s) ->
- Iload(chunk, addr, ren_regs before args, ren_reg after dst, s)
+ | Iload(trap, chunk, addr, args, dst, s) ->
+ Iload(trap, chunk, addr, ren_regs before args, ren_reg after dst, s)
| Istore(chunk, addr, args, src, s) ->
Istore(chunk, addr, ren_regs before args, ren_reg before src, s)
| Icall(sg, ros, args, res, s) ->
diff --git a/backend/Stacking.v b/backend/Stacking.v
index 7b382d05..0e3f2832 100644
--- a/backend/Stacking.v
+++ b/backend/Stacking.v
@@ -133,8 +133,8 @@ Definition transl_instr
end
| Lop op args res =>
Mop (transl_op fe op) args res :: k
- | Lload chunk addr args dst =>
- Mload chunk (transl_addr fe addr) args dst :: k
+ | Lload trap chunk addr args dst =>
+ Mload trap chunk (transl_addr fe addr) args dst :: k
| Lstore chunk addr args src =>
Mstore chunk (transl_addr fe addr) args src :: k
| Lcall sig ros =>
diff --git a/backend/Stackingproof.v b/backend/Stackingproof.v
index ffd9b227..d3fcdb91 100644
--- a/backend/Stackingproof.v
+++ b/backend/Stackingproof.v
@@ -1891,12 +1891,13 @@ Proof.
apply plus_one. econstructor.
instantiate (1 := v'). rewrite <- A. apply eval_operation_preserved.
exact symbols_preserved. eauto.
- econstructor; eauto with coqlib.
- apply agree_regs_set_reg; auto.
- rewrite transl_destroyed_by_op. apply agree_regs_undef_regs; auto.
- apply agree_locs_set_reg; auto. apply agree_locs_undef_locs. auto. apply destroyed_by_op_caller_save.
- apply frame_set_reg. apply frame_undef_regs. exact SEP.
-
+ econstructor; eauto with coqlib;
+ try (apply agree_regs_set_reg; auto);
+ (* generic proof *)
+ solve [
+ (rewrite transl_destroyed_by_op; apply agree_regs_undef_regs; auto) |
+ (apply agree_locs_set_reg; auto; apply agree_locs_undef_locs; auto; apply destroyed_by_op_caller_save) |
+ (apply frame_set_reg; apply frame_undef_regs; exact SEP) ].
- (* Lload *)
assert (exists a',
eval_addressing ge (Vptr sp' Ptrofs.zero) (transl_addr (make_env (function_bounds f)) addr) rs0##args = Some a'
@@ -1917,6 +1918,46 @@ Proof.
apply agree_regs_set_reg. rewrite transl_destroyed_by_load. apply agree_regs_undef_regs; auto. auto.
apply agree_locs_set_reg. apply agree_locs_undef_locs. auto. apply destroyed_by_load_caller_save. auto.
+- (* Lload notrap1*)
+ assert (eval_addressing ge (Vptr sp' Ptrofs.zero) (transl_addr (make_env (function_bounds f)) addr) rs0##args = None) as Haddress.
+ eapply eval_addressing_inject_none; eauto.
+ eapply globalenv_inject_preserves_globals. eapply sep_proj2. eapply sep_proj2. eapply sep_proj2. eexact SEP.
+ eapply agree_reglist; eauto.
+ econstructor; split.
+ apply plus_one. apply exec_Mload_notrap1.
+ rewrite <- Haddress. apply eval_addressing_preserved. exact symbols_preserved.
+ eauto. econstructor; eauto with coqlib.
+ apply agree_regs_set_reg. rewrite transl_destroyed_by_load. apply agree_regs_undef_regs; auto. auto.
+ apply agree_locs_set_reg. apply agree_locs_undef_locs. auto. apply destroyed_by_load_caller_save. auto.
+
+- (* Lload notrap2 *)
+ assert (exists a',
+ eval_addressing ge (Vptr sp' Ptrofs.zero) (transl_addr (make_env (function_bounds f)) addr) rs0##args = Some a'
+ /\ Val.inject j a a').
+ eapply eval_addressing_inject; eauto.
+ eapply globalenv_inject_preserves_globals. eapply sep_proj2. eapply sep_proj2. eapply sep_proj2. eexact SEP.
+ eapply agree_reglist; eauto.
+ destruct H1 as [a' [A B]].
+
+ destruct ( Mem.loadv chunk m' a') as [v'|] eqn:Hloadv.
+ {
+ econstructor; split.
+ apply plus_one. apply exec_Mload with (a:=a') (v:=v'); eauto.
+ try (rewrite <- A; apply eval_addressing_preserved; auto; exact symbols_preserved).
+ econstructor; eauto with coqlib.
+ apply agree_regs_set_reg. rewrite transl_destroyed_by_load. apply agree_regs_undef_regs; auto. auto.
+ apply agree_locs_set_reg. apply agree_locs_undef_locs. auto. apply destroyed_by_load_caller_save. auto.
+ }
+ {
+ econstructor; split.
+ apply plus_one. apply exec_Mload_notrap2 with (a:=a'); eauto.
+ try (rewrite <- A; apply eval_addressing_preserved; auto; exact symbols_preserved).
+
+ econstructor; eauto with coqlib.
+ apply agree_regs_set_reg. rewrite transl_destroyed_by_load. apply agree_regs_undef_regs; auto. auto.
+ apply agree_locs_set_reg. apply agree_locs_undef_locs. auto. apply destroyed_by_load_caller_save. auto.
+ }
+
- (* Lstore *)
assert (exists a',
eval_addressing ge (Vptr sp' Ptrofs.zero) (transl_addr (make_env (function_bounds f)) addr) rs0##args = Some a'
diff --git a/backend/Tailcallproof.v b/backend/Tailcallproof.v
index 9ec89553..79a5c1cf 100644
--- a/backend/Tailcallproof.v
+++ b/backend/Tailcallproof.v
@@ -436,6 +436,43 @@ Proof.
apply eval_addressing_preserved. exact symbols_preserved. eauto.
econstructor; eauto. apply set_reg_lessdef; auto.
+- (* load notrap1 *)
+ TransfInstr.
+ assert (Val.lessdef_list (rs##args) (rs'##args)). apply regs_lessdef_regs; auto.
+ left.
+ exists (State s' (transf_function f) (Vptr sp0 Ptrofs.zero) pc' (rs'#dst <- (default_notrap_load_value chunk)) m'); split.
+ eapply exec_Iload_notrap1.
+ eassumption.
+ eapply eval_addressing_lessdef_none. eassumption.
+ erewrite eval_addressing_preserved.
+ eassumption. exact symbols_preserved.
+
+ econstructor; eauto. apply set_reg_lessdef; auto.
+
+- (* load notrap2 *)
+ TransfInstr.
+ assert (Val.lessdef_list (rs##args) (rs'##args)). apply regs_lessdef_regs; auto.
+ left.
+
+ exploit eval_addressing_lessdef; eauto.
+ intros [a' [ADDR' ALD]].
+
+ destruct (Mem.loadv chunk m' a') eqn:Echunk2.
+ + exists (State s' (transf_function f) (Vptr sp0 Ptrofs.zero) pc' (rs'#dst <- v) m'); split.
+ eapply exec_Iload with (a:=a'). eassumption.
+ erewrite eval_addressing_preserved.
+ eassumption.
+ exact symbols_preserved.
+ assumption.
+ econstructor; eauto. apply set_reg_lessdef; auto.
+ + exists (State s' (transf_function f) (Vptr sp0 Ptrofs.zero) pc' (rs'#dst <- (default_notrap_load_value chunk)) m'); split.
+ eapply exec_Iload_notrap2. eassumption.
+ erewrite eval_addressing_preserved.
+ eassumption.
+ exact symbols_preserved.
+ assumption.
+ econstructor; eauto. apply set_reg_lessdef; auto.
+
- (* store *)
TransfInstr.
assert (Val.lessdef_list (rs##args) (rs'##args)). apply regs_lessdef_regs; auto.
diff --git a/backend/Tunnelingproof.v b/backend/Tunnelingproof.v
index 4f95ac9b..d3b8a9f0 100644
--- a/backend/Tunnelingproof.v
+++ b/backend/Tunnelingproof.v
@@ -441,6 +441,31 @@ Proof.
rewrite <- EV. apply eval_addressing_preserved. exact symbols_preserved.
eauto. eauto.
econstructor; eauto using locmap_set_lessdef, locmap_undef_regs_lessdef.
+- (* Lload notrap1 *)
+ exploit eval_addressing_lessdef_none. apply reglist_lessdef; eauto. eassumption.
+ left; simpl; econstructor; split.
+ eapply exec_Lload_notrap1.
+ rewrite <- H0.
+ apply eval_addressing_preserved. exact symbols_preserved. eauto.
+ econstructor; eauto using locmap_set_lessdef, locmap_undef_regs_lessdef.
+- (* Lload notrap2 *)
+ exploit eval_addressing_lessdef. apply reglist_lessdef; eauto. eauto.
+ intros (ta & EV & LD).
+ destruct (Mem.loadv chunk tm ta) eqn:Htload.
+ {
+ left; simpl; econstructor; split.
+ eapply exec_Lload.
+ rewrite <- EV. apply eval_addressing_preserved. exact symbols_preserved.
+ exact Htload. eauto.
+ econstructor; eauto using locmap_set_lessdef, locmap_undef_regs_lessdef.
+ }
+ {
+ left; simpl; econstructor; split.
+ eapply exec_Lload_notrap2.
+ rewrite <- EV. apply eval_addressing_preserved. exact symbols_preserved.
+ exact Htload. eauto.
+ econstructor; eauto using locmap_set_lessdef, locmap_undef_regs_lessdef.
+ }
- (* Lgetstack *)
left; simpl; econstructor; split.
econstructor; eauto.
diff --git a/backend/Unusedglob.v b/backend/Unusedglob.v
index 8ac7c4ce..1b5f2547 100644
--- a/backend/Unusedglob.v
+++ b/backend/Unusedglob.v
@@ -46,7 +46,7 @@ Definition ref_instruction (i: instruction) : list ident :=
match i with
| Inop _ => nil
| Iop op _ _ _ => globals_operation op
- | Iload _ addr _ _ _ => globals_addressing addr
+ | Iload _ _ addr _ _ _ => globals_addressing addr
| Istore _ addr _ _ _ => globals_addressing addr
| Icall _ (inl r) _ _ _ => nil
| Icall _ (inr id) _ _ _ => id :: nil
diff --git a/backend/Unusedglobproof.v b/backend/Unusedglobproof.v
index 680daba7..fa120b6d 100644
--- a/backend/Unusedglobproof.v
+++ b/backend/Unusedglobproof.v
@@ -915,7 +915,7 @@ Proof.
/\ Val.inject j a ta).
{ apply eval_addressing_inj with (ge1 := ge) (sp1 := Vptr sp0 Ptrofs.zero) (vl1 := rs##args).
intros. apply symbol_address_inject. eapply match_stacks_preserves_globals; eauto.
- apply KEPT. red. exists pc, (Iload chunk addr args dst pc'); auto.
+ apply KEPT. red. exists pc, (Iload trap chunk addr args dst pc'); auto.
econstructor; eauto.
apply regs_inject; auto.
assumption. }
@@ -924,6 +924,36 @@ Proof.
econstructor; split. eapply exec_Iload; eauto.
econstructor; eauto. apply set_reg_inject; auto.
+- (* load notrap1 *)
+ assert (eval_addressing tge (Vptr tsp Ptrofs.zero) addr trs##args = None).
+ { eapply eval_addressing_inj_none.
+ intros. apply symbol_address_inject. eapply match_stacks_preserves_globals; eauto.
+ apply KEPT. red. exists pc, (Iload NOTRAP chunk addr args dst pc'); auto.
+ econstructor; eauto.
+ rewrite Ptrofs.add_zero; reflexivity.
+ apply regs_inject; auto.
+ eassumption.
+ assumption. }
+
+ econstructor; split. eapply exec_Iload_notrap1; eauto.
+ econstructor; eauto. apply set_reg_inject; auto.
+
+- (* load notrap2 *)
+ assert (A: exists ta,
+ eval_addressing tge (Vptr tsp Ptrofs.zero) addr trs##args = Some ta
+ /\ Val.inject j a ta).
+ { apply eval_addressing_inj with (ge1 := ge) (sp1 := Vptr sp0 Ptrofs.zero) (vl1 := rs##args).
+ intros. apply symbol_address_inject. eapply match_stacks_preserves_globals; eauto.
+ apply KEPT. red. exists pc, (Iload NOTRAP chunk addr args dst pc'); auto.
+ econstructor; eauto.
+ apply regs_inject; auto.
+ assumption. }
+ destruct A as (ta & B & C).
+ destruct (Mem.loadv chunk tm ta) eqn:Echunk2.
+ + econstructor; split. eapply exec_Iload; eauto.
+ econstructor; eauto. apply set_reg_inject; auto.
+ + econstructor; split. eapply exec_Iload_notrap2; eauto.
+ econstructor; eauto. apply set_reg_inject; auto.
- (* store *)
assert (A: exists ta,
eval_addressing tge (Vptr tsp Ptrofs.zero) addr trs##args = Some ta
diff --git a/backend/ValueAnalysis.v b/backend/ValueAnalysis.v
index 2b233900..9a33768c 100644
--- a/backend/ValueAnalysis.v
+++ b/backend/ValueAnalysis.v
@@ -139,9 +139,14 @@ Definition transfer (f: function) (rm: romem) (pc: node) (ae: aenv) (am: amem) :
| Some(Iop op args res s) =>
let a := eval_static_operation op (aregs ae args) in
VA.State (AE.set res a ae) am
- | Some(Iload chunk addr args dst s) =>
+ | Some(Iload TRAP chunk addr args dst s) =>
let a := loadv chunk rm am (eval_static_addressing addr (aregs ae args)) in
VA.State (AE.set dst a ae) am
+
+ (* TODO: maybe a case analysis on the results of loadv? *)
+
+ | Some(Iload NOTRAP chunk addr args dst s) =>
+ VA.State (AE.set dst Vtop ae) am
| Some(Istore chunk addr args src s) =>
let am' := storev chunk am (eval_static_addressing addr (aregs ae args)) (areg ae src) in
VA.State ae am'
@@ -1268,11 +1273,29 @@ Proof.
apply ematch_update; auto. eapply eval_static_operation_sound; eauto with va.
- (* load *)
+ destruct trap.
+ + eapply sound_succ_state; eauto. simpl; auto.
+ unfold transfer; rewrite H. eauto.
+ apply ematch_update; auto. eapply loadv_sound; eauto with va.
+ eapply eval_static_addressing_sound; eauto with va.
+ + eapply sound_succ_state; eauto. simpl; auto.
+ unfold transfer; rewrite H. eauto.
+ apply ematch_update; auto.
+ eapply vmatch_top.
+ eapply loadv_sound; try eassumption.
+ eapply eval_static_addressing_sound; eauto with va.
+- (* load notrap1 *)
eapply sound_succ_state; eauto. simpl; auto.
unfold transfer; rewrite H. eauto.
- apply ematch_update; auto. eapply loadv_sound; eauto with va.
- eapply eval_static_addressing_sound; eauto with va.
-
+ apply ematch_update; auto.
+ unfold default_notrap_load_value.
+ constructor.
+- (* load notrap2 *)
+ eapply sound_succ_state; eauto. simpl; auto.
+ unfold transfer; rewrite H. eauto.
+ apply ematch_update; auto.
+ unfold default_notrap_load_value.
+ constructor.
- (* store *)
exploit eval_static_addressing_sound; eauto with va. intros VMADDR.
eapply sound_succ_state; eauto. simpl; auto.
diff --git a/backend/XTL.ml b/backend/XTL.ml
index f10efeed..c496fafb 100644
--- a/backend/XTL.ml
+++ b/backend/XTL.ml
@@ -30,7 +30,7 @@ type instruction =
| Xspill of var * var
| Xparmove of var list * var list * var * var
| Xop of operation * var list * var
- | Xload of memory_chunk * addressing * var list * var
+ | Xload of trapping_mode * memory_chunk * addressing * var list * var
| Xstore of memory_chunk * addressing * var list * var
| Xcall of signature * (var, ident) sum * var list * var list
| Xtailcall of signature * (var, ident) sum * var list
@@ -159,7 +159,7 @@ let type_instr = function
let (targs, tres) = type_of_operation op in
set_vars_type args targs;
set_var_type res tres
- | Xload(chunk, addr, args, dst) ->
+ | Xload(trap, chunk, addr, args, dst) ->
set_vars_type args (type_of_addressing addr);
set_var_type dst (type_of_chunk chunk)
| Xstore(chunk, addr, args, src) ->
diff --git a/backend/XTL.mli b/backend/XTL.mli
index 54988d4b..b4b77fab 100644
--- a/backend/XTL.mli
+++ b/backend/XTL.mli
@@ -31,7 +31,7 @@ type instruction =
| Xspill of var * var
| Xparmove of var list * var list * var * var
| Xop of operation * var list * var
- | Xload of memory_chunk * addressing * var list * var
+ | Xload of trapping_mode * memory_chunk * addressing * var list * var
| Xstore of memory_chunk * addressing * var list * var
| Xcall of signature * (var, ident) sum * var list * var list
| Xtailcall of signature * (var, ident) sum * var list