Require Import Coqlib Wfsimpl Maps Errors Integers.
Require Import AST Linking Values Memory Globalenvs Events Smallstep.
Require Import Op Registers RTL.
Require Import Tailrec.
Lemma mem_free_perm_4:
forall (
m1 :
mem) (
bf :
block) (
lo hi :
Z) (
m2 :
mem),
Mem.free m1 bf lo hi =
Some m2 ->
forall (
ofs :
Z) (
k :
perm_kind) (
p :
permission),
lo <=
ofs <
hi ->
Mem.perm m1 bf ofs k p.
Proof.
Lemma successors_inside_sound :
forall f
(
INSIDE :
successors_inside f =
true)
pc instr pc'
(
AT : (
fn_code f) !
pc =
Some instr)
(
IN :
In pc' (
successors_instr instr)),
(
pc' <=
max_pc_function f)%
positive.
Proof.
Lemma transf_function_successors:
forall ge id f tf
(
TRANSF : (
transf_function ge id f) =
OK tf)
pc
instr (
AT : (
fn_code f) !
pc =
Some instr)
pc' (
IN :
In pc' (
successors_instr instr)),
(
pc' <=
max_pc_function f)%
positive.
Proof.
Remark succ_le:
forall a b, ((
Pos.succ a) <=
b)%
positive -> (
a <=
b)%
positive.
Proof.
intros. lia.
Qed.
Lemma copy_to_temps_increases:
forall srcregs tmpreg pc prec_code,
(
pc <=
(
fst (
copy_to_temps srcregs tmpreg pc prec_code)))%
positive.
Proof.
induction srcregs;
cbn in *;
intros.
lia.
apply succ_le.
apply IHsrcregs.
Qed.
Lemma copy_from_temps_increases:
forall params tmpreg pc prec_code,
(
pc <=
(
fst (
copy_from_temps params tmpreg pc prec_code)))%
positive.
Proof.
induction params;
cbn in *;
intros.
lia.
apply succ_le.
apply IHparams.
Qed.
Lemma copy_to_temps_preserves:
forall srcregs tmpreg pc prec_code pc' (
LT : (
pc' <
pc)%
positive),
(
snd (
copy_to_temps srcregs tmpreg pc prec_code)) !
pc' =
prec_code !
pc'.
Proof.
induction srcregs;
cbn in *;
intros.
reflexivity.
rewrite IHsrcregs by lia.
rewrite PTree.gso by lia.
reflexivity.
Qed.
Lemma copy_from_temps_preserves:
forall srcregs tmpreg pc prec_code pc' (
LT : (
pc' <
pc)%
positive),
(
snd (
copy_from_temps srcregs tmpreg pc prec_code)) !
pc' =
prec_code !
pc'.
Proof.
induction srcregs;
cbn in *;
intros.
reflexivity.
rewrite IHsrcregs by lia.
rewrite PTree.gso by lia.
reflexivity.
Qed.
Lemma copy_to_temps_set:
forall srcregs tmpreg pc prec_code k
(
LT : (
k <
List.length srcregs)%
nat),
(
snd (
copy_to_temps srcregs tmpreg pc prec_code)) !
(
Pos.of_nat ((
Pos.to_nat pc) +
k)%
nat) =
Some
(
Iop Omove ((
nth k srcregs 1%
positive)::
nil)
(
Pos.of_nat ((
Pos.to_nat tmpreg) +
k)%
nat)
(
Pos.of_nat ((
Pos.to_nat pc) +
k + 1)%
nat)).
Proof.
Lemma copy_to_temps_end:
forall srcregs tmpreg pc prec_code,
(
fst (
copy_to_temps srcregs tmpreg pc prec_code)) =
Pos.of_nat ((
Pos.to_nat pc) + (
List.length srcregs)).
Proof.
induction srcregs; cbn; intros.
lia.
rewrite IHsrcregs. lia.
Qed.
Lemma copy_from_temps_set:
forall dstregs tmpreg pc prec_code k
(
LT : (
k <
List.length dstregs)%
nat),
(
snd (
copy_from_temps dstregs tmpreg pc prec_code)) !
(
Pos.of_nat ((
Pos.to_nat pc) +
k)%
nat) =
Some
(
Iop Omove ((
Pos.of_nat ((
Pos.to_nat tmpreg) +
k)%
nat)::
nil)
(
nth k dstregs 1%
positive)
(
Pos.of_nat ((
Pos.to_nat pc) +
k + 1)%
nat)).
Proof.
Lemma copy_from_temps_end:
forall dstregs tmpreg pc prec_code,
(
fst (
copy_from_temps dstregs tmpreg pc prec_code)) =
Pos.of_nat ((
Pos.to_nat pc) + (
List.length dstregs)).
Proof.
induction dstregs; cbn; intros.
lia.
rewrite IHdstregs. lia.
Qed.
Lemma build_jump_set1:
forall start tmpreg srcregs dstregs pc0 code0 k
(
LT : (
k <
length srcregs)%
nat),
(
snd (
build_jump start tmpreg srcregs dstregs pc0 code0)) !
(
Pos.of_nat ((
Pos.to_nat pc0) +
k)%
nat) =
Some
(
Iop Omove ((
nth ((
length srcregs) -
S k)
srcregs 1%
positive)::
nil)
(
Pos.of_nat ((
Pos.to_nat tmpreg) +
k)%
nat)
(
Pos.of_nat ((
Pos.to_nat pc0) +
k + 1)%
nat)).
Proof.
Lemma build_jump_set2:
forall start tmpreg srcregs dstregs pc0 code0 k
(
LT : (
k <
length dstregs)%
nat),
(
snd (
build_jump start tmpreg srcregs dstregs pc0 code0)) !
(
Pos.of_nat ((
Pos.to_nat pc0) + (
List.length srcregs) +
k)%
nat) =
Some
(
Iop Omove ((
Pos.of_nat ((
Pos.to_nat tmpreg) +
k)%
nat)::
nil)
(
nth ((
length dstregs) -
S k)
dstregs 1%
positive)
(
Pos.of_nat ((
Pos.to_nat pc0) + (
length srcregs) +
k + 1)%
nat)).
Proof.
Lemma build_jump_set3:
forall start tmpreg srcregs dstregs pc0 code0,
(
snd (
build_jump start tmpreg srcregs dstregs pc0 code0)) !
(
Pos.of_nat ((
Pos.to_nat pc0) + (
List.length srcregs) + (
List.length dstregs))%
nat) =
Some (
Inop start).
Proof.
Inductive is_rec_call
start tmpreg srcregs dstregs pc0 code :=
is_rec_call_intro
(
TO_TEMPS :
forall k
(
LT : (
k <
List.length srcregs)%
nat),
code ! (
Pos.of_nat ((
Pos.to_nat pc0) +
k)%
nat) =
Some
(
Iop Omove ((
nth (
length srcregs -
S k)
srcregs 1%
positive)::
nil)
(
Pos.of_nat ((
Pos.to_nat tmpreg) +
k)%
nat)
(
Pos.of_nat ((
Pos.to_nat pc0) +
k + 1)%
nat)))
(
FROM_TEMPS :
forall k
(
LT : (
k <
List.length dstregs)%
nat),
code !
(
Pos.of_nat ((
Pos.to_nat pc0) + (
List.length srcregs) +
k)%
nat) =
Some
(
Iop Omove ((
Pos.of_nat ((
Pos.to_nat tmpreg) +
k)%
nat)::
nil)
(
nth (
length dstregs -
S k)
dstregs 1%
positive)
(
Pos.of_nat ((
Pos.to_nat pc0) + (
List.length srcregs) +
k + 1)%
nat)))
(
BACKJUMP :
code ! (
Pos.of_nat ((
Pos.to_nat pc0) +
(
List.length srcregs) + (
List.length dstregs))%
nat) =
Some (
Inop start)).
Lemma build_jump_set:
forall start tmpreg srcregs dstregs pc0 code0,
is_rec_call start tmpreg srcregs dstregs pc0
(
snd (
build_jump start tmpreg srcregs dstregs pc0 code0)).
Proof.
Lemma build_jump_end:
forall start tmpreg srcregs dstregs pc0 code0,
(
fst (
build_jump start tmpreg srcregs dstregs pc0 code0)) =
(
Pos.of_nat ((
Pos.to_nat pc0) + 1 +
(
List.length srcregs) + (
List.length dstregs))%
nat).
Proof.
Lemma process_instr_preserves:
forall id start params tmpreg new_pc new_code pc instr pc'
(
LT : (
pc' <
new_pc)%
positive)
(
NEQ : (
pc' <>
pc)%
positive),
(
snd (
process_instr id start params tmpreg new_pc new_code pc instr)) !
pc' =
new_code !
pc'.
Proof.
Lemma process_instr_at:
forall id start params tmpreg new_pc new_code pc instr
(
LT : (
pc <
new_pc)%
positive),
(
snd (
process_instr id start params tmpreg new_pc new_code pc instr)) !
pc =
match instr with
|
Itailcall sig (
inr id')
srcregs =>
if (
QualIdent.eq id id') &&
(
Nat.eq_dec (
List.length srcregs) (
List.length params))
then Some (
Inop new_pc)
else new_code !
pc
| _ =>
new_code !
pc
end.
Proof.
Lemma process_instr_increases:
forall id entrypoint params new_reg new_pc code0 pc instr,
(
new_pc <= (
fst (
process_instr id entrypoint params new_reg new_pc code0 pc instr)))%
positive.
Proof.
Lemma fold_process_instr_preserves :
forall id entrypoint params l new_reg new_pc code0 pc'
(
ALL_LT :
forall pc instr,
In (
pc,
instr)
l -> (
pc <
new_pc)%
positive)
(
NO_OVERRIDE :
forall instr,
In (
pc',
instr)
l ->
match instr with
|
Itailcall sig (
inr id')
srcregs =>
if (
QualIdent.eq id id') &&
(
Nat.eq_dec (
List.length srcregs)
(
List.length params))
then False
else True
| _ =>
True
end)
(
LT' : (
pc' <
new_pc)%
positive),
(
snd (
fold_left
(
fun (
a :
node *
code) (
p :
positive *
instruction) =>
let (
new_pc,
new_code) :=
a in
process_instr id entrypoint params
new_reg new_pc new_code
(
fst p) (
snd p))
l
(
new_pc,
code0))) !
pc' =
code0 !
pc'.
Proof.
induction l;
cbn;
intros.
reflexivity.
destruct a as [
pc instr].
cbn.
assert (
pc <
new_pc)%
positive as LT.
{
eapply ALL_LT.
left.
reflexivity. }
pose proof (
process_instr_at id entrypoint params new_reg new_pc code0 pc instr LT)
as AT.
pose proof (
process_instr_preserves id entrypoint params new_reg new_pc code0 pc instr pc' LT')
as PRESERVE.
pose proof (
process_instr_increases id entrypoint params new_reg new_pc code0 pc instr)
as INCR.
destruct (
process_instr id entrypoint params new_reg new_pc code0 pc instr)
as [
new_pc1 code1].
cbn in AT,
PRESERVE,
INCR.
rewrite IHl;
cycle 1.
{
intros pc0 instr0 IN0.
assert (
pc0 <
new_pc)%
positive.
{
eapply ALL_LT.
right.
exact IN0. }
lia.
}
{
intros instr0 IN0.
apply NO_OVERRIDE.
right.
assumption. }
lia.
destruct (
peq pc' pc)
as [
EQ |
NEQ] ;
cycle 1.
{
exact (
PRESERVE NEQ). }
subst pc'.
assert (
match instr with
|
Itailcall _ (
inr id')
srcregs =>
if
QualIdent.eq id id' &&
Nat.eq_dec (
Datatypes.length srcregs)
(
Datatypes.length params)
then False
else True
| _ =>
True
end)
as NO.
{
apply NO_OVERRIDE.
left.
reflexivity. }
destruct instr;
try assumption.
destruct s0.
assumption.
destruct (_ && _).
lia.
assumption.
Qed.
Lemma transf_function_preserves:
forall ge id f tf pc
(
UNCHANGED :
match (
fn_code f) !
pc with
|
Some (
Itailcall sig (
inr id')
srcregs) =>
if (
QualIdent.eq id id') &&
(
Nat.eq_dec (
List.length srcregs) (
List.length (
fn_params f)))
then False
else True
|
Some _ =>
True
|
None =>
False
end)
(
TRANSF :
transf_function ge id f =
OK tf),
(
fn_code tf) !
pc = (
fn_code f) !
pc.
Proof.
Lemma fold_tail_rec:
forall start reg0 params id sig args at_pc
(
LENGTHS : (
length args) = (
length params))
elts (
NOREPET:
list_norepet (
map fst elts))
pc0
(
BELOW :
forall pc i,
In (
pc,
i)
elts -> (
pc <
pc0)%
positive)
(
code0 :
code)
(
IN :
In (
at_pc, (
Itailcall sig (
inr id)
args))
elts),
let (
next_pc',
code') :=
fold_left
(
fun (
a :
node *
code) (
p :
positive *
instruction) =>
let (
new_pc,
new_code) :=
a in
process_instr id start
params reg0 new_pc
new_code (
fst p) (
snd p))
elts
(
pc0,
code0)
in
exists next_pc,
code' !
at_pc =
Some (
Inop next_pc) /\
is_rec_call start reg0 args params next_pc code'.
Proof.
Lemma transf_function'_tail_rec:
forall sig id f tf pc args
(
TRANSF :
transf_function' id f =
OK tf)
(
AT : (
fn_code f) !
pc =
Some (
Itailcall sig (
inr id)
args))
(
LENGTHS : (
List.length args) = (
List.length (
fn_params f))),
exists next_pc,
(
fn_code tf) !
pc =
Some (
Inop next_pc) /\
is_rec_call (
fn_entrypoint f) (
Pos.succ (
max_reg_function f))
args (
fn_params f)
next_pc
(
fn_code tf).
Proof.
Lemma transf_function_tail_rec:
forall ge sig id f tf pc args
(
TRANSF :
transf_function ge id f =
OK tf)
(
AT : (
fn_code f) !
pc =
Some (
Itailcall sig (
inr id)
args))
(
LENGTHS : (
List.length args) = (
List.length (
fn_params f))),
exists next_pc,
(
fn_code tf) !
pc =
Some (
Inop next_pc) /\
is_rec_call (
fn_entrypoint f) (
Pos.succ (
max_reg_function f))
args (
fn_params f)
next_pc
(
fn_code tf).
Proof.
Definition block2sp sp :=
Vptr sp (
Ptrofs.repr 0).
Lemma exec_jump1:
forall tge args
tf start next_reg next_pc ts trs tm tsp
(
BELOW:
Forall (
fun r => (
r <
next_reg)%
positive)
args)
(
REC_CALL :
is_rec_call start next_reg
args (
fn_params tf)
next_pc
(
fn_code tf))
k (
POSITION : (
k <= (
length args))%
nat),
exists trs2,
star step tge (
State ts tf (
block2sp tsp)
next_pc trs tm)
E0
(
State ts tf (
block2sp tsp) (
Pos.of_nat(
Pos.to_nat next_pc +
k)%
nat)
trs2 tm) /\
(
forall reg (
LOW: (
reg <
next_reg)%
positive),
trs2#
reg =
trs#
reg) /\
(
forall k' (
DONE: (
k' <
k)%
nat),
trs2#(
Pos.of_nat (
Pos.to_nat next_reg +
k')%
nat) =
trs#(
nth (
length args -
S k')%
nat args 1%
positive)).
Proof.
induction k;
intros.
{
exists trs.
split.
{
replace (
Pos.of_nat (
Pos.to_nat next_pc + 0))
with next_pc by lia.
apply star_refl. }
split. {
trivial. }
intros.
lia.
}
assert ((
k <=
Datatypes.length args)%
nat)
as ZZ by lia.
destruct (
IHk ZZ)
as (
trs1 &
STAR1 &
LOW1 &
HIGH1).
clear ZZ.
eexists.
split.
{
eapply star_right with (
t2:=
E0).
exact STAR1. 2:
reflexivity.
eapply exec_Iop.
destruct REC_CALL.
rewrite TO_TEMPS.
replace (
Pos.to_nat next_pc +
k + 1)%
nat with
(
Pos.to_nat next_pc +
S k)%
nat by lia.
reflexivity.
lia.
cbn.
reflexivity.
}
split.
{
intros.
rewrite Regmap.gso by lia.
apply LOW1;
auto.
}
intros.
destruct (
Nat.eq_dec k' k).
{
subst k'.
clear DONE.
rewrite Regmap.gss.
assert ((
nth (
Datatypes.length args -
S k)%
nat args 1%
positive) <
next_reg)%
positive as ZZ.
{
apply Forall_nth.
assumption.
lia. }
apply LOW1.
lia.
}
rewrite Regmap.gso by lia.
apply HIGH1.
lia.
Qed.
Fixpoint skip_first {
X :
Type} (
n :
nat) (
l :
list X) :=
match n with
|
O =>
l
|
S n' =>
match l with
|
nil =>
nil
| _::
tail =>
skip_first n' tail
end
end.
Fixpoint assign_regs (
vl :
list val) (
rl :
list reg)
rs0 {
struct rl} :
regset :=
match rl with
|
nil =>
rs0
|
r1 ::
rs =>
match vl with
|
nil =>
rs0
|
v1 ::
vs => (
assign_regs vs rs rs0) #
r1 <-
v1
end
end.
Fixpoint reg_sequence (
l :
nat) (
pos0 :
reg) :
list reg :=
match l with
|
O =>
nil
|
S l' =>
pos0 :: (
reg_sequence l' (
Pos.succ pos0))
end.
Remark reg_sequence_length:
forall n pos0,
length (
reg_sequence n pos0) =
n.
Proof.
induction n. reflexivity.
intro. cbn. rewrite IHn. reflexivity.
Qed.
Remark reg_sequence_nth:
forall l pos0 k (
LENGTH : (
k <
l)%
nat)
dummy,
nth k (
reg_sequence l pos0)
dummy = (
Pos.of_nat ((
Pos.to_nat pos0) +
k) :
reg).
Proof.
induction l; intros; cbn. lia.
destruct k. lia. rewrite IHl by lia. lia.
Qed.
Lemma skip_first_length:
forall {
X :
Type} (
l :
list X),
(
skip_first (
length l)
l) =
nil.
Proof.
induction l. reflexivity.
cbn. assumption.
Qed.
Lemma skip_first_nth :
forall {
X :
Type} (
n :
nat) (
l :
list X)
(
k :
nat) (
default :
X),
(
nth k (
skip_first n l)
default) = (
nth (
n+
k)%
nat l default).
Proof.
induction n; intros. reflexivity.
destruct l as [ | head tail]; cbn.
{ destruct k; reflexivity. }
apply IHn.
Qed.
Lemma nth_extensionality:
forall {
X :
Type} (
l1 l2 :
list X)
(
LENGTHS:
length l1 =
length l2)
dummy1 dummy2
(
ALL:
forall k, (
k <
length l1)%
nat ->
nth k l1 dummy1 =
nth k l2 dummy2),
l1 =
l2.
Proof.
induction l1;
destruct l2;
cbn in *;
intros.
reflexivity.
lia.
lia.
f_equal.
{
pose proof (
ALL O)
as ZZ;
cbn in ZZ.
apply ZZ.
lia. }
apply IHl1 with (
dummy1 :=
dummy1) (
dummy2 :=
dummy2).
lia.
intros.
pose proof (
ALL (
S k))
as ZZ;
cbn in ZZ.
apply ZZ.
lia.
Qed.
Remark rev_reg_sequence_S:
forall k next_reg,
(
rev (
reg_sequence (
S k)
next_reg)) =
(
Pos.of_nat (
Pos.to_nat next_reg +
k)) ::
(
rev (
reg_sequence k next_reg)).
Proof.
Remark skip_first_decompose:
forall k (
l :
list reg)
(
LENGTH : (
k <
length l)%
nat),
(
skip_first k l) = (
nth k l 1%
positive)::(
skip_first (
S k)
l).
Proof.
induction k; intros.
{ destruct l; cbn in *. lia. reflexivity. }
cbn. destruct l as [ | head tail].
{ cbn in LENGTH. lia. }
destruct tail as [ | head' tail' ].
{ cbn in LENGTH. lia. }
rewrite IHk; cycle 1.
{ cbn in *. lia. }
reflexivity.
Qed.
Lemma exec_jump2:
forall tge args
tf start next_reg next_pc ts trs tm tsp
(
BELOW:
Forall (
fun r => (
r <
next_reg)%
positive) (
fn_params tf))
(
REC_CALL :
is_rec_call start next_reg
args (
fn_params tf)
next_pc
(
fn_code tf))
k (
POSITION : (
k <=
length (
fn_params tf))%
nat),
exists trs2,
star step tge (
State ts tf (
block2sp tsp)
(
Pos.of_nat (
Pos.to_nat next_pc +
length args)%
nat)
trs tm)
E0
(
State ts tf (
block2sp tsp)
(
Pos.of_nat(
Pos.to_nat next_pc +
length args +
k)%
nat)
trs2 tm) /\
(
forall reg (
HIGH: (
reg >=
next_reg)%
positive),
trs2#
reg =
trs#
reg) /\
trs2 =
assign_regs
(
trs ## (
rev (
reg_sequence k next_reg)))
(
skip_first (
length (
fn_params tf) -
k) (
fn_params tf))
trs.
Proof.
Lemma exec_tail_rec_call:
forall tge tf start next_reg next_pc args ts trs tm tsp
(
BELOW_ARGS:
Forall (
fun r => (
r <
next_reg)%
positive)
args)
(
BELOW_PARAMS:
Forall (
fun r => (
r <
next_reg)%
positive) (
fn_params tf))
(
LENGTHS : (
List.length args) = (
List.length (
fn_params tf)))
(
REC_CALL :
is_rec_call start next_reg
args (
fn_params tf)
next_pc
(
fn_code tf)),
exists trs1 trs2,
plus step tge (
State ts tf (
block2sp tsp)
next_pc trs tm)
E0
(
State ts tf (
block2sp tsp)
start trs2 tm) /\
trs2 =
assign_regs (
trs##
args) (
fn_params tf)
trs1.
Proof.
Definition match_fundef (
prog :
program) (
f tf :
fundef) :=
exists cu id,
linkorder cu prog /\
(
transf_fundef (
Genv.globalenv cu)
id f =
OK tf).
Definition match_varinfo (
v tv:
unit) :=
True.
Definition match_prog (
p tp:
program) :
Prop :=
match_program_gen match_fundef match_varinfo p p tp.
Lemma transf_program_match:
forall prog tprog
(
TRANS :
transf_program prog =
OK tprog),
match_prog prog tprog.
Proof.
Section TAILREC.
Variable prog:
program.
Variable tprog:
program.
Hypothesis TRANSF:
match_prog prog tprog.
Let ge :=
Genv.globalenv prog.
Let tge :=
Genv.globalenv tprog.
Lemma symbols_preserved:
forall (
s:
qualident),
Genv.find_symbol tge s =
Genv.find_symbol ge s.
Proof.
Lemma senv_preserved:
Senv.equiv ge tge.
Proof.
Lemma function_ptr_translated:
forall (
b:
block) (
f:
fundef)
(
FIND :
Genv.find_funct_ptr ge b =
Some f),
exists cu f',
linkorder cu prog /\
Genv.find_funct_ptr tge b =
Some f' /\
match_fundef cu f f'.
Proof.
intros.
destruct (
Genv.find_funct_ptr_match TRANSF _
FIND)
as (
cu &
tf &
TFIND &
MATCH &
LINK).
unfold match_fundef in *.
destruct MATCH as (
cu' &
id' &
LINK' &
TRANS').
exists cu.
exists tf.
split.
eassumption.
split.
exact TFIND.
exists cu'.
exists id'.
split;
eassumption.
Qed.
Lemma functions_translated:
forall (
v:
val) (
f:
fundef),
Genv.find_funct ge v =
Some f ->
exists cu f',
linkorder cu prog /\
Genv.find_funct tge v =
Some f' /\
match_fundef cu f f'.
Proof.
Lemma sig_function_translated:
forall ge id f f',
transf_function ge id f =
OK f' ->
fn_sig f' =
fn_sig f.
Proof.
Lemma sig_fundef_translated:
forall ge id f f',
transf_fundef ge id f =
OK f' ->
funsig f' =
funsig f.
Proof.
Lemma stacksize_function_translated:
forall ge id f f',
transf_function ge id f =
OK f' ->
fn_stacksize f' =
fn_stacksize f.
Proof.
Lemma entrypoint_function_translated:
forall ge id f f',
transf_function ge id f =
OK f' ->
fn_entrypoint f' =
fn_entrypoint f.
Proof.
Lemma params_function_translated:
forall ge id f f',
transf_function ge id f =
OK f' ->
fn_params f' =
fn_params f.
Proof.
Inductive match_regs (
fn :
function) (
IF :
meminj) (
rs rs' :
regset) :=
match_regs_intro
(
REG_INJECT : (
forall r, (
r <=
RTL.max_reg_function fn)%
positive ->
Val.inject IF (
rs#
r) (
rs'#
r)))
(
REG_UNUSED : (
forall r, (
r >
RTL.max_reg_function fn)%
positive ->
rs#
r =
Vundef)).
Lemma match_regs_incr:
forall IF IF' (
INCR :
inject_incr IF IF')
fn rs trs
(
MATCH:
match_regs fn IF rs trs),
match_regs fn IF' rs trs.
Proof.
intros.
destruct MATCH.
constructor;
intros.
-
eapply val_inject_incr.
eassumption.
auto.
-
auto.
Qed.
Lemma match_copy:
forall fn IF rs trs trs1
(
MATCH_REGS:
match_regs fn IF rs trs)
params args
(
BELOW_ARGS:
Forall (
fun r => (
r <=
max_reg_function fn)%
positive)
args)
(
BELOW_PARAMS:
Forall (
fun r => (
r <=
max_reg_function fn)%
positive)
params),
(
match_regs fn IF (
init_regs (
rs ##
args)
params)
(
assign_regs (
trs ##
args)
params trs1)).
Proof.
induction params;
intros;
cbn.
-
constructor;
intros.
+
rewrite Regmap.gi.
constructor.
+
apply Regmap.gi.
-
destruct args as [ |
hargs targs];
cbn.
{
constructor.
-
intros.
rewrite Regmap.gi.
constructor.
-
intros.
apply Regmap.gi. }
destruct MATCH_REGS.
inv BELOW_ARGS.
inv BELOW_PARAMS.
destruct (
IHparams targs H2 H4)
as [
IND1 IND2].
constructor;
intros.
+
destruct (
peq r a).
*
subst r.
rewrite Regmap.gss.
rewrite Regmap.gss.
apply REG_INJECT.
assumption.
*
rewrite Regmap.gso by congruence.
rewrite Regmap.gso by congruence.
apply IND1.
assumption.
+
destruct (
peq r a).
*
subst r.
lia.
*
rewrite Regmap.gso by congruence.
apply IND2.
assumption.
Qed.
Definition match_sp (
IF :
meminj)
sp tsp :=
IF sp =
Some (
tsp, 0).
Definition find_function_symbol symb :=
match Genv.find_symbol ge symb with
|
Some b =>
Genv.find_funct_ptr ge b
|
None =>
None
end.
Record good_meminj (
bound:
block) (
IF:
meminj) :
Prop :=
mk_good_meminj {
good_meminj_find_symbol:
forall id b,
Genv.find_symbol ge id =
Some b ->
Plt b bound;
good_meminj_find_def:
forall b def,
Genv.find_def ge b =
Some def ->
Plt b bound;
good_meminj_fixes:
forall b,
Plt b bound ->
IF b =
Some(
b, 0%
Z);
good_meminj_nocollide:
forall b b' delta,
Ple bound b ->
IF b =
Some(
b',
delta) ->
Ple bound b'
}.
Lemma good_meminj_preserves_globals:
forall bound IF (
GOOD:
good_meminj bound IF),
(
meminj_preserves_globals ge IF).
Proof.
intros.
destruct GOOD.
constructor;
intros.
-
eauto.
-
split;
intros.
+
unfold Genv.find_var_info in H.
destruct (
Genv.find_def ge b)
as [
def | ]
eqn:
DEF.
2:
discriminate.
eauto.
+
unfold Genv.find_var_info in H.
destruct (
Genv.find_def ge b2)
as [
def | ]
eqn:
DEF.
2:
discriminate.
pose proof (
good_meminj_find_def0 _ _
DEF)
as LT.
pose proof (
good_meminj_fixes0 _
LT).
assert ((
Plt b1 bound) \/ (
Ple bound b1))
as CASES by (
unfold Plt,
Ple;
lia).
destruct CASES as [
CASE |
CASE].
*
pose proof (
good_meminj_fixes0 _
CASE).
congruence.
*
pose proof (
good_meminj_nocollide0 _ _ _
CASE H0).
unfold Plt,
Ple in *.
lia.
Qed.
Inductive match_stackframes (
bound :
block) (
IF :
meminj) :
stackframe ->
stackframe ->
Prop :=
|
match_stackframes_intro:
forall cu return_reg id f tf sp tsp pc rs trs
(
LINK:
linkorder cu prog)
(
BOUND_SP:
Ple bound sp)
(
REG_OK : (
return_reg <=
max_reg_function f)%
positive)
(
MATCH_FUNCTIONS :
transf_function (
Genv.globalenv cu)
id f =
OK tf)
(
MATCH_REGS :
match_regs f IF rs trs)
(
MATCH_SP :
match_sp IF sp tsp),
match_stackframes bound IF
(
Stackframe return_reg f (
block2sp sp)
pc rs)
(
Stackframe return_reg tf (
block2sp tsp)
pc trs).
Lemma match_sp_incr:
forall IF IF' (
INCR :
inject_incr IF IF')
sp sp'
(
MATCH :
match_sp IF sp sp'),
match_sp IF' sp sp'.
Proof.
Lemma match_stackframes_incr:
forall bound IF IF' (
INCR :
inject_incr IF IF')
(
a b :
stackframe) (
MATCH :
match_stackframes bound IF a b),
match_stackframes bound IF' a b.
Proof.
Lemma forall2_impl:
forall {
A B :
Type} (
P :
A->
B->
Prop) (
P':
A->
B->
Prop)
(
impl :
forall a b,
P a b ->
P' a b)
(
la :
list A) (
lb :
list B)
(
ALL:
List.Forall2 P la lb),
List.Forall2 P' la lb.
Proof.
induction la; cbn; intros; inv ALL; constructor; auto.
Qed.
Definition match_stacks bound IF s1 s2 :=
Forall2 (
match_stackframes bound IF)
s1 s2.
Lemma match_stacks_incr:
forall bound IF IF' s ts
(
ALL_IF :
match_stacks bound IF s ts)
(
INCR :
inject_incr IF IF'),
match_stacks bound IF' s ts.
Proof.
Definition weakly_allocated_block m b lo hi :=
forall ofs p, (
Mem.perm m b ofs Max p ->
lo <=
ofs <
hi).
Lemma alloc_new_weakly_allocated_block:
forall m lo hi m' b (
ALLOC :
Mem.alloc m lo hi = (
m',
b)),
weakly_allocated_block m' b lo hi.
Proof.
Lemma alloc_keep_weakly_allocated_block:
forall m b lo hi m' lo' hi' b'
(
VALID:
Plt b (
Mem.nextblock m))
(
ALLOC :
Mem.alloc m lo' hi' = (
m',
b'))
(
WEAKLY_ALLOCATED:
weakly_allocated_block m b lo hi),
weakly_allocated_block m' b lo hi.
Proof.
Lemma free_weakly_allocated_block:
forall m b lo hi b' lo' hi' m' (
FREE :
Mem.free m b' lo' hi' =
Some m')
(
WEAKLY_ALLOCATED:
weakly_allocated_block m b lo hi) (
NEQ:
b<>
b'),
weakly_allocated_block m' b lo hi.
Proof.
Lemma store_weakly_allocated_block:
forall m b lo hi (
WEAKLY_ALLOCATED:
weakly_allocated_block m b lo hi)
chunk b' ofs' v' m' (
STORE:
Mem.store chunk m b' ofs' v' =
Some m'),
weakly_allocated_block m' b lo hi.
Proof.
Lemma storev_weakly_allocated_block:
forall m b lo hi (
WEAKLY_ALLOCATED:
weakly_allocated_block m b lo hi)
chunk ptr' v' m' (
STORE:
Mem.storev chunk m ptr' v' =
Some m'),
weakly_allocated_block m' b lo hi.
Proof.
Lemma external_call_weakly_allocated_block:
forall m1 b lo hi (
WEAKLY_ALLOCATED:
weakly_allocated_block m1 b lo hi)
ef ge vargs m2 t vres
(
EXTCALL:
external_call ef ge vargs m1 t vres m2)
(
VALID:
Mem.valid_block m1 b),
(
weakly_allocated_block m2 b lo hi).
Proof.
Inductive ubound_stack :
block -> (
list stackframe) ->
Prop :=
|
ubound_stack_nil:
forall ub,
ubound_stack ub nil
|
ubound_stack_cons :
forall ub return_reg f sp pc rs tail
(
UBOUND_H :
Plt sp ub) (
UBOUND_T :
ubound_stack sp tail),
ubound_stack ub
((
Stackframe return_reg f (
block2sp sp)
pc rs) ::
tail).
Lemma ubound_stack_advance:
forall b1 b2 (
LE:
Ple b1 b2)
s
(
UBOUND :
ubound_stack b1 s), (
ubound_stack b2 s).
Proof.
induction s;
intros. {
constructor. }
inv UBOUND.
constructor.
{
unfold Ple,
Plt in *.
lia. }
assumption.
Qed.
Inductive weakly_allocated_stackframe :
mem ->
stackframe ->
Prop :=
weakly_allocated_stackframe_intro:
forall m return_reg f sp pc rs
(
WEAKLY_ALLOCATED_STACKFRAME:
weakly_allocated_block m sp 0 (
fn_stacksize f)),
weakly_allocated_stackframe m
(
Stackframe return_reg f (
block2sp sp)
pc rs).
Definition weakly_allocated_stack m :=
Forall (
weakly_allocated_stackframe m).
Lemma store_weakly_allocated_stack:
forall m s (
WEAKLY_ALLOCATED:
weakly_allocated_stack m s)
chunk b' ofs' v' m' (
STORE:
Mem.store chunk m b' ofs' v' =
Some m'),
weakly_allocated_stack m' s.
Proof.
induction s;
intros;
inv WEAKLY_ALLOCATED;
constructor.
-
inv H1.
constructor.
eapply store_weakly_allocated_block;
eassumption.
-
eapply IHs;
eassumption.
Qed.
Lemma storev_weakly_allocated_stack:
forall m s (
WEAKLY_ALLOCATED:
weakly_allocated_stack m s)
chunk ptr' v' m' (
STORE:
Mem.storev chunk m ptr' v' =
Some m'),
weakly_allocated_stack m' s.
Proof.
Lemma alloc_keep_weakly_allocated_stack:
forall s m m' lo' hi' b'
(
UBOUND:
ubound_stack (
Mem.nextblock m)
s)
(
ALLOC :
Mem.alloc m lo' hi' = (
m',
b'))
(
WEAKLY_ALLOCATED:
weakly_allocated_stack m s),
weakly_allocated_stack m' s.
Proof.
Definition not_in_stack b' :=
Forall
(
fun sf =>
match sf with
| (
Stackframe _ _ (
Vptr sp _) _ _) =>
sp <>
b'
| _ =>
True
end).
Lemma ubound_not_in_stack:
forall bound s
(
UBOUND:
ubound_stack bound s),
not_in_stack bound s.
Proof.
Lemma free_weakly_allocated_stack:
forall s m m' lo' hi' b'
(
NOT_IN:
not_in_stack b' s)
(
ALLOC :
Mem.free m b' lo' hi' =
Some m')
(
WEAKLY_ALLOCATED:
weakly_allocated_stack m s),
weakly_allocated_stack m' s.
Proof.
induction s;
intros;
inv WEAKLY_ALLOCATED;
inv NOT_IN;
constructor.
-
inv H1.
constructor.
eapply free_weakly_allocated_block;
eauto.
-
eapply IHs;
eauto.
Qed.
Lemma external_call_weakly_allocated_stack:
forall m1 s (
WEAKLY_ALLOCATED:
weakly_allocated_stack m1 s)
ef ge vargs m2 t vres
(
EXTCALL:
external_call ef ge vargs m1 t vres m2)
(
VALID:
ubound_stack (
Mem.nextblock m1)
s),
(
weakly_allocated_stack m2 s).
Proof.
Inductive match_states :
RTL.state ->
RTL.state ->
Prop :=
|
match_states_intro:
forall cu bound IF id s ts f tf sp tsp pc rs trs m tm
(
LINK:
linkorder cu prog)
(
WEAKLY_ALLOCATED_FRAME:
weakly_allocated_block m sp 0 (
fn_stacksize f))
(
UBOUND_SP:
Plt sp (
Mem.nextblock m))
(
UBOUND_STACK:
ubound_stack sp s)
(
WEAKLY_ALLOCATED_STACK:
weakly_allocated_stack m s)
(
BOUND_SP:
Ple bound sp)
(
NEXT_M:
Ple bound (
Mem.nextblock m))
(
NEXT_TM:
Ple bound (
Mem.nextblock tm))
(
GLOBALS :
good_meminj bound IF)
(
MATCH_STACKS:
match_stacks bound IF s ts)
(
MATCH_FUNCTIONS :
transf_function (
Genv.globalenv cu)
id f =
OK tf)
(
MATCH_REGS :
match_regs f IF rs trs)
(
MATCH_SP :
match_sp IF sp tsp)
(
MATCH_MEM :
Mem.inject IF m tm),
match_states (
State s f (
block2sp sp)
pc rs m)
(
State ts tf (
block2sp tsp)
pc trs tm)
|
match_states_call:
forall cu bound IF id s ts f tf args targs m tm
(
LINK:
linkorder cu prog)
(
UBOUND_STACK:
ubound_stack (
Mem.nextblock m)
s)
(
WEAKLY_ALLOCATED_STACK:
weakly_allocated_stack m s)
(
NEXT_M:
Ple bound (
Mem.nextblock m))
(
NEXT_TM:
Ple bound (
Mem.nextblock tm))
(
GLOBALS :
good_meminj bound IF)
(
MATCH_STACKS:
match_stacks bound IF s ts)
(
MATCH_FUNCTIONS :
transf_fundef (
Genv.globalenv cu)
id f =
OK tf)
(
MATCH_ARGS :
Val.inject_list IF args targs)
(
MATCH_MEM :
Mem.inject IF m tm),
match_states (
Callstate s f args m)
(
Callstate ts tf targs tm)
|
match_states_return:
forall bound IF s ts res tres m tm
(
UBOUND_STACK:
ubound_stack (
Mem.nextblock m)
s)
(
WEAKLY_ALLOCATED_STACK:
weakly_allocated_stack m s)
(
NEXT_M:
Ple bound (
Mem.nextblock m))
(
NEXT_TM:
Ple bound (
Mem.nextblock tm))
(
GLOBALS :
good_meminj bound IF)
(
MATCH_STACKS:
match_stacks bound IF s ts)
(
MATCH_RES :
Val.inject IF res tres)
(
MATCH_MEM :
Mem.inject IF m tm),
match_states (
Returnstate s res m)
(
Returnstate ts tres tm)
|
match_states_tail_rec:
forall cu bound IF id fd s ts f tf sp tsp pc rs trs m mfree tm sig args
(
LINK:
linkorder cu prog)
(
WEAKLY_ALLOCATED_FRAME:
weakly_allocated_block m sp 0 (
fn_stacksize f))
(
UBOUND_SP:
Plt sp (
Mem.nextblock m))
(
UBOUND_STACK:
ubound_stack sp s)
(
WEAKLY_ALLOCATED_STACK:
weakly_allocated_stack m s)
(
BOUND_SP:
Ple bound sp)
(
NEXT_M:
Ple bound (
Mem.nextblock m))
(
NEXT_TM:
Ple bound (
Mem.nextblock tm))
(
GLOBALS :
good_meminj bound IF)
(
FIND:
find_function_symbol id =
Some fd)
(
MATCH_STACKS:
match_stacks bound IF s ts)
(
MATCH_FUNCTIONS :
transf_function (
Genv.globalenv cu)
id f =
OK tf)
(
MATCH_REGS :
match_regs f IF rs trs)
(
MATCH_SP :
match_sp IF sp tsp)
(
MATCH_MEM :
Mem.inject IF m tm)
(
FREE :
Mem.free m sp 0 (
fn_stacksize f) =
Some mfree)
(
LENGTHS :
List.length args =
List.length (
fn_params f))
(
ARGS_OK : (
Forall (
fun r :
positive => (
r <= (
max_reg_function f)))%
positive)
args)
(
AT: (
fn_code f)!
pc =
Some (
Itailcall sig (
inr id)
args)),
match_states (
Callstate s (
Internal f)
rs ##
args mfree)
(
State ts tf (
block2sp tsp)
pc trs tm).
Lemma val_inject_refl:
forall v,
Val.inject (
fun x =>
Some (
x, 0))
v v.
Proof.
destruct v;
try constructor.
econstructor.
reflexivity.
symmetry.
apply Ptrofs.add_zero.
Qed.
Lemma transf_initial_states:
forall st1,
initial_state prog st1 ->
exists st2,
initial_state tprog st2 /\
match_states st1 st2.
Proof.
Lemma transf_final_states:
forall st1 st2 r
(
MATCH :
match_states st1 st2)
(
FINAL :
final_state st1 r),
final_state st2 r.
Proof.
intros. inv FINAL. inv MATCH. inv MATCH_STACKS.
inv MATCH_RES. constructor.
Qed.
Definition measure (
S:
RTL.state) :
nat :=
match S with
|
State _ _ _ _ _ _ => 1%
nat
|
Callstate _ _ _ _ |
Returnstate _ _ _ => 0%
nat
end.
Lemma match_regs_args :
forall args f IF rs trs
(
MATCH_REGS :
match_regs f IF rs trs)
(
ARGS_OK :
forall r,
In r args -> (
r <= (
max_reg_function f))%
positive),
Val.inject_list IF (
rs ##
args) (
trs ##
args).
Proof.
induction args; intros.
constructor.
simpl.
constructor.
{ inv MATCH_REGS.
apply REG_INJECT. apply ARGS_OK. left. reflexivity. }
apply IHargs with (f := f). assumption.
intros. apply ARGS_OK. right. assumption.
Qed.
Lemma match_regs_params:
forall params f IF args args'
(
INJECT :
Val.inject_list IF args args')
(
ALL :
List.Forall (
fun x => (
x <=
max_reg_function f)%
positive)
params),
match_regs f IF (
init_regs args params)
(
init_regs args' params).
Proof.
induction params;
intros;
cbn.
{
constructor.
{
intros.
rewrite Regmap.gi.
constructor. }
intros.
apply Regmap.gi.
}
destruct args.
{
constructor.
{
intros.
rewrite Regmap.gi.
constructor. }
intros.
apply Regmap.gi.
}
inv INJECT.
inv ALL.
destruct (
IHparams f IF args vl' H3 H4)
as (
LOW &
HIGH).
constructor.
{
intros.
destruct (
peq a r).
-
subst a.
rewrite Regmap.gss.
rewrite Regmap.gss.
assumption.
-
rewrite Regmap.gso by lia.
rewrite Regmap.gso by lia.
apply LOW;
auto.
}
intros.
destruct (
peq a r).
lia.
rewrite Regmap.gso by lia.
apply HIGH;
auto.
Qed.
Lemma match_regs_assign :
forall f IF rs trs res v tv
(
RES_OK : (
res <= (
max_reg_function f))%
positive)
(
MATCH_REGS :
match_regs f IF rs trs)
(
INJECT :
Val.inject IF v tv),
match_regs f IF (
rs #
res <-
v) (
trs #
res <-
tv).
Proof.
Lemma imply_forall2:
forall {
A B :
Type}
(
P :
A->
B->
Prop)
(
P' :
A->
B->
Prop)
(
IMPL :
forall a b,
P a b ->
P' a b)
(
la :
list A) (
lb :
list B)
(
ALL :
Forall2 P la lb),
Forall2 P' la lb.
Proof.
induction la; intros; inv ALL; constructor; auto.
Qed.
Lemma match_sp_inject:
forall IF sp tsp (
MATCH :
match_sp IF sp tsp),
(
Val.inject IF (
block2sp sp) (
block2sp tsp)).
Proof.
Lemma eval_builtin_arg_inject:
forall bound IF arg varg rs trs m tm sp tsp
(
GLOBALS:
good_meminj bound IF)
(
MATCH_REGS :
List.Forall (
fun r =>
Val.inject IF (
rs#
r) (
trs#
r))
(
params_of_builtin_arg arg))
(
MATCH_MEM :
Mem.inject IF m tm)
(
MATCH_SP :
match_sp IF sp tsp)
(
EVAL :
eval_builtin_arg tge (
fun r :
positive =>
rs #
r)
(
block2sp sp)
m arg varg),
exists tvarg,
eval_builtin_arg tge (
fun r :
positive =>
trs #
r)
(
block2sp tsp)
tm arg tvarg /\
Val.inject IF varg tvarg.
Proof.
induction arg;
cbn;
intros;
inv EVAL.
1,2,3,4,5: (
inv MATCH_REGS;
eexists;
split ; [
constructor |
trivial];
fail).
-
apply match_sp_inject in MATCH_SP.
pose proof (
Val.offset_ptr_inject IF (
block2sp sp) (
block2sp tsp)
ofs MATCH_SP)
as OFFSET.
destruct (
Mem.loadv_inject _ _ _ _ _ _ _
MATCH_MEM H2 OFFSET)
as (
v2 &
LOAD2 &
INJ2).
eexists.
split.
+
constructor.
eassumption.
+
eassumption.
-
apply match_sp_inject in MATCH_SP.
pose proof (
Val.offset_ptr_inject IF (
block2sp sp) (
block2sp tsp)
ofs MATCH_SP)
as OFFSET.
eexists.
split.
constructor.
assumption.
-
destruct (
good_meminj_preserves_globals _ _
GLOBALS)
as (
PRES1 &
PRES2 &
PRES3).
unfold Senv.symbol_address in *.
destruct (
Senv.find_symbol tge id)
eqn:
FIND;
cycle 1.
{
cbn in H3.
discriminate. }
destruct senv_preserved as (
SENV1 &
SENV2 &
SENV3).
rewrite SENV1 in FIND.
pose proof (
PRES1 _ _
FIND)
as PRES.
assert (
Val.inject IF (
Vptr b ofs) (
Vptr b ofs))
as INJ.
{
econstructor.
exact PRES.
rewrite Ptrofs.add_zero.
reflexivity. }
destruct (
Mem.loadv_inject _ _ _ _ _ _ _
MATCH_MEM H3 INJ)
as (
v2 &
LD1 &
LOD2).
exists v2.
split. 2:
assumption.
constructor.
unfold Senv.symbol_address.
rewrite SENV1.
rewrite FIND.
assumption.
-
destruct (
good_meminj_preserves_globals _ _
GLOBALS)
as (
PRES1 &
PRES2 &
PRES3).
eexists.
split. {
apply eval_BA_addrglobal. }
unfold Senv.symbol_address.
destruct (
Senv.find_symbol tge id)
eqn:
FIND. 2:
constructor.
destruct senv_preserved as (
SENV1 &
SENV2 &
SENV3).
rewrite SENV1 in FIND.
pose proof (
PRES1 _ _
FIND)
as PRES.
econstructor.
exact PRES.
rewrite Ptrofs.add_zero.
reflexivity.
-
apply Forall_app in MATCH_REGS.
destruct MATCH_REGS as (
MATCH_REGS1 &
MATCH_REGS2).
destruct (
IHarg1 _ _
trs _ _ _ _
GLOBALS MATCH_REGS1 MATCH_MEM MATCH_SP H1)
as (
tv1 &
X1 &
Y1).
destruct (
IHarg2 _ _
trs _ _ _ _
GLOBALS MATCH_REGS2 MATCH_MEM MATCH_SP H3)
as (
tv2 &
X2 &
Y2).
eexists.
split.
+
constructor.
eassumption.
eassumption.
+
apply Val.longofwords_inject;
assumption.
-
apply Forall_app in MATCH_REGS.
destruct MATCH_REGS as (
MATCH_REGS1 &
MATCH_REGS2).
destruct (
IHarg1 _ _
trs _ _ _ _
GLOBALS MATCH_REGS1 MATCH_MEM MATCH_SP H1)
as (
tv1 &
X1 &
Y1).
destruct (
IHarg2 _ _
trs _ _ _ _
GLOBALS MATCH_REGS2 MATCH_MEM MATCH_SP H3)
as (
tv2 &
X2 &
Y2).
eexists.
split.
constructor.
eassumption.
eassumption.
destruct Archi.ptr64.
+
apply Val.addl_inject;
assumption.
+
apply Val.add_inject;
assumption.
Qed.
Lemma eval_builtin_args_inject:
forall bound IF args vargs rs trs m tm sp tsp
(
GLOBALS:
good_meminj bound IF)
(
MATCH_REGS :
List.Forall (
fun r =>
Val.inject IF (
rs#
r) (
trs#
r))
(
params_of_builtin_args args))
(
MATCH_MEM :
Mem.inject IF m tm)
(
MATCH_SP :
match_sp IF sp tsp)
(
EVAL :
eval_builtin_args tge (
fun r :
positive =>
rs #
r)
(
block2sp sp)
m args vargs),
exists tvargs,
eval_builtin_args tge (
fun r :
positive =>
trs #
r)
(
block2sp tsp)
tm args tvargs /\
Val.inject_list IF vargs tvargs.
Proof.
unfold eval_builtin_args.
induction args;
cbn;
intros;
inv EVAL.
{
exists nil.
split.
constructor.
constructor. }
apply Forall_app in MATCH_REGS.
destruct MATCH_REGS as (
MATCH_REGS_H &
MATCH_REGS_T).
destruct (
eval_builtin_arg_inject _ _ _ _ _ _ _ _ _ _
GLOBALS MATCH_REGS_H MATCH_MEM MATCH_SP H1)
as (
th &
XH &
YH).
destruct (
IHargs _ _ _ _ _ _ _
GLOBALS MATCH_REGS_T MATCH_MEM MATCH_SP H3)
as (
tt &
XT &
YT).
eexists.
split.
+
constructor.
exact XH.
exact XT.
+
constructor;
assumption.
Qed.
Lemma eval_assert_arg_inject:
forall bound IF arg varg rs trs m tm sp tsp
(
GLOBALS:
good_meminj bound IF)
(
MATCH_REGS :
List.Forall (
fun r =>
Val.inject IF (
rs#
r) (
trs#
r))
(
params_of_assert_arg arg))
(
MATCH_MEM :
Mem.inject IF m tm)
(
MATCH_SP :
match_sp IF sp tsp)
(
EVAL :
eval_assert_arg ge (
block2sp sp)
rs m arg varg),
exists tvarg,
eval_assert_arg tge (
block2sp tsp)
trs tm arg tvarg /\
Val.inject IF varg tvarg.
Proof.
Lemma eval_assert_args_inject:
forall bound IF args vargs rs trs m tm sp tsp
(
GLOBALS:
good_meminj bound IF)
(
MATCH_REGS :
List.Forall (
fun r =>
Val.inject IF (
rs#
r) (
trs#
r))
(
params_of_assert_args args))
(
MATCH_MEM :
Mem.inject IF m tm)
(
MATCH_SP :
match_sp IF sp tsp)
(
EVAL :
eval_assert_args ge (
block2sp sp)
rs m args vargs),
exists tvargs,
eval_assert_args tge (
block2sp tsp)
trs tm args tvargs /\
Val.inject_list IF vargs tvargs.
Proof.
unfold eval_assert_args.
induction args;
cbn;
intros;
inv EVAL.
{
exists nil.
split.
constructor.
constructor. }
apply Forall_app in MATCH_REGS.
destruct MATCH_REGS as (
MATCH_REGS_H &
MATCH_REGS_T).
destruct (
eval_assert_arg_inject _ _ _ _ _ _ _ _ _ _
GLOBALS MATCH_REGS_H MATCH_MEM MATCH_SP H1)
as (
th &
XH &
YH).
destruct (
IHargs _ _ _ _ _ _ _
GLOBALS MATCH_REGS_T MATCH_MEM MATCH_SP H3)
as (
tt &
XT &
YT).
eexists.
split.
+
constructor.
exact XH.
exact XT.
+
constructor;
assumption.
Qed.
Definition meminj_subst (
IF:
meminj) (
b b' :
block) :=
fun x =>
if peq x b' then IF b else IF x.
Definition meminj_subst_incr:
forall IF b b' (
EMPTY:
IF b' =
None),
inject_incr IF (
meminj_subst IF b b').
Proof.
Transparent Mem.alloc.
Lemma malloc_undef:
forall m lo hi malloc next_block ofs
(
ALLOC :
Mem.alloc m lo hi = (
malloc,
next_block)),
(
ZMap.get ofs (
Mem.mem_contents malloc) #
next_block) =
Undef.
Proof.
Lemma mem_alloc_contents_before:
forall m lo hi malloc next_block b
(
ALLOC :
Mem.alloc m lo hi = (
malloc,
next_block))
(
NEQ :
b <>
next_block),
(
Mem.mem_contents malloc) #
b =
(
Mem.mem_contents m) #
b.
Proof.
Opaque Mem.alloc.
Transparent Mem.free.
Lemma mem_free_contents_before:
forall m lo hi mfree b b'
(
FREE :
Mem.free m b lo hi =
Some mfree),
(
Mem.mem_contents mfree) #
b' = (
Mem.mem_contents m) #
b'.
Proof.
Opaque Mem.free.
Lemma free_alloc_mem_inj:
forall IF m tm b tb b' lo hi mfree malloc
(
BAD:
IF b' =
None)
(
BOUNDS':
forall ofs k p, (
lo <=
ofs <
hi ->
Mem.perm m b ofs k p))
(
MEM_INJ :
Mem.mem_inj IF m tm)
(
BLK_INJ:
match_sp IF b tb)
(
FREE :
Mem.free m b lo hi =
Some mfree)
(
ALLOC :
Mem.alloc mfree lo hi = (
malloc,
b')),
Mem.mem_inj (
meminj_subst IF b b')
malloc tm.
Proof.
intros.
unfold meminj_subst.
destruct MEM_INJ.
constructor;
intros.
-
destruct (
peq b1 b').
+
subst b1.
apply mi_perm with (
b1 :=
b).
assumption.
apply BOUNDS'.
eapply Mem.perm_alloc_3.
exact ALLOC.
exact H0.
+
apply mi_perm with (
b1:=
b1).
assumption.
eapply Mem.perm_free_3.
exact FREE.
eapply Mem.perm_alloc_4.
exact ALLOC.
all:
auto.
-
destruct (
peq b1 b').
+
subst b1.
eapply mi_align with (
ofs:=
ofs) (
p:=
p).
exact H.
intros z zRANGE.
apply BOUNDS'.
eapply Mem.perm_alloc_3.
exact ALLOC.
exact (
H0 z zRANGE).
+
eapply mi_align with (
ofs:=
ofs) (
p:=
p).
exact H.
intros z zRANGE.
eapply Mem.perm_free_3.
exact FREE.
eapply Mem.perm_alloc_4.
exact ALLOC.
apply H0.
all:
auto.
-
destruct (
peq b1 b').
+
subst b1.
rewrite (
malloc_undef _ _ _ _ _ _
ALLOC).
constructor.
+
rewrite (
mem_alloc_contents_before _ _ _ _ _ _
ALLOC)
by lia.
rewrite (
mem_free_contents_before _ _ _ _ _ _
FREE).
pose proof (
Mem.perm_alloc_4 _ _ _ _ _
ALLOC _ _ _ _
H0 n)
as PERM_FREE.
pose proof (
Mem.perm_free_3 _ _ _ _ _
FREE _ _ _ _
PERM_FREE)
as PERM.
pose proof (
mi_memval _ _ _ _
H PERM)
as INJECT.
destruct (
ZMap.get ofs (
Mem.mem_contents m) #
b1).
all:
inv INJECT;
constructor.
inv H2;
try constructor.
econstructor;
cycle 1.
reflexivity.
destruct (
peq b0 b'). 2:
assumption.
subst b0.
congruence.
Qed.
Lemma free_alloc_no_overlap:
forall IF m b b' lo hi mfree malloc
(
BAD:
IF b' =
None)
(
BOUNDS:
forall ofs k p, (
Mem.perm m b ofs k p ->
lo <=
ofs <
hi))
(
BOUNDS':
forall ofs k p, (
lo <=
ofs <
hi ->
Mem.perm m b ofs k p))
(
MEM_INJ :
Mem.meminj_no_overlap IF m)
(
FREE :
Mem.free m b lo hi =
Some mfree)
(
ALLOC :
Mem.alloc mfree lo hi = (
malloc,
b')),
Mem.meminj_no_overlap (
meminj_subst IF b b')
malloc.
Proof.
unfold Mem.meminj_no_overlap,
meminj_subst.
intros.
destruct (
peq b1 b')
as [
EQ1 |
NEQ1].
-
subst b1.
pose proof (
Mem.perm_alloc_3 _ _ _ _ _
ALLOC _ _ _
H2)
as RANGE1.
pose proof (
BOUNDS' _
Max Nonempty RANGE1)
as PERM1.
destruct (
peq b2 b')
as [
EQ2 |
NEQ2].
+
subst b2.
contradiction.
+
pose proof (
Mem.perm_alloc_4 _ _ _ _ _
ALLOC _ _ _ _
H3 NEQ2)
as PERM_FREE2.
pose proof (
Mem.perm_free_3 _ _ _ _ _
FREE _ _ _ _
PERM_FREE2)
as PERM2.
destruct (
peq b b2).
*
subst b2.
exfalso.
pose proof (
BOUNDS _ _ _
PERM2)
as RANGE2.
exact (
Mem.perm_free_2 _ _ _ _ _
FREE _ _ _
RANGE2 PERM_FREE2).
*
apply MEM_INJ with (
b1:=
b) (
b2:=
b2);
trivial.
-
pose proof (
Mem.perm_alloc_4 _ _ _ _ _
ALLOC _ _ _ _
H2 NEQ1)
as PERM_FREE1.
pose proof (
Mem.perm_free_3 _ _ _ _ _
FREE _ _ _ _
PERM_FREE1)
as PERM1.
destruct (
peq b2 b')
as [
EQ2 |
NEQ2].
+
subst b2.
clear H.
pose proof (
Mem.perm_alloc_3 _ _ _ _ _
ALLOC _ _ _
H3)
as RANGE2.
destruct (
peq b b1).
*
subst b1.
pose proof (
BOUNDS _ _ _
PERM1)
as RANGE1.
exfalso.
exact (
Mem.perm_free_2 _ _ _ _ _
FREE _ _ _
RANGE1 PERM_FREE1).
*
apply MEM_INJ with (
b1:=
b1) (
b2:=
b);
trivial.
congruence.
apply BOUNDS'.
assumption.
+
pose proof (
Mem.perm_alloc_4 _ _ _ _ _
ALLOC _ _ _ _
H3 NEQ2)
as PERM_FREE2.
pose proof (
Mem.perm_free_3 _ _ _ _ _
FREE _ _ _ _
PERM_FREE2)
as PERM2.
apply MEM_INJ with (
b1:=
b1) (
b2:=
b2);
trivial.
Qed.
Lemma free_alloc_inject:
forall IF m tm b tb b' lo hi mfree malloc
(
BOUNDS:
forall ofs k p, (
Mem.perm m b ofs k p ->
lo <=
ofs <
hi))
(
BOUNDS':
forall ofs k p, (
lo <=
ofs <
hi ->
Mem.perm m b ofs k p))
(
MEM_INJ :
Mem.inject IF m tm)
(
BLK_INJ:
match_sp IF b tb)
(
FREE :
Mem.free m b lo hi =
Some mfree)
(
ALLOC :
Mem.alloc mfree lo hi = (
malloc,
b')),
Mem.inject (
meminj_subst IF b b')
malloc tm.
Proof.
Lemma good_meminj_def_invariant:
forall good IF (
GOOD:
good_meminj good IF)
b de
(
FIND:
Genv.find_def ge b =
Some de),
(
IF b) =
Some(
b, 0%
Z).
Proof.
intros. destruct GOOD. eauto.
Qed.
Lemma find_function_injects:
forall good IF (
GOOD:
good_meminj good IF)
v tv (
INJECT :
Val.inject IF v tv)
fd
(
FIND:
Genv.find_funct ge v =
Some fd)
tfd
(
tFIND:
Genv.find_funct tge v =
Some tfd),
(
Genv.find_funct tge tv =
Some tfd).
Proof.
Lemma good_meminj_separated:
forall bound IF IF' m tm
(
NEXT_TM:
Ple bound (
Mem.nextblock tm))
(
GOOD:
good_meminj bound IF)
(
MATCH_MEM:
Mem.inject IF m tm)
(
INCR:
inject_incr IF IF')
(
SEPARATED:
inject_separated IF IF' m tm),
(
good_meminj bound IF').
Proof.
intros.
destruct GOOD.
constructor;
intros.
-
eauto.
-
eauto.
-
pose proof (
good_meminj_fixes0 _
H)
as IFb.
exact (
INCR _ _ _
IFb).
-
destruct (
IF b)
as [[
img_b delta_b] | ]
eqn:
IFb.
+
pose proof (
INCR _ _ _
IFb).
rewrite H0 in H1.
inv H1.
exact (
good_meminj_nocollide0 _ _ _
H IFb).
+
unfold inject_separated in *.
destruct (
SEPARATED _ _ _
IFb H0)
as [
INVALID INVALID'].
unfold Mem.valid_block,
Plt,
Ple in *.
lia.
Qed.
Remark storev_nextblock:
forall chunk tm tm2 ta trs,
(
Mem.storev chunk tm ta trs) =
Some tm2 ->
Mem.nextblock tm2 =
Mem.nextblock tm.
Proof.
Remark good_meminj_alloc:
forall bound m tm stk stk'
(
IF IF' :
meminj)
(
NEXT_M :
Ple bound (
Mem.nextblock m))
(
NEXT_TM :
Ple bound (
Mem.nextblock tm))
(
GLOBALS :
good_meminj bound IF)
(
INJECT_INCR :
inject_incr IF IF')
(
STK' :
IF' stk =
Some (
stk', 0))
(
BLOCKS :
forall b :
block,
b <>
stk ->
IF' b =
IF b)
(
NSTK :
stk =
Mem.nextblock m)
(
NSTK' :
stk' =
Mem.nextblock tm),
good_meminj bound IF'.
Proof.
intros.
destruct GLOBALS.
constructor.
-
eauto.
-
eauto.
-
intros.
unfold Plt,
Ple in *.
destruct (
peq b stk)
as [
EQ |
NEQ].
lia.
rewrite BLOCKS by assumption.
apply good_meminj_fixes0;
assumption.
-
intros.
destruct (
peq b stk).
+
subst b.
rewrite STK' in H0.
inv H0.
assumption.
+
rewrite BLOCKS in H0 by assumption.
eapply good_meminj_nocollide0.
exact H.
exact H0.
Qed.
Remark good_meminj_subst:
forall bound IF sp stk
(
SP:
Ple bound sp)
(
STK :
Ple bound stk)
(
GOOD :
good_meminj bound IF),
good_meminj bound (
meminj_subst IF sp stk).
Proof.
intros.
destruct GOOD.
constructor.
-
eauto.
-
eauto.
-
intros.
unfold meminj_subst.
destruct (
peq b stk).
+
unfold Plt,
Ple in *.
lia.
+
auto.
-
intros.
unfold meminj_subst in H0.
destruct (
peq b stk).
+
subst b.
exact (
good_meminj_nocollide0 sp _ _
SP H0).
+
exact (
good_meminj_nocollide0 b _ _
H H0).
Qed.
Theorem step_simulation:
forall S1 t S2,
step ge S1 t S2 ->
forall S1' (
MS:
match_states S1 S1'),
(
exists S2',
plus step tge S1' t S2' /\
match_states S2 S2')
\/ (
measure S2 <
measure S1 /\
t =
E0 /\
match_states S2 S1')%
nat.
Proof.
intros.
inv H;
inv MS.
-
left.
eexists.
split.
+
apply plus_one.
apply exec_Inop;
trivial.
erewrite transf_function_preserves with (
id :=
id) (
f :=
f).
1,3:
eassumption.
rewrite H0;
trivial.
+
econstructor;
eauto.
-
left.
assert (
Val.inject_list IF rs ##
args trs ##
args)
as INJECT.
{
apply match_regs_args with (
f :=
f).
assumption.
intros.
eapply max_reg_function_use.
eassumption.
assumption. }
inv MATCH_SP.
destruct (
eval_operation_inject (
good_meminj_preserves_globals _ _
GLOBALS)
sp0 H2 op INJECT MATCH_MEM H1)
as (
tv &
EVAL &
INJ).
rewrite eval_shift_stack_operation in EVAL.
fold (
block2sp tsp)
in EVAL.
eexists.
split.
+
apply plus_one.
apply exec_Iop with (
op :=
op) (
args :=
args) (
v :=
tv).
{
erewrite transf_function_preserves with (
id :=
id) (
f :=
f).
1,3:
eassumption.
{
rewrite H0;
trivial. }
}
rewrite eval_operation_preserved with (
ge1 :=
ge).
exact EVAL.
apply symbols_preserved.
+
apply match_states_intro with (
cu:=
cu) (
bound:=
bound) (
IF:=
IF) (
id:=
id);
trivial.
apply match_regs_assign;
trivial.
eapply max_reg_function_def with (
pc :=
pc).
eassumption.
reflexivity.
-
left.
assert (
Val.inject_list IF rs ##
args trs ##
args)
as INJECT.
{
apply match_regs_args with (
f :=
f).
assumption.
intros.
eapply max_reg_function_use.
eassumption.
assumption. }
inv MATCH_SP.
inv H1.
+
destruct (
eval_addressing_inject (
good_meminj_preserves_globals _ _
GLOBALS)
sp0 H2 addr INJECT EVAL)
as (
tv &
ADDR &
INJ).
rewrite eval_shift_stack_addressing in ADDR.
fold (
block2sp tsp)
in ADDR.
rename tv into ta.
destruct (
Mem.loadv_inject IF m tm chunk _ _ _
MATCH_MEM LOAD INJ)
as (
tv &
TLOAD &
INJV).
eexists.
split.
*
apply plus_one.
apply exec_Iload with (
trap :=
trap) (
chunk :=
chunk) (
addr :=
addr) (
args :=
args).
{
erewrite transf_function_preserves with (
id :=
id) (
f :=
f).
1,3:
eassumption.
rewrite H0;
trivial.
}
eapply has_loaded_normal.
{
rewrite eval_addressing_preserved with (
ge1 :=
ge)
by apply symbols_preserved.
exact ADDR. }
exact TLOAD.
*
apply match_states_intro with (
cu:=
cu) (
bound:=
bound) (
IF:=
IF) (
id:=
id);
trivial.
apply match_regs_assign;
trivial.
eapply max_reg_function_def with (
pc :=
pc).
eassumption.
reflexivity.
+
destruct (
eval_addressing tge (
block2sp tsp)
addr trs ##
args)
as [
ta | ]
eqn:
TEVAL.
*
destruct (
eval_addressing ge (
block2sp sp0)
addr rs ##
args)
as [
a | ]
eqn:
EVAL.
--
destruct (
eval_addressing_inject (
good_meminj_preserves_globals _ _
GLOBALS)
sp0 H2 addr INJECT EVAL)
as (
tv &
ADDR &
INJ).
rewrite eval_shift_stack_addressing in ADDR.
fold (
block2sp tsp)
in ADDR.
rename tv into ta2.
rewrite eval_addressing_preserved with (
ge1 :=
ge)
in TEVAL by apply symbols_preserved.
replace ta2 with ta in INJ by congruence.
clear ADDR ta2.
assert (
Mem.loadv chunk m a =
None)
as LOAD_NONE by auto.
clear LOAD.
destruct (
Mem.loadv chunk tm ta)
as [
tv | ]
eqn:
LOAD'.
++
exists (
State ts tf (
block2sp tsp)
pc' trs #
dst <-
tv tm).
split.
**
apply plus_one.
apply exec_Iload with (
trap:=
NOTRAP) (
chunk:=
chunk) (
addr:=
addr) (
args:=
args).
{
erewrite transf_function_preserves with (
id :=
id) (
f :=
f).
1,3:
eassumption.
{
rewrite H0;
trivial. }
}
eapply has_loaded_normal.
{
rewrite <-
eval_addressing_preserved with (
ge2 :=
tge)
in TEVAL by apply symbols_preserved.
exact TEVAL. }
exact LOAD'.
**
apply match_states_intro with (
cu:=
cu) (
bound:=
bound) (
IF:=
IF) (
id:=
id);
trivial.
apply match_regs_assign;
trivial.
eapply max_reg_function_def with (
pc :=
pc).
eassumption.
reflexivity.
++
exists (
State ts tf (
block2sp tsp)
pc' trs #
dst <-
Vundef tm).
split.
**
apply plus_one.
apply exec_Iload with (
trap:=
NOTRAP) (
chunk:=
chunk) (
addr:=
addr) (
args:=
args).
{
erewrite transf_function_preserves with (
id :=
id) (
f :=
f).
1,3:
eassumption.
{
rewrite H0;
trivial. }
}
apply has_loaded_default. 2:
reflexivity.
intros ta' TEVAL'.
rewrite eval_addressing_preserved with (
ge1 :=
ge)
in TEVAL' by apply symbols_preserved.
replace ta' with ta by congruence.
assumption.
**
apply match_states_intro with (
cu:=
cu) (
bound:=
bound) (
IF:=
IF) (
id:=
id);
trivial.
apply match_regs_assign;
trivial.
eapply max_reg_function_def with (
pc :=
pc).
eassumption.
reflexivity.
--
destruct (
Mem.loadv chunk tm ta)
as [
tv | ]
eqn:
LOAD'.
++
exists (
State ts tf (
block2sp tsp)
pc' trs #
dst <-
tv tm).
split.
**
apply plus_one.
apply exec_Iload with (
trap:=
NOTRAP) (
chunk:=
chunk) (
addr:=
addr) (
args:=
args).
{
erewrite transf_function_preserves with (
id :=
id) (
f :=
f).
1,3:
eassumption.
{
rewrite H0;
trivial. }
}
apply has_loaded_normal with (
a:=
ta);
trivial.
**
apply match_states_intro with (
cu:=
cu) (
bound:=
bound) (
IF:=
IF) (
id:=
id);
trivial.
apply match_regs_assign;
trivial.
eapply max_reg_function_def with (
pc :=
pc).
eassumption.
reflexivity.
++
exists (
State ts tf (
block2sp tsp)
pc' trs #
dst <-
Vundef tm).
split.
**
apply plus_one.
apply exec_Iload with (
trap:=
NOTRAP) (
chunk:=
chunk) (
addr:=
addr) (
args:=
args).
{
erewrite transf_function_preserves with (
id :=
id) (
f :=
f).
1,3:
eassumption.
{
rewrite H0;
trivial. }
}
apply has_loaded_default.
intros ta' TEVAL'.
replace ta' with ta by congruence.
assumption.
reflexivity.
**
apply match_states_intro with (
cu:=
cu) (
bound:=
bound) (
IF:=
IF) (
id:=
id);
trivial.
apply match_regs_assign;
trivial.
eapply max_reg_function_def with (
pc :=
pc).
eassumption.
reflexivity.
*
exists (
State ts tf (
block2sp tsp)
pc' trs #
dst <-
Vundef tm).
split.
**
apply plus_one.
apply exec_Iload with (
trap:=
NOTRAP) (
chunk:=
chunk) (
addr:=
addr) (
args:=
args).
{
erewrite transf_function_preserves with (
id :=
id) (
f :=
f).
1,3:
eassumption.
rewrite H0;
trivial.
}
apply has_loaded_default.
intros ta TADDR.
congruence.
reflexivity.
**
apply match_states_intro with (
cu:=
cu) (
bound:=
bound) (
IF:=
IF) (
id:=
id);
trivial.
apply match_regs_assign;
trivial.
eapply max_reg_function_def with (
pc :=
pc).
eassumption.
reflexivity.
-
left.
assert (
Val.inject_list IF rs ##
args trs ##
args)
as INJECT.
{
apply match_regs_args with (
f :=
f).
assumption.
intros.
eapply max_reg_function_use.
eassumption.
right.
assumption. }
inv MATCH_SP.
destruct (
eval_addressing_inject (
good_meminj_preserves_globals _ _
GLOBALS)
sp0 H3 addr INJECT H1)
as (
tv &
ADDR &
INJ).
rewrite eval_shift_stack_addressing in ADDR.
fold (
block2sp tsp)
in ADDR.
rename tv into ta.
assert (
Val.inject IF rs#
src trs#
src)
as INJECT_SRC.
{
inv MATCH_REGS.
apply REG_INJECT.
eapply max_reg_function_use.
eassumption.
constructor.
reflexivity. }
destruct (
Mem.storev_mapped_inject IF _ _ _ _ _
tm _ _
MATCH_MEM H2 INJ INJECT_SRC)
as (
m2' &
STORE &
INJm2').
eexists.
split.
+
apply plus_one.
apply exec_Istore with (
chunk:=
chunk) (
addr:=
addr) (
args :=
args) (
src :=
src) (
a :=
ta).
*
erewrite transf_function_preserves with (
id :=
id) (
f :=
f).
1,3:
eassumption.
rewrite H0;
trivial.
*
rewrite eval_addressing_preserved with (
ge1 :=
ge)
by apply symbols_preserved.
exact ADDR.
*
exact STORE.
+
apply match_states_intro with (
cu:=
cu) (
bound:=
bound) (
IF:=
IF) (
id:=
id);
trivial.
*
eapply storev_weakly_allocated_block;
eassumption.
*
pose proof (
storev_nextblock _ _ _ _ _
H2).
unfold Plt in *.
lia.
*
eapply storev_weakly_allocated_stack;
eassumption.
*
pose proof (
storev_nextblock _ _ _ _ _
H2).
unfold Ple in *.
lia.
*
pose proof (
storev_nextblock _ _ _ _ _
STORE).
unfold Ple in *.
lia.
-
destruct ros as [
reg |
symbol].
+
left.
cbn in H1.
destruct (
functions_translated _ _
H1)
as (
tcu &
tfd &
tcu_LINK &
FIND_FD &
MATCH_FD).
destruct MATCH_FD as (
cu' &
id' &
LINK' &
TRANS').
eexists.
split.
*
apply plus_one.
eapply exec_Icall with (
ros :=
inl reg).
{
erewrite transf_function_preserves with (
id :=
id) (
f :=
f).
1,3:
eassumption.
{
rewrite H0;
trivial. }
}
{
eapply find_function_injects.
eassumption.
{
destruct MATCH_REGS.
apply REG_INJECT.
eapply max_reg_function_use.
eassumption.
cbn.
left.
reflexivity. }
eassumption.
eassumption.
}
eapply sig_fundef_translated.
eassumption.
*
eapply match_states_call with (
cu:=
cu') (
bound:=
bound) (
IF:=
IF) (
id:=
id');
trivial.
--
eapply linkorder_trans;
eassumption.
--
constructor;
trivial.
--
constructor. 2:
assumption.
constructor.
assumption.
--
constructor. 2:
assumption.
apply match_stackframes_intro with (
id:=
id) (
cu:=
cu);
trivial.
{
eapply max_reg_function_def.
eassumption.
reflexivity. }
--
eapply match_regs_args.
eassumption.
intros.
eapply max_reg_function_use.
eassumption.
right.
assumption.
+
left.
simpl in H1.
destruct (
Genv.find_symbol ge symbol)
eqn:
FIND. 2:
discriminate.
destruct (
function_ptr_translated b _
H1)
as (
tcu' &
tcu'_LINK &
f' &
FIND' &
MATCH').
eexists.
split.
*
apply plus_one.
eapply exec_Icall with (
ros :=
inr symbol).
{
erewrite transf_function_preserves with (
id :=
id) (
f :=
f).
1,3:
eassumption.
{
rewrite H0;
trivial. }
}
{
simpl.
rewrite symbols_preserved.
rewrite FIND.
exact FIND'.
}
destruct MATCH' as (
cu' &
id' &
LINK' &
TRANS').
exact (
sig_fundef_translated _ _ _ _
TRANS').
*
destruct MATCH' as (
cu' &
id' &
LINK' &
TRANS').
apply match_states_call with (
cu:=
cu') (
id:=
id') (
bound:=
bound) (
IF:=
IF);
trivial.
--
eapply linkorder_trans;
eassumption.
--
constructor;
trivial.
--
constructor. 2:
assumption.
constructor.
assumption.
--
constructor. 2:
assumption.
apply match_stackframes_intro with (
id:=
id) (
cu:=
cu);
trivial.
{
eapply max_reg_function_def.
eassumption.
reflexivity. }
--
eapply match_regs_args.
eassumption.
intros.
eapply max_reg_function_use.
eassumption.
exact H.
-
destruct ros as [
reg |
symbol].
+
left.
cbn in H1.
destruct (
functions_translated _ _
H1)
as (
tcu &
tcu_LINK &
tfd &
FIND_FD &
MATCH_FD).
destruct (
Mem.free_parallel_inject IF m tm _ _ _ _ _ _
MATCH_MEM H3 MATCH_SP)
as (
tm' &
FREE &
MATCH_MEM').
change (0 + 0)
with 0
in FREE.
rewrite Z.add_0_r in FREE.
destruct MATCH_FD as (
cu' &
id' &
LINK' &
TRANS').
eexists.
split.
*
apply plus_one.
eapply exec_Itailcall with (
ros :=
inl reg).
--
erewrite transf_function_preserves with (
id :=
id) (
f :=
f).
1,3:
eassumption.
rewrite H0;
trivial.
--
eapply find_function_injects.
eassumption.
{
destruct MATCH_REGS.
apply REG_INJECT.
eapply max_reg_function_use.
eassumption.
cbn.
left.
reflexivity. }
eassumption.
eassumption.
--
eapply sig_fundef_translated.
eassumption.
--
erewrite stacksize_function_translated with (
id:=
id) (
f:=
f)
by eassumption.
exact FREE.
*
apply match_states_call with (
cu:=
cu') (
bound:=
bound) (
IF:=
IF) (
id:=
id');
trivial.
--
eapply linkorder_trans;
eassumption.
--
rewrite (
Mem.nextblock_free _ _ _ _ _
H3).
eapply ubound_stack_advance. 2:
eassumption.
unfold Ple,
Plt in *.
lia.
--
eapply free_weakly_allocated_stack.
++
apply ubound_not_in_stack.
eassumption.
++
eassumption.
++
eassumption.
--
pose proof (
Mem.nextblock_free _ _ _ _ _
H3).
unfold Ple in *.
lia.
--
pose proof (
Mem.nextblock_free _ _ _ _ _
FREE).
unfold Ple in *.
lia.
--
eapply match_regs_args.
eassumption.
intros.
eapply max_reg_function_use.
eassumption.
right.
eassumption.
+
destruct ((
QualIdent.eq id symbol) &&
(
Nat.eq_dec (
List.length args) (
List.length (
fn_params f))))
eqn:
ACTIVATE.
*
right.
split.
{
cbn.
lia. }
split.
reflexivity.
destruct (
QualIdent.eq id symbol). 2:
discriminate.
subst symbol.
destruct (
Nat.eq_dec (
Datatypes.length args)
(
Datatypes.length (
fn_params f)))
as [
LENGTHS | ].
2:
discriminate.
clear ACTIVATE.
assert (
fd =
Internal f)
as FD.
{
unfold find_function in *.
destruct Genv.find_symbol eqn:
SYMBOL. 2:
discriminate.
unfold Genv.find_funct_ptr in *.
destruct (
Genv.find_def ge b)
eqn:
FIND_DEF. 2:
discriminate.
assert ((
prog_defmap prog)!.
id =
Some g)
as DEFMAP.
{
apply Genv.find_def_symbol.
exists b;
auto. }
destruct g. 2:
discriminate.
inv H1.
unfold transf_function in *.
destruct option_eq_dec as [
EQ2 | ]. 2:
discriminate.
clear MATCH_FUNCTIONS.
unfold find_function in *.
destruct (
Genv.find_symbol (
Genv.globalenv cu)
id)
as [
b2 | ]
eqn:
SYMBOL2. 2:
discriminate.
unfold Genv.find_funct_ptr in *.
destruct (
Genv.find_def (
Genv.globalenv cu)
b2)
eqn:
FIND_DEF2. 2:
discriminate.
assert ((
prog_defmap cu)!.
id =
Some g)
as DEFMAP2.
{
apply Genv.find_def_symbol.
exists b2;
auto. }
destruct g. 2:
discriminate.
inv EQ2.
destruct (
prog_defmap_linkorder _ _ _ _
LINK DEFMAP2)
as (
gd3 &
DEFMAP3 &
LINK3).
rewrite DEFMAP in DEFMAP3.
inv DEFMAP3.
inv LINK3.
inv H2.
reflexivity.
}
rewrite FD.
eapply match_states_tail_rec with (
sp:=
stk) (
m:=
m);
try eassumption.
apply Forall_forall.
intros.
assert (
x <= (
max_reg_function f))%
positive.
{
eapply max_reg_function_use.
eassumption.
cbn.
assumption. }
lia.
*
left.
simpl in H1.
destruct (
Genv.find_symbol ge symbol)
eqn:
FIND. 2:
discriminate.
destruct (
function_ptr_translated b _
H1)
as (
tcu' &
tcu'_LINK &
f' &
FIND' &
MATCH').
destruct (
Mem.free_parallel_inject IF m tm _ _ _ _ _ _
MATCH_MEM H3 MATCH_SP)
as (
tm' &
FREE &
MATCH_MEM').
change (0 + 0)
with 0
in FREE.
rewrite Z.add_0_r in FREE.
eexists.
split.
--
apply plus_one.
eapply exec_Itailcall.
++
erewrite transf_function_preserves with (
id :=
id) (
f :=
f).
1,3:
eassumption.
rewrite H0.
rewrite ACTIVATE.
trivial.
++
simpl.
rewrite symbols_preserved.
rewrite FIND.
exact FIND'.
++
destruct MATCH' as (
cu' &
id' &
LINK' &
TRANS').
exact (
sig_fundef_translated _ _ _ _
TRANS').
++
erewrite stacksize_function_translated with (
id:=
id) (
f:=
f)
by eassumption.
exact FREE.
--
destruct MATCH' as (
cu' &
id' &
LINK' &
TRANS').
apply match_states_call with (
cu:=
cu') (
bound:=
bound) (
IF:=
IF) (
id:=
id');
trivial.
++
eapply linkorder_trans;
eassumption.
++
eapply ubound_stack_advance. 2:
eassumption.
pose proof (
Mem.nextblock_free _ _ _ _ _
H3).
unfold Ple,
Plt in *.
lia.
++
eapply free_weakly_allocated_stack.
**
apply ubound_not_in_stack.
eassumption.
**
eassumption.
**
eassumption.
++
pose proof (
Mem.nextblock_free _ _ _ _ _
H3).
unfold Ple in *.
lia.
++
pose proof (
Mem.nextblock_free _ _ _ _ _
FREE).
unfold Ple in *.
lia.
++
eapply match_regs_args.
eassumption.
intros.
eapply max_reg_function_use.
eassumption.
assumption.
-
left.
assert (
Forall (
fun r :
positive =>
Val.inject IF rs #
r trs #
r)
(
params_of_builtin_args args))
as INJ_ARGS.
{
apply Forall_forall.
intros r IN.
inv MATCH_REGS.
apply REG_INJECT.
eapply max_reg_function_use.
exact H0.
exact IN.
}
pose proof (
eval_builtin_args_preserved _
symbols_preserved H1)
as ARGS.
destruct (
eval_builtin_args_inject bound IF args vargs rs trs m tm sp0 tsp GLOBALS INJ_ARGS MATCH_MEM MATCH_SP ARGS)
as (
tvargs &
EVAL' &
INJ').
destruct (
external_call_mem_inject _ _ _ _ (
good_meminj_preserves_globals _ _
GLOBALS)
H2 MATCH_MEM INJ')
as
(
IF' &
vres' &
m2' &
CALL' &
RES_INJ &
MEM_INJ &
UNCHANGED1 &
UNCHANGED2 &
INCR &
SEPARATED).
eexists.
split.
+
apply plus_one.
eapply exec_Ibuiltin with (
ef:=
ef) (
args:=
args) (
res:=
res).
{
erewrite transf_function_preserves with (
id :=
id) (
f :=
f).
1,3:
eassumption.
{
rewrite H0;
trivial. }
}
exact EVAL'.
apply external_call_symbols_preserved with (
ge1 :=
ge).
{
apply senv_preserved. }
exact CALL'.
+
apply match_states_intro with (
cu:=
cu) (
bound:=
bound) (
IF:=
IF') (
id:=
id);
trivial.
*
eapply external_call_weakly_allocated_block;
eassumption.
*
pose proof (
external_call_nextblock _ _ _ _ _ _ _
H2).
unfold Plt,
Ple in *.
lia.
*
eapply external_call_weakly_allocated_stack;
try eassumption.
eapply ubound_stack_advance. 2:
eassumption.
unfold Plt,
Ple in *.
lia.
*
pose proof (
external_call_nextblock _ _ _ _ _ _ _
H2).
unfold Plt,
Ple in *.
lia.
*
pose proof (
external_call_nextblock _ _ _ _ _ _ _
CALL').
unfold Plt,
Ple in *.
lia.
*
apply good_meminj_separated with (
IF:=
IF) (
m:=
m) (
tm:=
tm);
trivial.
*
apply match_stacks_incr with (
IF :=
IF);
trivial.
*
destruct res eqn:
RES;
cbn;
trivial.
apply match_regs_assign;
trivial.
pose proof (
max_reg_function_def _ _ _
x H0)
as ZZ.
apply ZZ.
reflexivity.
all:
apply match_regs_incr with (
IF:=
IF);
trivial.
*
apply match_sp_incr with (
IF:=
IF);
assumption.
-
left.
assert (
Val.inject_list IF rs ##
args trs ##
args)
as INJECT.
{
apply match_regs_args with (
f :=
f).
assumption.
intros.
eapply max_reg_function_use.
eassumption.
assumption. }
inv MATCH_SP.
pose proof (
eval_condition_inject cond INJECT MATCH_MEM H1)
as EVAL.
eexists.
split.
+
apply plus_one.
apply exec_Icond with (
cond:=
cond) (
args:=
args)
(
ifso:=
ifso) (
ifnot:=
ifnot) (
b:=
b) (
predb :=
predb).
{
erewrite transf_function_preserves with (
id :=
id) (
f :=
f).
1,3:
eassumption.
rewrite H0;
trivial.
}
assumption.
reflexivity.
+
apply match_states_intro with (
cu:=
cu) (
bound:=
bound) (
IF :=
IF) (
id :=
id);
trivial.
-
left.
assert (
Val.inject IF rs#
arg trs#
arg)
as INJECT.
{
inv MATCH_REGS.
apply REG_INJECT.
eapply max_reg_function_use.
eassumption.
constructor.
reflexivity. }
eexists.
split.
+
apply plus_one.
apply exec_Ijumptable with (
arg:=
arg) (
tbl:=
tbl) (
n:=
n).
{
erewrite transf_function_preserves with (
id :=
id) (
f :=
f).
1,3:
eassumption.
rewrite H0;
trivial.
}
rewrite H1 in INJECT.
inv INJECT.
reflexivity.
exact H2.
+
apply match_states_intro with (
cu:=
cu) (
bound:=
bound) (
IF:=
IF) (
id:=
id);
auto.
-
left.
destruct (
Mem.free_parallel_inject IF m tm _ _ _ _ _ _
MATCH_MEM H1 MATCH_SP)
as (
tm' &
FREE &
MATCH_MEM').
rewrite Z.add_0_r in FREE.
rewrite Z.add_0_r in FREE.
eexists.
split.
+
apply plus_one.
apply exec_Ireturn.
{
erewrite transf_function_preserves with (
id :=
id) (
f :=
f).
1,3:
eassumption.
rewrite H0;
trivial.
}
erewrite stacksize_function_translated with (
id :=
id) (
f :=
f)
by eassumption.
exact FREE.
+
apply match_states_return with (
bound:=
bound) (
IF:=
IF);
auto.
*
eapply ubound_stack_advance. 2:
eassumption.
rewrite (
Mem.nextblock_free _ _ _ _ _
H1).
unfold Ple,
Plt in *.
lia.
*
eapply free_weakly_allocated_stack.
--
apply ubound_not_in_stack.
eassumption.
--
eassumption.
--
eassumption.
*
pose proof (
Mem.nextblock_free _ _ _ _ _
H1).
unfold Ple in *.
lia.
*
pose proof (
Mem.nextblock_free _ _ _ _ _
FREE).
unfold Ple in *.
lia.
*
destruct or;
cbn. 2:
constructor.
inv MATCH_REGS.
apply REG_INJECT.
eapply max_reg_function_use.
eassumption.
constructor.
reflexivity.
-
left.
eapply eval_assert_args_inject in H1 as (?&
EVAL&?);
eauto.
2:{
eapply Forall_forall;
intros.
eapply MATCH_REGS,
max_reg_function_use;
eauto. }
do 2
esplit.
+
apply plus_one.
eapply exec_Iassert;
eauto.
erewrite transf_function_preserves with (
id :=
id) (
f :=
f);
eauto.
rewrite H0;
trivial.
eapply eval_condition_inject;
eauto.
+
econstructor;
eauto.
-
monadInv MATCH_FUNCTIONS.
rename x into tf.
assert (0 <= 0)
as LE0 by lia.
assert (
fn_stacksize f <=
fn_stacksize f)
as HI by lia.
destruct (
Mem.alloc_parallel_inject IF m tm _ _ _ _ 0 (
fn_stacksize f)
MATCH_MEM H1 LE0 HI)
as (
IF' &
m2' &
stk' &
ALLOC' &
MATCH_MEM' &
INJECT_INCR &
STK' &
BLOCKS).
left.
eexists.
split.
+
apply plus_one.
apply exec_function_internal.
*
rewrite (
sig_function_translated _ _ _ _
EQ).
eapply Val.has_argtype_list_inject;
eassumption.
*
erewrite stacksize_function_translated with (
id :=
id) (
f :=
f)
by eassumption.
exact ALLOC'.
+
erewrite entrypoint_function_translated with (
f' :=
tf) (
id :=
id) (
f :=
f)
by eassumption.
erewrite params_function_translated with (
f' :=
tf) (
id :=
id) (
f :=
f)
by eassumption.
apply match_states_intro with (
cu:=
cu) (
bound:=
bound) (
IF:=
IF') (
id:=
id);
trivial.
*
eapply alloc_new_weakly_allocated_block.
exact H1.
*
pose proof (
Mem.alloc_result _ _ _ _ _
H1)
as NSTK.
pose proof (
Mem.nextblock_alloc _ _ _ _ _
H1).
unfold Ple,
Plt in *.
lia.
*
eapply ubound_stack_advance. 2:
eassumption.
pose proof (
Mem.alloc_result _ _ _ _ _
H1)
as NSTK.
unfold Ple,
Plt in *.
lia.
*
eapply alloc_keep_weakly_allocated_stack;
eassumption.
*
pose proof (
Mem.alloc_result _ _ _ _ _
H1)
as NSTK.
unfold Ple in *.
lia.
*
pose proof (
Mem.nextblock_alloc _ _ _ _ _
H1).
unfold Ple in *.
lia.
*
pose proof (
Mem.nextblock_alloc _ _ _ _ _
ALLOC').
unfold Ple in *.
lia.
*
pose proof (
Mem.alloc_result _ _ _ _ _
H1)
as NSTK.
pose proof (
Mem.alloc_result _ _ _ _ _
ALLOC')
as NSTK'.
apply (
good_meminj_alloc bound m tm stk stk' IF IF');
auto.
*
apply match_stacks_incr with (
IF:=
IF);
trivial.
*
apply match_regs_params.
eapply val_inject_list_incr.
exact INJECT_INCR.
assumption.
apply Forall_forall.
intros.
apply max_reg_function_params.
assumption.
-
left.
destruct (
transf_function_tail_rec _ _ _ _ _ _ _
MATCH_FUNCTIONS AT LENGTHS)
as (
next_pc &
JUMP1 &
REC_CALL).
rewrite <- (
params_function_translated _ _ _ _
MATCH_FUNCTIONS)
in LENGTHS.
rewrite <- (
params_function_translated _ _ _ _
MATCH_FUNCTIONS)
in REC_CALL.
assert (
Forall
(
fun r :
positive => (
r <=
max_reg_function f)%
positive)
(
fn_params f))
as PARAMS_OK.
{
apply Forall_forall.
intros.
apply max_reg_function_params.
assumption. }
assert (
Forall
(
fun r :
positive => (
r <
Pos.succ (
max_reg_function f))%
positive)
(
fn_params f))
as PARAMS_OK'.
{
apply Forall_forall.
intros.
assert (
x <=
max_reg_function f)%
positive.
{
apply max_reg_function_params.
assumption. }
lia.
}
assert (
Forall
(
fun r :
positive => (
r <
Pos.succ (
max_reg_function f))%
positive)
args0)
as ARGS_OK'.
{
apply Forall_forall.
intros.
rewrite Forall_forall in ARGS_OK.
assert (
x <=
max_reg_function f)%
positive by auto.
lia. }
erewrite <-
params_function_translated in PARAMS_OK' by eassumption.
destruct (
exec_tail_rec_call tge _ _ _ _ _
ts trs tm tsp ARGS_OK' PARAMS_OK' LENGTHS REC_CALL)
as (
trs1 &
trs2 &
PLUS &
FINAL).
exists (
State ts tf (
block2sp tsp) (
fn_entrypoint f)
trs2 tm).
split.
+
eapply plus_left.
apply exec_Inop.
exact JUMP1. 2:
reflexivity.
apply plus_star.
exact PLUS.
+
rewrite FINAL.
assert (
inject_incr IF (
meminj_subst IF sp stk))
as INJECT'.
{
apply meminj_subst_incr.
destruct MATCH_MEM.
apply mi_freeblocks.
intro BAD_VALID.
pose proof (
Mem.valid_block_free_1 _ _ _ _ _
FREE _
BAD_VALID)
as MEUH.
pose proof (
Mem.fresh_block_alloc _ _ _ _ _
H1).
contradiction.
}
apply match_states_intro with (
cu:=
cu) (
bound:=
bound) (
id:=
id) (
IF:=
meminj_subst IF sp stk).
*
assumption.
*
eapply alloc_new_weakly_allocated_block;
eassumption.
*
rewrite (
Mem.alloc_result _ _ _ _ _
H1).
rewrite (
Mem.nextblock_alloc _ _ _ _ _
H1).
unfold Plt.
lia.
*
eapply ubound_stack_advance. 2:
eassumption.
rewrite (
Mem.alloc_result _ _ _ _ _
H1).
rewrite (
Mem.nextblock_free _ _ _ _ _
FREE).
unfold Plt,
Ple in *.
lia.
*
eapply alloc_keep_weakly_allocated_stack. 2:
eassumption.
--
eapply ubound_stack_advance. 2:
eassumption.
rewrite (
Mem.nextblock_free _ _ _ _ _
FREE).
unfold Plt,
Ple in *.
lia.
--
eapply free_weakly_allocated_stack. 2,3:
eassumption.
apply ubound_not_in_stack;
eassumption.
*
pose proof (
Mem.alloc_result _ _ _ _ _
H1).
pose proof (
Mem.nextblock_free _ _ _ _ _
FREE).
unfold Ple in *.
lia.
*
pose proof (
Mem.nextblock_alloc _ _ _ _ _
H1).
pose proof (
Mem.nextblock_free _ _ _ _ _
FREE).
unfold Ple in *.
lia.
*
assumption.
*
pose proof (
Mem.alloc_result _ _ _ _ _
H1).
pose proof (
Mem.nextblock_free _ _ _ _ _
FREE).
apply good_meminj_subst;
trivial.
unfold Ple in *.
lia.
*
apply match_stacks_incr with (
IF :=
IF);
auto.
*
assumption.
*
rewrite (
params_function_translated _ _ _ _
MATCH_FUNCTIONS).
apply match_copy;
trivial.
apply match_regs_incr with (
IF:=
IF);
auto.
*
unfold match_sp,
meminj_subst.
destruct (
peq stk stk). 2:
contradiction.
exact MATCH_SP.
*
eapply free_alloc_inject;
try eassumption;
intros.
--
unfold weakly_allocated_block in WEAKLY_ALLOCATED_FRAME.
eapply WEAKLY_ALLOCATED_FRAME.
eapply Mem.perm_max.
eassumption.
--
eapply mem_free_perm_4;
eassumption.
-
inv MATCH_FUNCTIONS.
destruct (
external_call_mem_inject ef _ _ _ (
good_meminj_preserves_globals _ _
GLOBALS)
H0 MATCH_MEM MATCH_ARGS)
as (
IF' &
vres' &
m2' &
CALL' &
MATCH_RES' &
MATCH_MEM' &
UNCHANGED1 &
UNCHANGED2 &
INCR &
SEPARATED).
left.
eexists.
split.
+
apply plus_one.
apply exec_function_external.
apply external_call_symbols_preserved with (
ge1 :=
ge).
{
apply senv_preserved. }
exact CALL'.
+
apply match_states_return with (
bound:=
bound) (
IF :=
IF');
trivial.
*
pose proof (
external_call_nextblock _ _ _ _ _ _ _
H0).
eapply ubound_stack_advance. 2:
eassumption.
assumption.
*
eapply external_call_weakly_allocated_stack;
eassumption.
*
destruct UNCHANGED1.
unfold Ple in *.
lia.
*
destruct UNCHANGED2.
unfold Ple in *.
lia.
*
apply good_meminj_separated with (
IF:=
IF) (
m:=
m) (
tm:=
tm);
trivial.
*
apply match_stacks_incr with (
IF :=
IF);
trivial.
-
inv MATCH_STACKS.
inv H1.
inv UBOUND_STACK.
inv WEAKLY_ALLOCATED_STACK.
inv H1.
left.
exists (
State l' tf (
block2sp tsp)
pc trs #
res <-
tres tm).
split.
{
apply plus_one.
constructor. }
econstructor;
eauto.
apply match_regs_assign;
auto.
Qed.
Theorem transf_program_correct:
forward_simulation (
semantics prog) (
semantics tprog).
eapply forward_simulation_star.
apply senv_preserved.
eexact transf_initial_states.
eexact transf_final_states.
eexact step_simulation.
Qed.