Require Import Coqlib.
Require Import Errors.
Require Import AST.
Require Import Maps.
Require Import Integers.
Require Import Floats.
Require Import Values.
Require Import Globalenvs.
Require Import Values_symbolictype.
Require Import Values_symbolic.
Require Import Normalise.
Require Import NormaliseSpec.
Require Import ExprEval.
Require Import Memory.
Require Import Psatz.
Require Import MemRel Align Tactics.
Require Import Permutation MemReserve BlockAppears ForgetNorm ListUtils.
Definition inject_well_behaved (
f:
meminj) (
m:
mem) :=
forall b,
f b =
None ->
Mem.size_block m b <= 8 /\ (
Mem.mask m b <= 3)%
nat.
Definition is_injected (
f:
meminj) (
b:
block *
Z) :=
match f (
fst b)
with
Some b2 =>
true
|
None =>
false
end.
Record inj_well_behaved f m1 m2 :=
{
iwb_o2o:
Mem.one2oneinject f;
iwb_wb:
inject_well_behaved f m1;
iwb_bounds:
forall b b'
delta,
f b =
Some (
b',
delta) ->
Mem.size_block m1 b =
Mem.size_block m2 b';
iwb_mask:
forall b b'
delta,
f b =
Some (
b',
delta) ->
Mem.mask m1 b =
Mem.mask m2 b';
iwb_no_oota:
forall b',
Mem.valid_block m2 b' ->
exists b delta,
f b =
Some (
b',
delta);
iwb_inj:
forall b1 b2 b'
delta1 delta2,
f b1 =
Some (
b',
delta1) ->
f b2 =
Some (
b',
delta2) ->
b1 =
b2
}.
Definition inj_block (
f:
meminj) :=
(
fun b :
block =>
match f b with
Some (
b',
delta) =>
Some b'
|
None =>
None
end).
Let B1 be the list of blocks of m1. We can split those blocks into l1
and l2, where l1 keeps the blocks that are injected by f, and l2
keeps the other blocks.
This theorem shows that the blocks of m2 are the blocks of m1, with
injection applied.
Lemma part_inj_permut:
forall sm ei f m1 m2
(
IWB:
inj_well_behaved f m1 m2)
(
MINJ:
Mem.inject sm ei f m1 m2),
Permutation
(
map fst (
Mem.mk_block_list m2))
(
filter_map (
inj_block f) (
map fst (
Mem.mk_block_list m1))).
Proof.
Lemma inject_well_behaved_diff_blocks:
forall sm ei f m1 m2
(
MINJ:
Mem.inject sm ei f m1 m2)
(
IWB:
inj_well_behaved f m1 m2)
l0 l1
(
PART:
partition (
is_injected f) (
Mem.mk_block_list m1) = (
l0,
l1)),
(
num_boxes (
boxes (
canon_cm m2) (
Mem.mk_block_list m2)) +
sum (
map (
box_span m1 (
canon_cm m1)) (
map fst l1)))%
nat =
num_boxes (
boxes (
canon_cm m1) (
Mem.mk_block_list m1)).
Proof.
Lemma inject_well_behaved_diff_blocks_num:
forall sm ei f m1 m2
(
MINJ:
Mem.inject sm ei f m1 m2)
(
IWB:
inj_well_behaved f m1 m2)
l0 l1
(
PART:
partition (
is_injected f) (
Mem.mk_block_list m1) = (
l0,
l1)),
(
nb_boxes_used_cm m2 (
canon_cm m2) +
sum (
map (
box_span m1 (
canon_cm m1)) (
map fst l1)) =
nb_boxes_used_cm m1 (
canon_cm m1))%
nat.
Proof.
Lemma iwb_in_bound:
forall f m1 m2 (
IWF:
inj_well_behaved f m1 m2)
b b0 z (
FB:
f b =
Some (
b0,
z))
o (
IB:
in_bound o (
Mem.bounds_of_block m1 b)),
in_bound o (
Mem.bounds_of_block m2 b0).
Proof.
Lemma not_inj_in_bound_in_filter_map:
forall f m1 l l0 b'
o'
(
PART:
partition (
is_injected f) (
Mem.mk_block_list m1) = (
l,
l0))
(
FB:
f b' =
None)
(
IB:
in_bound (
Int.unsigned o') (
Mem.bounds_of_block m1 b')),
In b' (
filter_map (
fun bsz :
block *
Z =>
let (
b,
sz) :=
bsz in
if zlt 0
sz
then Some b
else None)
l0).
Proof.
Lemma length_filter_map_fold_right:
forall f m1 m2 l l0
(
IWB:
inj_well_behaved f m1 m2)
(
PART:
partition (
is_injected f) (
Mem.mk_block_list m1) = (
l,
l0)),
length (
filter_map (
fun bsz :
block *
Z =>
let (
b0,
sz) :=
bsz in if zlt 0
sz then Some b0 else None)
l0)
=
fold_right Peano.plus 0%
nat (
map (
fun x :
block =>
length (
box_range'
m1 (
canon_cm m1)
x)) (
map fst l0)).
Proof.
Lemma not_inj_in_bound_get_addr:
forall f m1 m2 l l0 b'
o'
(
IWB:
inj_well_behaved f m1 m2)
(
PART:
partition (
is_injected f) (
Mem.mk_block_list m1) = (
l,
l0))
(
FB:
f b' =
None)
(
IB:
in_bound (
Int.unsigned o') (
Mem.bounds_of_block m1 b')),
let l' := (
filter_map (
fun bsz :
block *
Z =>
let (
b,
sz) :=
bsz in
if zlt 0
sz
then Some b
else None)
l0)
in
forall l1 (
LEN: (
length l1 >=
fold_right Peano.plus 0%
nat (
map (
fun x :
block =>
length (
box_range'
m1 (
canon_cm m1)
x)) (
map fst l0)))%
nat),
exists n (
x:
Z),
find peq b'
l' =
Some n /\
(
n <
length l')%
nat /\
list_nth_z l1 (
Z.of_nat n) =
Some x
.
Proof.
Opaque Z.mul.
Theorem forget_compat:
forall sm ei f m1 m2
(
MINJ:
Mem.inject sm ei f m1 m2)
(
IWB:
inj_well_behaved f m1 m2)
cm2
(
COMP:
Mem.compat_m m2 Mem.M32 cm2),
exists cm1,
Mem.compat_m m1 Mem.M32 cm1 /\
(
forall b b' :
block,
f b =
Some (
b',0) ->
cm1 b =
cm2 b').
Proof.
intros.
des (
partition (
is_injected f) (
Mem.mk_block_list m1)).
assert (
has_free_boxes
m2 cm2
(
sum (
map (
fun x :
block =>
length (
box_range'
m1 (
canon_cm m1)
x)) (
map fst l0)))).
{
red.
eapply le_lt_trans.
eapply NPeano.Nat.add_le_mono.
eapply canon_cm_more_boxes.
eauto.
apply eq_le;
eauto.
rewrite plus_0_r.
setoid_rewrite inject_well_behaved_diff_blocks_num;
eauto.
eapply le_lt_trans.
eapply nb_boxes_used_cm_nb_boxes_used_m.
apply mult_lt_le_mono; [|
split; [
apply two_power|
lia]].
apply Nat2Z.inj_lt.
rewrite Z2Nat.id.
apply Mem.wfm_alloc.
apply Mem.nb_boxes_max_pos.
}
apply has_free_boxes_correct in H.
destruct H as (
l1 &
LEN &
LNR &
PROP &
ADDRSPACE &
ALIGN).
exists (
fun b =>
match f b with
Some (
b',
delta) =>
cm2 b'
|
None =>
match
map_option
(
fun n =>
list_nth_z l1 (
Z.of_nat n))
(
find peq b (
filter_map (
fun bsz :
block *
Z =>
let (
b,
sz) :=
bsz in
if zlt 0
sz
then Some b
else None)
l0))
with
Some A =>
Int.repr A
|
None =>
Int.zero
end
end
).
split.
-
constructor.
+
intros b o IB.
destr.
des p.
*
inv COMP.
apply addr_space.
eapply iwb_in_bound;
eauto.
*
exploit not_inj_in_bound_get_addr.
eauto.
eauto.
eauto.
eauto.
apply LEN.
intros (
n &
A &
EQ &
LT &
EQA).
rewrite EQ.
simpl.
rewrite EQA.
rewrite Forall_forall in ADDRSPACE.
trim (
ADDRSPACE A).
eapply list_nth_z_in;
eauto.
generalize (
ADDRSPACE o).
intro AO.
trim AO.
rewrite bounds_eq in IB.
red in IB.
simpl in IB.
exploit iwb_wb;
eauto.
lia.
generalize (
ADDRSPACE Int.zero).
intro A0.
trim A0.
rewrite Int.unsigned_zero.
lia.
rewrite Int.unsigned_zero in A0.
rewrite Int.add_unsigned.
rewrite (
Int.unsigned_repr A)
by lia.
rewrite Int.unsigned_repr;
lia.
+
intros b b'
o o'
DIFF IB IB'.
destr.
des p.
*
destr.
des p.
{
inv COMP.
apply overlap;
auto.
intro;
subst.
exploit iwb_inj.
eauto.
apply Heqo1.
apply Heqo0.
destr.
eapply iwb_in_bound;
eauto.
eapply iwb_in_bound;
eauto.
}
{
exploit not_inj_in_bound_get_addr.
eauto.
eauto.
eauto.
eauto.
apply LEN.
intros (
n &
A &
EQ &
LT &
EQA).
rewrite EQ.
simpl.
rewrite EQA.
rewrite Forall_forall in PROP.
apply PROP.
eapply list_nth_z_in;
eauto.
eapply iwb_in_bound;
eauto.
rewrite bounds_eq in IB'.
red in IB'.
simpl in IB'.
exploit iwb_wb;
eauto.
lia.
}
*
destr.
{
exploit not_inj_in_bound_get_addr.
eauto.
eauto.
eauto.
eauto.
apply LEN.
intros (
n &
A &
EQ &
LT &
EQA).
revert Heqo1.
rewrite EQ.
simpl.
rewrite EQA.
intro B;
inv B.
rewrite Forall_forall in PROP.
generalize (
PROP z).
intro PZ.
trim PZ.
eapply list_nth_z_in;
eauto.
specialize (
fun LT b2 d pf =>
PZ _ _ o (
iwb_in_bound _ _ _ IWB b'
b2 d pf _ IB')
LT).
trim PZ.
rewrite bounds_eq in IB.
red in IB.
simpl in IB.
exploit iwb_wb;
eauto.
lia.
destr.
{
des p.
specialize (
PZ _ _ eq_refl).
auto.
}
{
exploit not_inj_in_bound_get_addr.
eauto.
eauto.
apply Heqo1.
eauto.
apply LEN.
intros (
n2 &
A2 &
EQ2 &
LT2 &
EQA2).
rewrite EQ2.
simpl.
rewrite EQA2.
intro B;
inv B.
assert (
n <>
n2)
by eauto using find_diff_diff.
rewrite bounds_eq in IB,
IB'.
red in IB,
IB'.
simpl in IB,
IB'.
exploit iwb_wb.
eauto.
apply Heqo0.
exploit iwb_wb.
eauto.
apply Heqo1.
assert (
z <>
A2)
by (
eapply lnr_list_nth_z_diff;
eauto;
lia).
intros.
rewrite Forall_forall in ADDRSPACE.
specialize (
fun o pf x pf' =>
ADDRSPACE x pf'
o pf).
generalize (
ADDRSPACE o).
intro ASo.
trim ASo.
lia.
trim (
ASo z).
eapply list_nth_z_in;
eauto.
generalize (
ADDRSPACE o').
intro ASo'.
trim ASo'.
lia.
trim (
ASo'
A2).
eapply list_nth_z_in;
eauto.
generalize (
ADDRSPACE Int.zero).
intro AS0.
trim AS0.
rewrite Int.unsigned_zero.
lia.
generalize (
AS0 _ (
list_nth_z_in _ _ EQA)).
generalize (
AS0 _ (
list_nth_z_in _ _ EQA2)).
rewrite Int.unsigned_zero.
intros A2rng Zrng.
intros;
revert H0.
unfold Int.add.
rewrite (
Int.unsigned_repr z)
by lia.
rewrite (
Int.unsigned_repr A2)
by lia.
rewrite !
Int.unsigned_repr by lia.
rewrite Forall_forall in ALIGN.
destruct (
ALIGN _ (
list_nth_z_in _ _ EQA))
as (
k &
EQk).
destruct (
ALIGN _ (
list_nth_z_in _ _ EQA2))
as (
k2 &
EQk2).
subst.
clear -
H1 H2 H3 IB IB'.
lia.
}
}
{
des (
find peq b (
filter_map (
fun bsz :
block *
Z =>
let (
b0,
sz) :=
bsz in if zlt 0
sz then Some b0 else None)
l0)).
eapply find_some_range in Heqo2.
erewrite length_filter_map_fold_right in Heqo2;
eauto.
exploit (
list_nth_z_succeeds (
A:=
Z)).
split.
2:
eapply Z.lt_le_trans. 2:
apply Heqo2.
lia.
apply inj_le.
instantiate (1 :=
l1).
unfold sum in LEN.
lia.
intros (
x &
EQ).
destr.
assert (~
In b (
filter_map (
fun bsz :
block *
Z =>
let (
b0,
sz) :=
bsz in
if zlt 0
sz
then Some b0
else None)
l0)).
intro IN.
eapply find_in with (
eq_dec:=
peq) (
x:=
b)
in IN.
dex;
destr.
rewrite in_map_filter in H.
exfalso;
apply H.
exists (
b,
Mem.size_block m1 b).
rewrite in_partition_r. 2:
eauto.
unfold is_injected.
simpl.
rewrite Heqo0.
repSplit;
auto.
eapply mbla_below_in'.
eapply Mem.in_bound_valid in IB.
red in IB.
apply Pos2Nat.inj_lt in IB.
lia.
destr.
contradict IB.
rewrite bounds_eq.
unfold in_bound.
simpl.
lia.
}
+
intros.
destr.
des p.
*
unfold Mem.nat_mask.
erewrite iwb_mask;
eauto.
inv COMP;
eauto.
*
destr.
des (
find peq b (
filter_map (
fun bsz :
block *
Z =>
let (
b0,
sz) :=
bsz in if zlt 0
sz then Some b0 else None)
l0)).
rewrite Forall_forall in ALIGN.
destruct (
ALIGN _ (
list_nth_z_in _ _ Heqo0))
as (
k &
EQk).
subst.
exploit iwb_wb;
eauto.
intros (
B &
M).
IntFacts.solve_int.
rewrite Int.testbit_repr;
auto.
replace (8*
k)
with (
k * 2 ^ 3)
by lia.
rewrite Z.mul_pow2_bits by lia.
des (
Z.testbit k (
i-3)).
assert (
i-3 >= 0).
destruct (
zle 0 (
i-3)).
lia.
rewrite Z.testbit_neg_r in Heqb0.
congruence.
lia.
unfold Mem.nat_mask.
rewrite Int.bits_not;
auto.
rewrite Int.testbit_repr;
auto.
rewrite two_power_nat_two_p,
Int.Ztestbit_two_p_m1;
auto.
destr.
lia.
lia.
-
intros.
rewrite H.
auto.
-
auto.
Qed.
Lemma forget_norm:
forall sm ei (
wf:
wf_inj ei) (
f :
meminj) (
m1 m2 :
mem),
Mem.inject sm ei f m1 m2 ->
inj_well_behaved f m1 m2 ->
forall e1 e2 (
EI:
ei f e1 e2) (
BA:
sep_inj m1 f e1),
val_inject f (
Mem.mem_norm m1 e1) (
Mem.mem_norm m2 e2).
Proof.
Lemma norm_forget:
forall sm ei (
wf:
wf_inj ei)
f m m'
e1 v1 e1'
(
O2O:
inj_well_behaved f m m')
(
INJ:
Mem.inject sm ei f m m')
(
EI:
ei f e1 e1')
(
NU:
v1 <>
Vundef),
forall (
MN:
Mem.mem_norm m e1 =
v1) (
BA:
sep_inj m f e1),
Mem.mem_norm m'
e1' <>
Vundef /\
ei f (
Eval v1) (
Eval (
Mem.mem_norm m'
e1')).
Proof.
Lemma storev_inject:
forall sm ei (
wf:
wf_inj ei)
f chunk m1 a1 v1 n1 m2 a2 v2
(
IWB:
inj_well_behaved f m1 m2)
(
INJ:
Mem.inject sm ei f m1 m2)
(
STOREV:
Mem.storev chunk m1 a1 v1 =
Some n1)
(
EIaddr:
ei f a1 a2)
(
SI:
sep_inj m1 f a1)
(
EIval:
ei f v1 v2),
exists n2,
Mem.storev chunk m2 a2 v2 =
Some n2 /\
Mem.inject sm ei f n1 n2.
Proof.
Lemma loadv_inject:
forall sm ei (
wf:
wf_inj ei)
f chunk m1 a1 v1 m2 a2
(
IWB:
inj_well_behaved f m1 m2)
(
INJ:
Mem.inject sm ei f m1 m2)
(
LOADV:
Mem.loadv chunk m1 a1 =
Some v1)
(
EIaddr:
ei f a1 a2)
(
SI:
sep_inj m1 f a1),
exists v2,
Mem.loadv chunk m2 a2 =
Some v2 /\
ei f v1 v2.
Proof.
Lemma o2oinj_inverse:
forall f m tm (
IWB:
inj_well_behaved f m tm)
sm ei (
MINJ:
Mem.inject sm ei f m tm),
exists g,
forall b b',
f b =
Some (
b',0) ->
g b' =
Some b.
Proof.
intros.
set (
bl :=
Alloc.list_ints (
Pos.to_nat (
Mem.nextblock m))).
set (
bl' :=
map (
fun x =>
let b :=
Pos.of_nat x in (
b,
f b))
bl).
set (
filter_fun :=
fun (
b:
block) (
x:
block *
option (
block*
Z)) =>
match snd x with
Some (
b',
delta) =>
if peq b b'
then true else false
|
_ =>
false
end).
exists (
fun b =>
head (
map fst (
filter (
filter_fun b)
bl'))).
intros.
assert (
ISIN:
In (
b,
Some (
b', 0))
bl').
{
destruct (
Mem.valid_block_dec m b).
apply in_map_iff.
exists (
Pos.to_nat b).
rewrite Pos2Nat.id.
simpl.
unfold block.
split;
auto.
f_equal;
auto.
apply list_ints_le.
split.
zify;
omega.
apply Pos2Nat.inj_le.
unfold Mem.valid_block in v.
xomega.
eapply Mem.mi_freeblocks in n;
eauto.
congruence.
}
assert (
UNIQUE:
forall bb delta,
In (
bb,
Some (
b',
delta))
bl' ->
b =
bb /\
delta = 0).
{
intros bb delta IN.
generalize IN;
intro IN'.
unfold bl'
in IN.
rewrite in_map_iff in IN.
dex;
destr.
des IN.
inv e.
exploit iwb_o2o;
eauto.
intros;
subst.
destruct (
peq b (
Pos.of_nat x));
auto.
exploit iwb_inj.
eauto.
apply H.
apply H2.
auto.
}
assert (
ALL:
Forall (
fun x =>
x = (
b,
Some (
b',0))) (
filter (
filter_fun b')
bl')). {
rewrite Forall_forall.
intros x IN.
apply filter_charact in IN.
destruct IN as [
IN INEQ].
revert INEQ.
unfold filter_fun;
simpl.
des x.
des o.
des p.
destr.
intros _.
subst.
apply UNIQUE in IN.
destr.
}
des (
filter (
filter_fun b')
bl').
generalize (
filter_charact _ (
filter_fun b') (
b ,
Some (
b',0))
bl').
rewrite Heql.
destr.
intros [
A B].
exfalso;
apply B;
unfold filter_fun;
simpl.
rewrite peq_true;
auto.
inv ALL;
reflexivity.
Qed.
Lemma o2oinj_cm_inj:
forall f sm ei m tm
(
IWB:
inj_well_behaved f m tm)
(
MINJ:
Mem.inject sm ei f m tm)
cm,
exists cm',
cm_inj cm'
f cm.
Proof.
Lemma o2oinj_em_inj:
forall f sm ei m tm
(
IWB:
inj_well_behaved f m tm)
(
MINJ:
Mem.inject sm ei f m tm)
em,
exists em',
em_inj em'
f em.
Proof.
Lemma expr_inj_se_not_dep:
forall sm ei f m tm v v'
(
IWB:
inj_well_behaved f m tm)
(
MINJ:
Mem.inject sm ei f m tm)
(
EI:
expr_inj_se f v v'),
sep_inj m f v.
Proof.
intros sm ei f m tm v v'
IWB MINJ (
a &
b &
A &
B &
C).
red.
intros b0 Fb.
generalize (
expr_inj_not_dep _ _ _ C _ Fb).
intros NBA DEP.
eapply (
dep_block_appears'
m)
in NBA;
eauto.
apply NBA.
red;
red;
intros.
specialize (
DEP _ COMP _ COMP'
SameB em).
destruct (
o2oinj_inverse _ _ _ IWB _ ei MINJ)
as [
g SPEC].
intros.
edestruct (
o2oinj_em_inj)
with (
em:=
em)
as [
em'
EMINJ];
eauto.
edestruct (
o2oinj_cm_inj)
with (
cm:=
cm)
as [
dep_cmi CMINJ];
eauto.
edestruct (
o2oinj_cm_inj)
with (
cm:=
cm')
as [
dep_cmi'
CMINJ'];
eauto.
erewrite <- !
A;
eauto.
Qed.
Lemma list_expr_inj_se_not_dep:
forall sm ei f m tm v v'
(
IWB:
inj_well_behaved f m tm)
(
MINJ:
Mem.inject sm ei f m tm)
(
EI:
list_ei expr_inj_se f v v'),
Forall (
sep_inj m f)
v.
Proof.
Lemma iwb_inv:
forall f m tm (
IWB:
inj_well_behaved f m tm)
m'
tm'
(
BND:
forall b,
Mem.bounds_of_block m b =
Mem.bounds_of_block m'
b)
(
BNDt:
forall b,
Mem.bounds_of_block tm b =
Mem.bounds_of_block tm'
b)
(
MSK:
forall b,
Mem.mask m b =
Mem.mask m'
b)
(
MSKt:
forall b,
Mem.mask tm b =
Mem.mask tm'
b)
(
PLE:
forall b',
Ple (
Mem.nextblock tm)
b' ->
Plt b' (
Mem.nextblock tm') ->
exists b delta,
f b =
Some (
b',
delta)),
inj_well_behaved f m'
tm'.
Proof.
Lemma free_inject:
forall f sm
m tm (
ME:
Mem.inject sm expr_inj_se f m tm)
(
IWB:
inj_well_behaved f m tm)
b lo hi
m' (
FREE:
Mem.free m b lo hi =
Some m')
b'
(
FB:
f b =
Some (
b',0))
tm'
(
FREE':
Mem.free tm b'
lo hi =
Some tm'),
Mem.inject sm expr_inj_se f m'
tm' /\
inj_well_behaved f m'
tm'.
Proof.
Lemma iwb_ext:
forall j j'
m tm (
IWB:
inj_well_behaved j m tm)
(
EXT:
forall b,
j b =
j'
b),
inj_well_behaved j'
m tm.
Proof.
intros; inv IWB; constructor; simpl; intros; eauto.
- red in iwb_o2o0 |- *; simpl; intros; eauto.
eapply iwb_o2o0. rewrite EXT. eauto.
- red in iwb_wb0 |- *; simpl; intros; eauto.
eapply iwb_wb0. rewrite EXT; auto.
- rewrite <- EXT in H; eauto.
- rewrite <- EXT in H; eauto.
- apply iwb_no_oota0 in H. dex. rewrite EXT in H; eauto.
- rewrite <- EXT in *; eauto.
Qed.