Correctness proof for the translation from Linear to Mach.
This file proves semantic preservation for the Stacking pass.
For the target language Mach, we use the abstract semantics
given in file Machabstr, where a part of the activation record
is not resident in memory. Combined with the semantic equivalence
result between the two Mach semantics (see file Machabstr2concr),
the proof in this file also shows semantic preservation with
respect to the concrete Mach semantics.
Require Import Coqlib.
Require Import Maps.
Require Import Errors.
Require Import Ast.
Require Import Integers.
Require Import Pointers.
Require Import Values.
Require Import Op.
Require Import Mem.
Require Import Events.
Require Import Globalenvs.
Require Import Locations.
Require Import Linear.
Require Import Lineartyping.
Require Import Mach.
Require Import Machabstr.
Require Import Bounds.
Require Import Conventions.
Require Import Stacklayout.
Require Import Stacking.
Require Import Simulations MCsimulation.
Require Import Memcomp Traces.
Require Import Libtactics.
Definition genv_rel :
Linear.genv ->
Mach.genv ->
Prop :=
(
fun x y =>
Genv.genv_match (
fun a b =>
transf_fundef a =
OK b)
y x).
Properties of frames and frame accesses
``Good variable'' properties for frame accesses.
Lemma typesize_typesize:
forall ty,
Ast.typesize ty = 4 *
Locations.typesize ty.
Proof.
destruct ty; auto.
Qed.
Section PRESERVATION.
Variables (
ge :
Linear.genv) (
tge :
Mach.genv).
Hypothesis TRANSF:
genv_rel ge tge.
Let lts := (
mklts thread_labels (
Linear.step ge)).
Let tlts := (
mklts thread_labels (
ma_step tge)).
Section FRAME_PROPERTIES.
Variable stack:
Machabstr.stackframes.
Variable f:
Linear.function.
Let b :=
function_bounds f.
Let fe :=
make_env b.
Variable tf:
Mach.function.
Hypothesis TRANSF_F:
transf_function f =
OK tf.
Lemma unfold_transf_function:
tf =
Mach.mkfunction
f.(
Linear.fn_sig)
(
transl_body f fe (
align_framesize (
align_stacksize (
Int.unsigned f.(
Linear.fn_stacksize))
fe_retaddrsize)
fe.(
fe_size)
fe_retaddrsize))
(
align_stacksize (
Int.unsigned f.(
Linear.fn_stacksize))
fe_retaddrsize)
f.(
Linear.fn_stacksize)
(
align_framesize (
align_stacksize (
Int.unsigned f.(
Linear.fn_stacksize))
fe_retaddrsize)
fe.(
fe_size)
fe_retaddrsize).
Proof.
generalize TRANSF_F.
unfold transf_function.
repeat (
destruct zle;
try done).
unfold fe,
b.
congruence.
Qed.
Lemma align_framesize_le:
forall ssz fsz rsz,
fsz <=
align_framesize ssz fsz rsz.
Proof.
intros.
unfold align_framesize.
pose proof (
align_le (
ssz +
rsz +
fsz) 16).
omega.
Qed.
Lemma align_stacksize_le:
forall ssz rsz,
ssz <=
align_stacksize ssz rsz.
Proof.
Lemma stacksize_no_overflow:
fe.(
fe_size) <= -
Int.min_signed.
Proof.
A frame index is valid if it lies within the resource bounds
of the current function.
Definition index_valid (
idx:
frame_index) :=
match idx with
|
FI_local x Tint => 0 <=
x <
b.(
bound_int_local)
|
FI_local x Tfloat => 0 <=
x <
b.(
bound_float_local)
|
FI_arg x ty => 0 <=
x /\
x +
typesize ty <=
b.(
bound_outgoing)
|
FI_saved_int x => 0 <=
x <
b.(
bound_int_callee_save)
|
FI_saved_float x => 0 <=
x <
b.(
bound_float_callee_save)
end.
Definition type_of_index (
idx:
frame_index) :=
match idx with
|
FI_local x ty =>
ty
|
FI_arg x ty =>
ty
|
FI_saved_int x =>
Tint
|
FI_saved_float x =>
Tfloat
end.
Non-overlap between the memory areas corresponding to two
frame indices.
Definition index_diff (
idx1 idx2:
frame_index) :
Prop :=
match idx1,
idx2 with
|
FI_local x1 ty1,
FI_local x2 ty2 =>
x1 <>
x2 \/
ty1 <>
ty2
|
FI_arg x1 ty1,
FI_arg x2 ty2 =>
x1 +
typesize ty1 <=
x2 \/
x2 +
typesize ty2 <=
x1
|
FI_saved_int x1,
FI_saved_int x2 =>
x1 <>
x2
|
FI_saved_float x1,
FI_saved_float x2 =>
x1 <>
x2
|
_,
_ =>
True
end.
Ltac AddPosProps :=
generalize (
bound_int_local_pos b);
intro;
generalize (
bound_float_local_pos b);
intro;
generalize (
bound_int_callee_save_pos b);
intro;
generalize (
bound_float_callee_save_pos b);
intro;
generalize (
bound_outgoing_pos b);
intro;
generalize (
align_float_part b);
intro.
Lemma size_pos:
fe.(
fe_size) >= 0.
Proof.
AddPosProps.
unfold fe, make_env, fe_size; omega.
Qed.
Opaque function_bounds.
Lemma offset_of_index_disj:
forall idx1 idx2,
index_valid idx1 ->
index_valid idx2 ->
index_diff idx1 idx2 ->
offset_of_index fe idx1 + 4 *
typesize (
type_of_index idx1) <=
offset_of_index fe idx2 \/
offset_of_index fe idx2 + 4 *
typesize (
type_of_index idx2) <=
offset_of_index fe idx1.
Proof.
AddPosProps.
intros.
destruct idx1; destruct idx2;
try (destruct t); try (destruct t0);
unfold offset_of_index, fe, make_env,
fe_size, fe_ofs_int_local, fe_ofs_int_callee_save,
fe_ofs_float_local, fe_ofs_float_callee_save,
type_of_index, typesize;
simpl in H5; simpl in H6; simpl in H7;
try omega.
destruct H7; clarify. omega.
destruct H7; clarify. omega.
Qed.
Remark aligned_4_4x:
forall x, (4 | 4 *
x).
Proof.
intro. exists x; ring. Qed.
Remark aligned_4_8x:
forall x, (4 | 8 *
x).
Proof.
intro. exists (x * 2); ring. Qed.
Remark aligned_4_align8:
forall x, (4 |
align x 8).
Proof.
Hint Resolve Zdivide_0 Zdivide_refl Zdivide_plus_r
aligned_4_4x aligned_4_8x aligned_4_align8:
align_4.
Hint Extern 4 (?
X | ?
Y) => (
exists (
Y/
X);
reflexivity) :
align_4.
Lemma offset_of_index_aligned:
forall idx, (4 |
offset_of_index fe idx).
Proof.
intros.
destruct idx;
unfold offset_of_index, fe, make_env,
fe_size, fe_ofs_int_local, fe_ofs_int_callee_save,
fe_ofs_float_local, fe_ofs_float_callee_save;
auto with align_4.
destruct t; auto with align_4.
Qed.
Lemma frame_size_aligned:
(4 |
fe_size fe).
Proof.
unfold offset_of_index, fe, make_env,
fe_size, fe_ofs_int_local, fe_ofs_int_callee_save,
fe_ofs_float_local, fe_ofs_float_callee_save;
auto with align_4.
Qed.
The following lemmas give sufficient conditions for indices
of various kinds to be valid.
Lemma index_local_valid:
forall ofs ty,
slot_within_bounds f b (
Local ofs ty) ->
index_valid (
FI_local ofs ty).
Proof.
unfold slot_within_bounds, index_valid. auto.
Qed.
Lemma index_arg_valid:
forall ofs ty,
slot_within_bounds f b (
Outgoing ofs ty) ->
index_valid (
FI_arg ofs ty).
Proof.
unfold slot_within_bounds, index_valid. auto.
Qed.
Lemma index_saved_int_valid:
forall r,
In r int_callee_save_regs ->
index_int_callee_save r <
b.(
bound_int_callee_save) ->
index_valid (
FI_saved_int (
index_int_callee_save r)).
Proof.
Lemma index_saved_float_valid:
forall r,
In r float_callee_save_regs ->
index_float_callee_save r <
b.(
bound_float_callee_save) ->
index_valid (
FI_saved_float (
index_float_callee_save r)).
Proof.
Hint Resolve index_local_valid index_arg_valid
index_saved_int_valid index_saved_float_valid:
stacking.
The offset of a valid index lies within the bounds of the frame.
Lemma offset_of_index_valid:
forall idx,
index_valid idx ->
0 <=
offset_of_index fe idx /\
offset_of_index fe idx + 4 *
typesize (
type_of_index idx) <=
fe.(
fe_size).
Proof.
AddPosProps.
intros.
destruct idx;
try destruct t;
unfold offset_of_index,
fe,
make_env,
fe_size,
fe_ofs_int_local,
fe_ofs_int_callee_save,
fe_ofs_float_local,
fe_ofs_float_callee_save,
type_of_index,
typesize;
unfold index_valid in H5;
simpl typesize in H5;
omega.
Qed.
Offsets for valid index are representable as signed machine integers
without loss of precision.
Lemma offset_of_index_no_overflow:
forall idx,
index_valid idx ->
Int.signed (
Int.repr (
offset_of_index fe idx)) =
offset_of_index fe idx.
Proof.
Characterization of the get_slot and set_slot
operations in terms of the following index_val and set_index_val
frame access functions.
Definition index_val (
idx:
frame_index) (
fr:
frame) :=
fr (
type_of_index idx) (
offset_of_index fe idx ).
Definition set_index_val (
idx:
frame_index) (
v:
val) (
fr:
frame) :=
update (
type_of_index idx) (
offset_of_index fe idx )
v fr.
Lemma slot_valid_index:
forall idx,
index_valid idx ->
slot_valid tf.(
fn_framesize) (
type_of_index idx) (
offset_of_index fe idx).
Proof.
Lemma get_slot_index:
forall fr idx ty v,
index_valid idx ->
ty =
type_of_index idx ->
v =
index_val idx fr ->
get_slot tf.(
fn_framesize)
fr ty (
Int.signed (
Int.repr (
offset_of_index fe idx))) =
Some v.
Proof.
Lemma set_slot_index:
forall fr idx v,
index_valid idx ->
set_slot tf.(
fn_framesize)
fr (
type_of_index idx) (
Int.signed (
Int.repr (
offset_of_index fe idx)))
v =
Some (
set_index_val idx v fr).
Proof.
``Good variable'' properties for index_val and set_index_val.
Lemma get_set_index_val_same:
forall fr idx v,
index_val idx (
set_index_val idx v fr) =
v.
Proof.
intros.
unfold index_val,
set_index_val.
apply update_same.
Qed.
Lemma get_set_index_val_other:
forall fr idx idx'
v,
index_valid idx ->
index_valid idx' ->
index_diff idx idx' ->
index_val idx' (
set_index_val idx v fr) =
index_val idx'
fr.
Proof.
Lemma get_set_index_val_overlap:
forall ofs1 ty1 ofs2 ty2 v fr,
S (
Outgoing ofs1 ty1) <>
S (
Outgoing ofs2 ty2) ->
Loc.overlap (
S (
Outgoing ofs1 ty1)) (
S (
Outgoing ofs2 ty2)) =
true ->
index_val (
FI_arg ofs2 ty2) (
set_index_val (
FI_arg ofs1 ty1)
v fr) =
Vundef.
Proof.
Accessing stack-based arguments in the caller's frame.
Definition get_parent_slot (
cs:
stackframes) (
ofs:
Z) (
ty:
typ) (
v:
val) :
Prop :=
get_slot (
parent_size cs) (
parent_frame cs)
ty (
Int.signed (
Int.repr (4 *
ofs))) =
Some v.
Agreement between location sets and Mach environments
The following
agree predicate expresses semantic agreement between:
-
on the Linear side, the current location set ls and the location
set of the caller ls0;
-
on the Mach side, a register set rs, a frame fr and a call stack cs.
Record agree (
ls ls0:
locset) (
rs:
regset) (
fr:
frame) (
cs:
stackframes):
Prop :=
mk_agree {
Machine registers have the same values on the Linear and Mach sides.
agree_reg:
forall r,
ls (
R r) =
rs r;
Machine registers outside the bounds of the current function
have the same values they had at function entry. In other terms,
these registers are never assigned.
agree_unused_reg:
forall r, ~(
mreg_within_bounds b r) ->
rs r =
ls0 (
R r);
Local and outgoing stack slots (on the Linear side) have
the same values as the one loaded from the current Mach frame
at the corresponding offsets.
agree_locals:
forall ofs ty,
slot_within_bounds f b (
Local ofs ty) ->
ls (
S (
Local ofs ty)) =
index_val (
FI_local ofs ty)
fr;
agree_outgoing:
forall ofs ty,
slot_within_bounds f b (
Outgoing ofs ty) ->
ls (
S (
Outgoing ofs ty)) =
index_val (
FI_arg ofs ty)
fr;
Incoming stack slots (on the Linear side) have
the same values as the one loaded from the parent Mach frame
at the corresponding offsets.
agree_incoming:
forall ofs ty,
In (
S (
Incoming ofs ty)) (
loc_parameters f.(
Linear.fn_sig)) ->
get_parent_slot cs ofs ty (
ls (
S (
Incoming ofs ty)));
The areas of the frame reserved for saving used callee-save
registers always contain the values that those registers had
on function entry.
agree_saved_int:
forall r,
In r int_callee_save_regs ->
index_int_callee_save r <
b.(
bound_int_callee_save) ->
index_val (
FI_saved_int (
index_int_callee_save r))
fr =
ls0 (
R r);
agree_saved_float:
forall r,
In r float_callee_save_regs ->
index_float_callee_save r <
b.(
bound_float_callee_save) ->
index_val (
FI_saved_float (
index_float_callee_save r))
fr =
ls0 (
R r)
}.
Hint Resolve agree_reg agree_unused_reg
agree_locals agree_outgoing agree_incoming
agree_saved_int agree_saved_float:
stacking.
Values of registers and register lists.
Lemma agree_eval_reg:
forall ls ls0 rs fr cs r,
agree ls ls0 rs fr cs ->
rs r =
ls (
R r).
Proof.
intros. symmetry. eauto with stacking.
Qed.
Lemma agree_eval_regs:
forall ls ls0 rs fr cs rl,
agree ls ls0 rs cs fr ->
map rs rl =
reglist ls rl.
Proof.
induction rl;
simpl;
intros.
auto.
f_equal.
eapply agree_eval_reg;
eauto.
auto.
Qed.
Hint Resolve agree_eval_reg agree_eval_regs:
stacking.
Preservation of agreement under various assignments:
of machine registers, of local slots, of outgoing slots.
Lemma agree_set_reg:
forall ls ls0 rs fr cs r v,
agree ls ls0 rs fr cs ->
mreg_within_bounds b r ->
agree (
Locmap.set (
R r)
v ls)
ls0 (
Regmap.set r v rs)
fr cs.
Proof.
intros.
constructor;
eauto with stacking.
intros.
case (
mreg_eq r r0);
intro.
subst r0.
rewrite Locmap.gss;
rewrite Regmap.gss;
auto.
rewrite Locmap.gso.
rewrite Regmap.gso.
eauto with stacking.
auto.
red.
auto.
intros.
rewrite Regmap.gso.
eauto with stacking.
red;
intro;
subst r0.
contradiction.
intros.
rewrite Locmap.gso.
eauto with stacking.
red.
auto.
intros.
rewrite Locmap.gso.
eauto with stacking.
red.
auto.
intros.
rewrite Locmap.gso.
eauto with stacking.
red.
auto.
Qed.
Lemma agree_set_local:
forall ls ls0 rs fr cs v ofs ty,
agree ls ls0 rs fr cs ->
slot_within_bounds f b (
Local ofs ty) ->
exists fr',
set_slot tf.(
fn_framesize)
fr ty (
Int.signed (
Int.repr (
offset_of_index fe (
FI_local ofs ty))))
v =
Some fr' /\
agree (
Locmap.set (
S (
Local ofs ty))
v ls)
ls0 rs fr'
cs.
Proof.
Lemma agree_set_outgoing:
forall ls ls0 rs fr cs v ofs ty,
agree ls ls0 rs fr cs ->
slot_within_bounds f b (
Outgoing ofs ty) ->
exists fr',
set_slot tf.(
fn_framesize)
fr ty (
Int.signed (
Int.repr (
offset_of_index fe (
FI_arg ofs ty))))
v =
Some fr' /\
agree (
Locmap.set (
S (
Outgoing ofs ty))
v ls)
ls0 rs fr'
cs.
Proof.
Lemma agree_undef_regs:
forall rl ls ls0 rs fr cs,
agree ls ls0 rs fr cs ->
(
forall r,
In r rl ->
In (
R r)
temporaries) ->
agree (
Locmap.undef (
List.map R rl)
ls)
ls0 (
undef_regs rl rs)
fr cs.
Proof.
Lemma agree_undef_temps:
forall ls ls0 rs fr cs,
agree ls ls0 rs fr cs ->
agree (
LTL.undef_temps ls)
ls0 (
Mach.undef_temps rs)
fr cs.
Proof.
Lemma agree_undef_op:
forall op env ls ls0 rs fr cs,
agree ls ls0 rs fr cs ->
agree (
Linear.undef_op op ls)
ls0 (
Mach.undef_op (
transl_op env op)
rs)
fr cs.
Proof.
Lemma agree_undef_getparam:
forall ls ls0 rs fr cs,
agree ls ls0 rs fr cs ->
agree (
Locmap.set (
R IT1)
Vundef ls)
ls0 (
rs#
IT1 <-
Vundef)
fr cs.
Proof.
Lemma agree_return_regs:
forall ls ls0 rs fr cs rs',
agree ls ls0 rs fr cs ->
(
forall r,
~
In r int_callee_save_regs -> ~
In r float_callee_save_regs ->
rs'
r =
rs r) ->
(
forall r,
In r int_callee_save_regs \/
In r float_callee_save_regs ->
rs'
r =
ls0 (
R r)) ->
(
forall r,
return_regs ls0 ls (
R r) =
rs'
r).
Proof.
Agreement over callee-save registers and stack locations
Definition agree_callee_save (
ls1 ls2:
locset) :
Prop :=
forall l,
match l with
|
R r =>
In r int_callee_save_regs \/
In r float_callee_save_regs
|
S s =>
True
end ->
ls2 l =
ls1 l.
Definition agree_callee_save_regs (
ls1 ls2:
locset) :
Prop :=
forall l,
match l with
|
R r =>
In r int_callee_save_regs \/
In r float_callee_save_regs
|
S s =>
False
end ->
ls2 l =
ls1 l.
Definition agree_parent (
ls :
locset) (
s :
list stackframe) :=
match s with
|
nil =>
agree_callee_save_regs ls (
parent_locset s)
|
_ =>
agree_callee_save ls (
parent_locset s)
end.
Remark mreg_not_within_bounds:
forall r,
~
mreg_within_bounds b r ->
In r int_callee_save_regs \/
In r float_callee_save_regs.
Proof.
Lemma agree_callee_save_regs_agree:
forall ls ls1 ls2 rs fr cs,
agree ls ls1 rs fr cs ->
agree_callee_save_regs ls1 ls2 ->
agree ls ls2 rs fr cs.
Proof.
intros.
inv H.
constructor;
auto.
intros.
rewrite agree_unused_reg0;
auto.
symmetry.
apply H0.
apply mreg_not_within_bounds;
auto.
intros.
rewrite (
H0 (
R r));
auto.
intros.
rewrite (
H0 (
R r));
auto.
Qed.
Lemma agree_callee_save_impl_regs:
forall ls ls'
(
AG:
agree_callee_save ls ls'),
agree_callee_save_regs ls ls'.
Proof.
intros. intro l; specialize (AG l).
by destruct l.
Qed.
Lemma agree_callee_save_agree:
forall ls ls1 ls2 rs fr cs,
agree ls ls1 rs fr cs ->
agree_callee_save ls1 ls2 ->
agree ls ls2 rs fr cs.
Proof.
Lemma agree_callee_save_return_regs:
forall ls1 ls2,
agree_callee_save (
return_regs ls1 ls2)
ls1.
Proof.
Lemma agree_callee_save_set_result:
forall ls1 ls2 v sg,
agree_callee_save ls1 ls2 ->
agree_callee_save (
Locmap.set (
R (
Conventions.loc_result sg))
v ls1)
ls2.
Proof.
Lemma agree_callee_save_regs_set_result:
forall ls1 ls2 v sg,
agree_callee_save_regs ls1 ls2 ->
agree_callee_save_regs (
Locmap.set (
R (
Conventions.loc_result sg))
v ls1)
ls2.
Proof.
Lemma agree_parent_set_result:
forall ls s v sg,
agree_parent ls s ->
agree_parent (
Locmap.set (
R (
Conventions.loc_result sg))
v ls)
s.
Proof.
A variant of agree used for return frames.
Definition agree_frame (
ls ls0:
locset) (
fr:
frame) (
cs:
stackframes):
Prop :=
exists rs,
agree ls ls0 rs fr cs.
Lemma agree_frame_agree:
forall ls1 ls2 rs fr cs ls0,
agree_frame ls1 ls0 fr cs ->
agree_callee_save ls2 ls1 ->
(
forall r,
rs r =
ls2 (
R r)) ->
agree ls2 ls0 rs fr cs.
Proof.
intros.
destruct H as [
rs'
AG].
inv AG.
constructor;
auto.
intros.
rewrite <-
agree_unused_reg0;
auto.
rewrite <-
agree_reg0.
rewrite H1.
symmetry;
apply H0.
apply mreg_not_within_bounds;
auto.
intros.
rewrite <-
H0;
auto.
intros.
rewrite <-
H0;
auto.
intros.
rewrite <-
H0;
auto.
Qed.
Correctness of saving and restoring of callee-save registers
The following lemmas show the correctness of the register saving
code generated by save_callee_save: after this code has executed,
the register save areas of the current frame do contain the
values of the callee-save registers used by the function.
Section SAVE_CALLEE_SAVE.
Variable bound:
frame_env ->
Z.
Variable number:
mreg ->
Z.
Variable mkindex:
Z ->
frame_index.
Variable ty:
typ.
Variable sp:
option pointer.
Variable csregs:
list mreg.
Hypothesis number_inj:
forall r1 r2,
In r1 csregs ->
In r2 csregs ->
r1 <>
r2 ->
number r1 <>
number r2.
Hypothesis mkindex_valid:
forall r,
In r csregs ->
number r <
bound fe ->
index_valid (
mkindex (
number r)).
Hypothesis mkindex_typ:
forall z,
type_of_index (
mkindex z) =
ty.
Hypothesis mkindex_inj:
forall z1 z2,
z1 <>
z2 ->
mkindex z1 <>
mkindex z2.
Hypothesis mkindex_diff:
forall r idx,
idx <>
mkindex (
number r) ->
index_diff (
mkindex (
number r))
idx.
Lemma save_callee_save_regs_correct:
forall l k rs fr,
incl l csregs ->
NoDup l ->
exists fr',
taustar tlts
(
State stack tf sp
(
save_callee_save_regs bound number mkindex ty fe l k)
rs fr)
(
State stack tf sp k rs fr')
/\ (
forall r,
In r l ->
number r <
bound fe ->
index_val (
mkindex (
number r))
fr' =
rs r)
/\ (
forall idx,
index_valid idx ->
(
forall r,
In r l ->
number r <
bound fe ->
idx <>
mkindex (
number r)) ->
index_val idx fr' =
index_val idx fr).
Proof.
End SAVE_CALLEE_SAVE.
Lemma save_callee_save_int_correct:
forall k sp rs fr,
exists fr',
taustar tlts
(
State stack tf sp
(
save_callee_save_int fe k)
rs fr)
(
State stack tf sp k rs fr')
/\ (
forall r,
In r int_callee_save_regs ->
index_int_callee_save r <
bound_int_callee_save b ->
index_val (
FI_saved_int (
index_int_callee_save r))
fr' =
rs r)
/\ (
forall idx,
index_valid idx ->
match idx with FI_saved_int _ =>
False |
_ =>
True end ->
index_val idx fr' =
index_val idx fr).
Proof.
Lemma save_callee_save_float_correct:
forall k sp rs fr,
exists fr',
taustar tlts
(
State stack tf sp
(
save_callee_save_float fe k)
rs fr)
(
State stack tf sp k rs fr')
/\ (
forall r,
In r float_callee_save_regs ->
index_float_callee_save r <
bound_float_callee_save b ->
index_val (
FI_saved_float (
index_float_callee_save r))
fr' =
rs r)
/\ (
forall idx,
index_valid idx ->
match idx with FI_saved_float _ =>
False |
_ =>
True end ->
index_val idx fr' =
index_val idx fr).
Proof.
Lemma save_callee_save_correct:
forall sp k rs ls cs,
(
forall r,
rs r =
ls (
R r)) ->
(
forall ofs ty,
In (
S (
Outgoing ofs ty)) (
loc_arguments f.(
Linear.fn_sig)) ->
get_parent_slot cs ofs ty (
ls (
S (
Outgoing ofs ty)))) ->
exists fr',
taustar tlts
(
State stack tf sp (
save_callee_save fe k)
rs empty_frame)
(
State stack tf sp k rs fr')
/\
agree (
call_regs ls)
ls rs fr'
cs.
Proof.
intros.
unfold save_callee_save.
exploit save_callee_save_int_correct;
eauto.
intros [
fr1 [
A1 [
B1 C1]]].
exploit save_callee_save_float_correct.
intros [
fr2 [
A2 [
B2 C2]]].
exists fr2.
split.
eapply taustar_trans.
eexact A1.
eexact A2.
constructor;
unfold call_regs;
auto.
intros.
rewrite C2;
auto with stacking.
rewrite C1;
auto with stacking.
intros.
rewrite C2;
auto with stacking.
rewrite C1;
auto with stacking.
intros.
apply H0.
unfold loc_parameters in H1.
exploit list_in_map_inv;
eauto.
intros [
l [
A B]].
exploit loc_arguments_acceptable;
eauto.
intro C.
destruct l;
simpl in A;
try done.
simpl in C.
destruct s;
try contradiction.
inv A.
auto.
intros.
rewrite C2;
auto with stacking.
rewrite B1;
auto with stacking.
intros.
rewrite B2;
auto with stacking.
Qed.
The following lemmas show the correctness of the register reloading
code generated by reload_callee_save: after this code has executed,
all callee-save registers contain the same values they had at
function entry.
Section RESTORE_CALLEE_SAVE.
Variable bound:
frame_env ->
Z.
Variable number:
mreg ->
Z.
Variable mkindex:
Z ->
frame_index.
Variable ty:
typ.
Variable sp:
option pointer.
Variable csregs:
list mreg.
Hypothesis mkindex_valid:
forall r,
In r csregs ->
number r <
bound fe ->
index_valid (
mkindex (
number r)).
Hypothesis mkindex_typ:
forall z,
type_of_index (
mkindex z) =
ty.
Hypothesis number_within_bounds:
forall r,
In r csregs ->
(
number r <
bound fe <->
mreg_within_bounds b r).
Hypothesis mkindex_val:
forall ls ls0 rs fr cs r,
agree ls ls0 rs fr cs ->
In r csregs ->
number r <
bound fe ->
index_val (
mkindex (
number r))
fr =
ls0 (
R r).
Lemma restore_callee_save_regs_correct:
forall k fr ls0 l ls rs cs
(
IN:
incl l csregs)
(
ND:
NoDup l)
(
AGREE:
agree ls ls0 rs fr cs),
exists ls',
exists rs',
taustar tlts
(
State stack tf sp
(
restore_callee_save_regs bound number mkindex ty fe l k)
rs fr)
(
State stack tf sp k rs'
fr)
/\ (
forall r,
In r l ->
rs'
r =
ls0 (
R r))
/\ (
forall r, ~(
In r l) ->
rs'
r =
rs r)
/\
agree ls'
ls0 rs'
fr cs.
Proof.
End RESTORE_CALLEE_SAVE.
Lemma restore_int_callee_save_correct:
forall sp k fr ls0 ls rs cs,
agree ls ls0 rs fr cs ->
exists ls',
exists rs',
taustar tlts
(
State stack tf sp
(
restore_callee_save_int fe k)
rs fr)
(
State stack tf sp k rs'
fr)
/\ (
forall r,
In r int_callee_save_regs ->
rs'
r =
ls0 (
R r))
/\ (
forall r, ~(
In r int_callee_save_regs) ->
rs'
r =
rs r)
/\
agree ls'
ls0 rs'
fr cs.
Proof.
Lemma restore_float_callee_save_correct:
forall sp k fr ls0 ls rs cs,
agree ls ls0 rs fr cs ->
exists ls',
exists rs',
taustar tlts
(
State stack tf sp
(
restore_callee_save_float fe k)
rs fr)
(
State stack tf sp k rs'
fr)
/\ (
forall r,
In r float_callee_save_regs ->
rs'
r =
ls0 (
R r))
/\ (
forall r, ~(
In r float_callee_save_regs) ->
rs'
r =
rs r)
/\
agree ls'
ls0 rs'
fr cs.
Proof.
Lemma restore_callee_save_correct:
forall sp k fr ls0 ls rs cs,
agree ls ls0 rs fr cs ->
exists rs',
taustar tlts
(
State stack tf sp (
restore_callee_save fe k)
rs fr)
(
State stack tf sp k rs'
fr)
/\ (
forall r,
In r int_callee_save_regs \/
In r float_callee_save_regs ->
rs'
r =
ls0 (
R r))
/\ (
forall r,
~(
In r int_callee_save_regs) ->
~(
In r float_callee_save_regs) ->
rs'
r =
rs r).
Proof.
End FRAME_PROPERTIES.
Semantic preservation
Definition stacksize_of_fn f :=
align_stacksize (
Int.unsigned f.(
Linear.fn_stacksize))
fe_retaddrsize.
Definition framesize_of_fn f :=
let fe :=
make_env (
function_bounds f)
in
align_framesize (
stacksize_of_fn f)
fe.(
fe_size)
fe_retaddrsize.
Preservation of code labels through the translation.
Section LABELS.
Remark find_label_fold_right:
forall (
A:
Type) (
fn:
A ->
Mach.code ->
Mach.code)
lbl,
(
forall x k,
Mach.find_label lbl (
fn x k) =
Mach.find_label lbl k) ->
forall (
args:
list A)
k,
Mach.find_label lbl (
List.fold_right fn k args) =
Mach.find_label lbl k.
Proof.
induction args; simpl. auto.
intros. rewrite H. auto.
Qed.
Remark find_label_save_callee_save:
forall fe lbl k,
Mach.find_label lbl (
save_callee_save fe k) =
Mach.find_label lbl k.
Proof.
Remark find_label_restore_callee_save:
forall fe lbl k,
Mach.find_label lbl (
restore_callee_save fe k) =
Mach.find_label lbl k.
Proof.
intros.
unfold restore_callee_save,
restore_callee_save_int,
restore_callee_save_float,
restore_callee_save_regs.
rewrite !
find_label_fold_right;
try done;
by intros;
unfold restore_callee_save_reg;
case zlt.
Qed.
Lemma find_label_transl_code:
forall fe shift lbl c,
Mach.find_label lbl (
transl_code fe shift c) =
option_map (
transl_code fe shift) (
Linear.find_label lbl c).
Proof.
induction c;
simpl;
intros;
try done.
destruct a;
unfold transl_instr;
try rewrite find_label_restore_callee_save;
try done.
by destruct s.
by destruct s.
by simpl;
case peq.
Qed.
Lemma transl_find_label:
forall f tf lbl c,
transf_function f =
OK tf ->
Linear.find_label lbl f.(
Linear.fn_code) =
Some c ->
Mach.find_label lbl tf.(
Mach.fn_code) =
Some (
transl_code (
make_env (
function_bounds f)) (
framesize_of_fn f)
c).
Proof.
End LABELS.
Code inclusion property for Linear executions.
Lemma find_label_incl:
forall lbl c c',
Linear.find_label lbl c =
Some c' ->
incl c'
c.
Proof.
induction c;
simpl;
try done.
intro c'.
case (
Linear.is_label lbl a);
intros.
injection H;
intro;
subst c'.
red;
intros;
auto with coqlib.
apply incl_tl.
auto.
Qed.
Preservation / translation of global symbols and functions.
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.
Lemma functions_translated:
forall v f,
Genv.find_funct ge v =
Some f ->
exists tf,
Genv.find_funct tge v =
Some tf /\
transf_fundef f =
OK tf.
Proof.
Lemma symbols_preserved:
forall id,
Genv.find_symbol tge id =
Genv.find_symbol ge id.
Proof.
by intros;
destruct TRANSF. Qed.
Lemma sig_preserved:
forall f tf,
transf_fundef f =
OK tf ->
Mach.funsig tf =
Linear.funsig f.
Proof.
intros [] ?
H;
monadInv H;
try done;
revert EQ.
unfold transf_function.
by repeat (
destruct zle);
intros;
clarify.
Qed.
Lemma find_function_translated:
forall f0 ls ls0 rs fr cs ros f,
agree f0 ls ls0 rs fr cs ->
Linear.find_function ge ros ls =
Some f ->
exists tf,
find_function tge ros rs =
Some tf /\
transf_fundef f =
OK tf.
Proof.
Hypothesis wt_ge:
forall x f,
Genv.find_funct_ptr ge x =
Some f ->
wt_fundef f.
Lemma find_function_well_typed:
forall ros ls f,
Linear.find_function ge ros ls =
Some f ->
wt_fundef f.
Proof.
intros until f;
destruct ros;
simpl.
by destruct ls;
try done;
eauto.
by destruct Genv.find_symbol;
try done;
eauto.
Qed.
Correctness of stack pointer relocation in operations and
addressing modes.
Definition shift_sp (
tf:
Mach.function) (
sp:
option pointer) :=
match sp with
|
None =>
None
|
Some p =>
Some (
Ptr.add p (
Int.repr (-
tf.(
fn_framesize))))
end.
Remark shift_offset_sp:
forall f tf sp n v,
transf_function f =
OK tf ->
offset_sp sp n =
Some v ->
offset_sp (
shift_sp tf sp)
(
Int.add (
Int.repr (
framesize_of_fn f))
n) =
Some v.
Proof.
Lemma shift_eval_addressing:
forall f tf sp addr args v,
transf_function f =
OK tf ->
eval_addressing ge sp addr args =
Some v ->
eval_addressing tge (
shift_sp tf sp)
(
transl_addr (
framesize_of_fn f)
addr)
args =
Some v.
Proof.
intros;
unfold transl_addr,
eval_addressing,
shift_stack_addressing in *;
destruct addr;
try (
rewrite symbols_preserved);
auto.
destruct args;
try done.
by apply shift_offset_sp.
Qed.
Lemma shift_eval_operation:
forall f tf sp op args v,
transf_function f =
OK tf ->
eval_operation ge sp op args =
Some v ->
eval_operation tge (
shift_sp tf sp)
(
transl_op (
framesize_of_fn f)
op)
args =
Some v.
Proof.
Preservation of the arguments to an external call.
Section EXTERNAL_ARGUMENTS.
Variable cs:
Machabstr.stackframes.
Variable ls:
locset.
Variable rs:
regset.
Variable sg:
signature.
Hypothesis AG1:
forall r,
rs r =
ls (
R r).
Hypothesis AG2:
forall (
ofs :
Z) (
ty :
typ),
In (
S (
Outgoing ofs ty)) (
loc_arguments sg) ->
get_parent_slot cs ofs ty (
ls (
S (
Outgoing ofs ty))).
Lemma transl_external_arguments_rec:
forall locs,
incl locs (
loc_arguments sg) ->
extcall_args (
parent_size cs)
rs (
parent_frame cs)
locs =
Some (
map ls locs).
Proof.
unfold extcall_args in *.
induction locs;
simpl;
try done;
intros INCL.
rewrite IHlocs; [|
apply (
incl_cons_inv INCL)].
assert (
loc_argument_acceptable a).
by apply loc_arguments_acceptable with sg;
auto with coqlib.
destruct a as [|[]];
try done.
by rewrite <-
AG1.
unfold extcall_arg;
unfold get_parent_slot in AG2;
rewrite AG2;
try done.
by apply INCL;
left.
Qed.
Lemma transl_external_arguments:
extcall_arguments (
parent_size cs)
rs (
parent_frame cs)
sg (
map ls (
loc_arguments sg)).
Proof.
End EXTERNAL_ARGUMENTS.
The proof of semantic preservation relies on simulation diagrams
of the following form:
st1 --------------- st2
| |
t| +|t
| |
v v
st1'--------------- st2'
Matching between source and target states is defined by
match_states
below. It implies:
-
Agreement between, on the Linear side, the location sets ls
and parent_locset s of the current function and its caller,
and on the Mach side the register set rs, the frame fr
and the caller's frame parent_frame ts.
-
Inclusion between the Linear code c and the code of the
function f being executed.
-
Well-typedness of f.
Inductive match_stacks:
list Linear.stackframe ->
Machabstr.stackframes ->
Prop :=
|
match_stacks_nil:
forall fr sz,
match_stacks nil (
Stackbase fr sz)
|
match_stacks_cons:
forall f sp c ls tf fr s ts,
match_stacks s ts ->
transf_function f =
OK tf ->
wt_function f ->
agree_frame f ls (
parent_locset s)
fr ts ->
incl c (
Linear.fn_code f) ->
match_stacks
(
Linear.Stackframe f sp ls c ::
s)
(
Machabstr.Stackframe tf (
shift_sp tf sp)
(
transl_code (
make_env (
function_bounds f)) (
framesize_of_fn f)
c)
fr ts).
Inductive match_states:
Linear.state ->
Machabstr.state ->
Prop :=
|
match_states_intro:
forall s f sp c ls ts tf rs fr
(
STACKS:
match_stacks s ts)
(
TRANSL:
transf_function f =
OK tf)
(
WTF:
wt_function f)
(
AG:
agree f ls (
parent_locset s)
rs fr ts)
(
INCL:
incl c (
Linear.fn_code f)),
match_states (
Linear.State s f sp c ls)
(
Machabstr.State ts tf (
shift_sp tf sp) (
transl_code (
make_env (
function_bounds f)) (
framesize_of_fn f)
c)
rs fr)
|
match_states_call:
forall s f ls ts tf rs
(
STACKS:
match_stacks s ts)
(
TRANSL:
transf_fundef f =
OK tf)
(
WTF:
wt_fundef f)
(
AG1:
forall r,
rs r =
ls (
R r))
(
AG2:
forall ofs ty,
In (
S (
Outgoing ofs ty)) (
loc_arguments (
Linear.funsig f)) ->
get_parent_slot ts ofs ty (
ls (
S (
Outgoing ofs ty))))
(
AG3:
agree_parent ls s),
match_states (
Linear.Callstate s f ls)
(
Machabstr.Callstate ts tf rs)
|
match_states_return:
forall s ls ts rs
(
STACKS:
match_stacks s ts)
(
AG1:
forall r,
rs r =
ls (
R r))
(
AG2:
agree_parent ls s),
match_states (
Linear.Returnstate s ls)
(
Machabstr.Returnstate ts rs)
|
match_states_blocked:
forall s ls ts rs efsig
(
STACKS:
match_stacks s ts)
(
AG1:
forall r,
rs r =
ls (
R r))
(
AG2:
agree_parent ls s),
match_states (
Linear.Blockedstate s ls efsig)
(
Machabstr.Blockedstate ts rs efsig).
Theorem transf_step_correct:
forall s1 t s2,
Linear.step ge s1 t s2 ->
forall s1' (
MS:
match_states s1 s1'),
exists s2',
weakstep tlts s1'
t s2' /\
match_states s2 s2'.
Proof.
Opaque Zplus Zmult offset_of_index.
assert (
RED:
forall f i c,
transl_code (
make_env (
function_bounds f)) (
framesize_of_fn f) (
i ::
c) =
transl_instr (
make_env (
function_bounds f)) (
framesize_of_fn f)
i
(
transl_code (
make_env (
function_bounds f)) (
framesize_of_fn f)
c))
by done.
(
step_cases (
destruct 1)
Case);
simpl;
intros;
try inv MS;
try rewrite RED;
try (
generalize (
WTF _ (
INCL _ (
in_eq _ _)));
intro WTI);
try (
generalize (
function_is_within_bounds f WTF _ (
INCL _ (
in_eq _ _)));
intro BOUND;
simpl in BOUND);
unfold transl_instr.
Case "
exec_Lgetstack".
inv WTI.
destruct BOUND.
exists (
State ts tf (
shift_sp tf sp) (
transl_code (
make_env (
function_bounds f)) (
framesize_of_fn f)
b)
(
rs0#
r <- (
rs (
S sl)))
fr).
split.
destruct sl.
apply step_weakstep;
simpl;
apply exec_Mgetstack.
apply get_slot_index;
try done.
eapply agree_locals;
eauto.
apply step_weakstep;
simpl;
apply exec_Mgetparam.
change (
get_parent_slot ts z t (
rs (
S (
Incoming z t)))).
eapply agree_incoming;
eauto.
apply step_weakstep;
simpl;
apply exec_Mgetstack.
apply get_slot_index;
try done.
eapply agree_outgoing;
eauto.
econstructor;
eauto with coqlib.
apply agree_set_reg;
auto.
Case "
exec_Lsetstack".
inv WTI.
destruct sl.
generalize (
agree_set_local _ _ TRANSL _ _ _ _ _ (
rs0 r)
_ _ AG BOUND).
intros [
fr' [
SET AG']].
econstructor;
split.
apply step_weakstep;
simpl;
eapply exec_Msetstack;
eauto.
econstructor;
eauto with coqlib.
replace (
rs (
R r))
with (
rs0 r).
auto.
symmetry.
eapply agree_reg;
eauto.
contradiction.
generalize (
agree_set_outgoing _ _ TRANSL _ _ _ _ _ (
rs0 r)
_ _ AG BOUND).
intros [
fr' [
SET AG']].
econstructor;
split.
apply step_weakstep;
simpl;
eapply exec_Msetstack;
eauto.
econstructor;
eauto with coqlib.
replace (
rs (
R r))
with (
rs0 r).
auto.
symmetry.
eapply agree_reg;
eauto.
Case "
exec_Lop".
eexists;
split.
eapply step_weakstep;
simpl;
apply exec_Mop.
apply shift_eval_operation;
auto.
eby change mreg with RegEq.t;
rewrite (
agree_eval_regs _ _ _ _ _ _ args AG).
econstructor;
eauto with coqlib.
auto using agree_set_reg,
agree_undef_op.
Case "
exec_Lload".
eexists;
split.
apply step_weakstep;
simpl;
eapply exec_Mload;
eauto.
-
apply shift_eval_addressing;
auto.
eby change mreg with RegEq.t;
rewrite (
agree_eval_regs _ _ _ _ _ _ args AG).
econstructor;
eauto with coqlib.
auto using agree_set_reg,
agree_undef_temps.
Case "
exec_Lstore".
econstructor;
split.
apply step_weakstep;
simpl.
eapply exec_Mstore;
eauto.
-
apply shift_eval_addressing;
auto.
eby change mreg with RegEq.t;
rewrite (
agree_eval_regs _ _ _ _ _ _ args AG).
by rewrite (
agree_eval_reg _ _ _ _ _ _ src AG).
econstructor;
eauto using agree_undef_temps with coqlib.
Case "
exec_Lcall".
assert (
WTF':
wt_fundef f')
by (
eapply find_function_well_typed;
eauto).
exploit find_function_translated;
eauto.
intros [
tf' [
FIND'
TRANSL']].
econstructor;
split.
apply step_weakstep;
simpl;
eapply exec_Mcall;
eauto.
econstructor;
eauto.
econstructor;
eauto with coqlib.
exists rs0;
auto.
intro.
symmetry.
eapply agree_reg;
eauto.
intros.
assert (
slot_within_bounds f (
function_bounds f) (
Outgoing ofs ty)).
red.
simpl.
generalize (
loc_arguments_bounded _ _ _ H0).
generalize (
loc_arguments_acceptable _ _ H0).
unfold loc_argument_acceptable.
omega.
unfold get_parent_slot,
parent_size,
parent_frame.
change (4 *
ofs)
with (
offset_of_index (
make_env (
function_bounds f)) (
FI_arg ofs ty)).
apply get_slot_index;
simpl;
auto.
eapply agree_outgoing;
eauto.
simpl.
red;
auto.
Case "
exec_Llabel".
econstructor;
split.
apply step_weakstep;
simpl;
apply exec_Mlabel.
econstructor;
eauto with coqlib.
Case "
exec_Lgoto".
econstructor;
split.
apply step_weakstep;
simpl;
apply exec_Mgoto.
apply transl_find_label;
eauto.
econstructor;
eauto.
eapply find_label_incl;
eauto.
Case "
exec_Lcond_true".
econstructor;
split.
apply step_weakstep;
simpl;
apply exec_Mcond_true.
rewrite <- (
agree_eval_regs _ _ _ _ _ _ args AG)
in H;
eauto.
apply transl_find_label;
eauto.
econstructor;
eauto using agree_undef_temps,
find_label_incl.
Case "
exec_Lcond_false".
econstructor;
split.
apply step_weakstep;
simpl;
apply exec_Mcond_false.
rewrite <- (
agree_eval_regs _ _ _ _ _ _ args AG)
in H;
auto.
econstructor;
eauto using agree_undef_temps with coqlib.
Case "
exec_Lreturn".
exploit restore_callee_save_correct;
eauto.
intros [
ls' [
A [
B C]]].
econstructor;
split.
eapply taustar_weakstep; [
eassumption|].
eapply step_weakstep;
simpl;
econstructor;
eauto.
destruct sp;
simpl;
try done.
destruct p;
simpl.
by rewrite <-
Int.neg_repr,
Int.add_assoc, (
Int.add_commut (
Int.neg _)),
Int.add_neg_zero,
Int.add_zero.
econstructor;
eauto.
intros.
symmetry.
eapply agree_return_regs;
eauto.
destruct s; [
apply agree_callee_save_impl_regs|];
apply agree_callee_save_return_regs.
Case "
exec_Lthreadcreate".
assert (
Y0:
slot_within_bounds f (
function_bounds f) (
Outgoing 0
Tint))
by (
constructor;
try done;
revert BOUND;
clear;
change (
size_arguments thread_create_sig)
with 2;
simpl;
intros;
omega).
assert (
Y1:
slot_within_bounds f (
function_bounds f) (
Outgoing 1
Tint))
by (
constructor;
try done;
revert BOUND;
clear;
change (
size_arguments thread_create_sig)
with 2;
simpl;
intros;
omega).
clear BOUND.
eexists;
split.
1:
eapply step_weakstep;
simpl;
econstructor;
eauto.
2:
by econstructor;
eauto with coqlib.
exploit (
get_slot_index _ _ TRANSL fr (
FI_arg 0
Tint));
try edone;
intro X0.
exploit (
get_slot_index _ _ TRANSL fr (
FI_arg 1
Tint));
try edone;
intro X1.
rewrite <-
H.
unfold extcall_arguments.
unfold extcall_args;
simpl in *.
change (4 * 0)
with (
offset_of_index (
make_env (
function_bounds f)) (
FI_arg 0
Tint)).
rewrite X0;
simpl.
change (4 * (0 + 1))
with (
offset_of_index (
make_env (
function_bounds f)) (
FI_arg 1
Tint)).
rewrite X1;
simpl.
symmetry;
f_equal;
f_equal; [|
f_equal];
eapply agree_outgoing;
eauto.
Case "
exec_Latomic".
eexists;
split.
-
eapply step_weakstep;
simpl;
econstructor;
eauto.
eby change mreg with RegEq.t;
rewrite (
agree_eval_regs _ _ _ _ _ _ args AG).
by econstructor;
eauto using agree_set_reg,
agree_undef_temps with coqlib.
Case "
exec_Lfence".
eexists;
split; [
by eapply step_weakstep;
simpl;
vauto|].
by econstructor;
eauto using agree_set_reg,
agree_undef_temps with coqlib.
Case "
exec_function_internal_empty".
generalize TRANSL;
clear TRANSL.
unfold transf_fundef,
transf_partial_fundef.
caseEq (
transf_function f);
simpl;
try done.
intros tfn TRANSL EQ.
inversion EQ;
clear EQ;
subst tf.
inversion WTF as [|
f'
WTFN].
subst f'.
set (
tsp :=
shift_sp tfn None).
set (
fe :=
make_env (
function_bounds f)).
exploit save_callee_save_correct;
eauto.
intros [
fr [
EXP AG]].
econstructor;
split.
eapply step_taustar_weakstep;
simpl.
eapply exec_function_internal_empty;
eauto;
try by rewrite (
unfold_transf_function f tfn TRANSL).
replace (
Mach.fn_code tfn)
with
(
transl_body f (
make_env (
function_bounds f)) (
framesize_of_fn f));
[|
by rewrite (
unfold_transf_function f tfn TRANSL);
simpl].
unfold transl_body.
eexact EXP.
unfold tsp,
shift_sp.
econstructor;
eauto with coqlib.
by destruct s;
eauto using agree_callee_save_regs_agree,
agree_callee_save_impl_regs.
Case "
exec_function_internal_nonempty".
generalize TRANSL;
clear TRANSL.
unfold transf_fundef,
transf_partial_fundef.
caseEq (
transf_function f);
simpl;
try congruence.
intros tfn TRANSL EQ.
inversion EQ;
clear EQ;
subst tf.
inversion WTF as [|
f'
WTFN].
subst f'.
set (
tsp :=
shift_sp tfn (
Some stk)).
set (
fe :=
make_env (
function_bounds f)).
exploit save_callee_save_correct;
eauto.
intros [
fr [
EXP AG]].
econstructor;
split.
eapply step_taustar_weakstep;
simpl.
eapply exec_function_internal_nonempty;
eauto;
try by rewrite (
unfold_transf_function f tfn TRANSL).
replace (
Mach.fn_code tfn)
with
(
transl_body f (
make_env (
function_bounds f)) (
framesize_of_fn f));
[|
by rewrite (
unfold_transf_function f tfn TRANSL);
simpl].
unfold transl_body.
eexact EXP.
replace (
Ptr.sub_int stk (
Int.repr (
fn_framesize tfn)))
with (
Ptr.add stk (
Int.repr (-
fn_framesize tfn))).
2:
by destruct stk;
simpl;
rewrite Int.sub_add_opp,
Int.neg_repr.
econstructor;
eauto with coqlib.
by destruct s;
eauto using agree_callee_save_regs_agree,
agree_callee_save_impl_regs.
Case "
exec_function_external_call".
inv TRANSL.
exploit transl_external_arguments;
eauto.
intro EXTARGS.
econstructor;
split.
eby apply step_weakstep;
simpl;
eapply exec_function_external_call.
econstructor;
eauto.
Case "
exec_function_external_return".
econstructor;
split.
apply step_weakstep;
simpl;
eapply exec_function_external_return;
eauto.
econstructor;
try done.
intros.
unfold Regmap.set.
case (
RegEq.eq r (
loc_result (
efsig)));
intro.
rewrite e.
rewrite Locmap.gss;
auto.
rewrite Locmap.gso;
auto.
red;
auto.
apply agree_parent_set_result;
auto.
Case "
exec_return".
inv STACKS.
econstructor;
split.
apply step_weakstep;
simpl;
apply exec_return.
econstructor;
eauto.
simpl in AG2.
eapply agree_frame_agree;
eauto.
Case "
exec_return_exit".
inv STACKS.
econstructor;
split.
by apply step_weakstep;
simpl;
apply exec_return_exit.
vauto.
Qed.
Definition order:
Linear.state ->
Linear.state ->
Prop :=
fun x y =>
False.
Lemma my_forward_sim:
@
forward_sim thread_labels lts tlts match_states order.
Proof.
split.
done.
intros s t l s'
ST MS.
right;
left.
apply (
transf_step_correct s l s'
ST t MS).
Qed.
Lemma build_locs_other:
forall args vals l
(
NI: ~
In l args),
build_locs args vals l =
Vundef.
Proof.
induction args;
intros.
by destruct vals.
destruct vals.
done.
simpl.
destruct Loc.eq as [<- |
N].
by elim NI;
left.
apply IHargs.
by intro IN;
elim NI;
right.
Qed.
Lemma build_frame_rec_other:
forall ofs t l vs f (
NI:
Loc.notin (
S (
Outgoing ofs t))
l),
build_frame_rec l vs f t (4 *
ofs) =
f t (4 *
ofs).
Proof.
induction l as [|[|[]]];
intros;
simpl;
try destruct vs;
try done;
simpl in NI;
destruct NI as [
N NI];
rewrite IHl;
try done.
rewrite update_other.
done.
destruct N as [
D|
D].
destruct t;
simpl in D |- *;
omega.
destruct t0;
simpl in D |- *;
omega.
Qed.
Lemma build_locs_in:
forall args vals l
(
IN:
In l args),
In (
build_locs args vals l)
vals \/
build_locs args vals l =
Vundef.
Proof.
induction args;
intros.
done.
destruct vals.
by right.
simpl in IN;
destruct IN as [<- |
IN].
by simpl;
destruct Loc.eq;
vauto.
simpl;
destruct Loc.eq as [-> |
N].
vauto.
by destruct (
IHargs vals _ IN);
vauto.
Qed.
Lemma in_conv_list_nil:
forall v tys (
IN:
In v (
Val.conv_list nil tys)),
v =
Vundef.
Proof.
induction tys. done.
simpl; intros [<-|IN]; auto.
Qed.
Lemma init_sim_succ:
forall {
p vals tinit},
ma_init tge p vals =
Some tinit ->
exists sinit,
linear_init ge p vals =
Some sinit /\
match_states sinit tinit.
Proof.
Lemma init_sim_fail:
forall {
p vals},
ma_init tge p vals =
None ->
linear_init ge p vals =
None.
Proof.
intros p vals INIT.
unfold linear_init,
ma_init in *.
pose proof TRANSF as (
MG &
MF).
specialize (
MF p).
destruct (
Genv.find_funct_ptr tge p)
as [[[]|]|];
try done;
destruct (
Genv.find_funct_ptr ge p)
as [[[]|]|];
try done;
simpl in *;
monadInv MF.
unfold transf_function in EQ.
repeat (
destruct zle; [
done|]).
inv EQ.
by destruct beq_nat.
Qed.
Definition bsim_rel := @
bsr _ lts tlts match_states.
Definition bsim_order := @
bsc _ tlts.
End PRESERVATION.
Definition stacking_match_prg (
p :
linear_sem.(
SEM_PRG))
(
p' :
ma_sem.(
SEM_PRG)) :
Prop :=
Lineartyping.wt_program p /\
transf_program p =
OK p'.
Definition full_genv_rel (
ge :
Linear.genv) (
tge :
Mach.genv) :=
genv_rel ge tge /\
forall x f,
Genv.find_funct_ptr ge x =
Some f ->
wt_fundef f.
The whole-system backward simulation for the Stacking
phase.
Theorem stacking_sim Mm :
Sim.sim Mm Mm linear_sem ma_sem stacking_match_prg.
Proof.