This file contains additional properties about memories.
Require Import Coqlib.
Require Import Integers.
Require Import Values.
Require Import Pointers.
Require Import Mem.
Require Import Ast.
Require Import Maps.
Require Import Libtactics.
Set Implicit Arguments.
Basic lemmata
Lemma store_allocated:
forall {
p c v m m'} (
A:
store_ptr c m p v =
Some m')
r k,
range_allocated r k m' <->
range_allocated r k m.
Proof.
Lemma alloc_allocated:
forall {
r'
k'
m m'} (
A:
alloc_ptr r'
k'
m =
Some m')
r k,
range_allocated r k m' <->
range_allocated r k m \/ (
r =
r' /\
k =
k').
Proof.
Lemma free_allocated:
forall {
p k'
m m'
n}
(
F:
free_ptr p k'
m =
Some m')
(
RA:
range_allocated (
p,
n)
k'
m)
r k,
range_allocated r k m' <->
range_allocated r k m /\
fst r <>
p.
Proof.
Lemma load_alloc_inside2 :
forall {
r k m m'
c'
p'},
alloc_ptr r k m =
Some m' ->
range_inside (
range_of_chunk p'
c')
r ->
load_ptr c'
m'
p' =
(
if pointer_chunk_aligned_dec p'
c'
then Some Vundef else None).
Proof.
Lemma load_alloc_not_inside2 :
forall {
r k m m'
c'
p'},
alloc_ptr r k m =
Some m' ->
load_ptr c'
m p' =
None ->
~
range_inside (
range_of_chunk p'
c')
r ->
load_ptr c'
m'
p' =
None.
Proof.
Lemma load_free_none :
forall {
p k m m'
c'
p'},
free_ptr p k m =
Some m' ->
load_ptr c'
m p' =
None ->
load_ptr c'
m'
p' =
None.
Proof.
Lemma load_store_none :
forall {
p c v m m'
c'
p'},
store_ptr c m p v =
Some m' ->
load_ptr c'
m p' =
None ->
load_ptr c'
m'
p' =
None.
Proof.
Extensional equality on memories
Definition mem_eq m1 m2:=
(
forall chunk p,
load_ptr chunk m1 p =
load_ptr chunk m2 p)
/\ (
forall r k,
range_allocated r k m1 <->
range_allocated r k m2)
/\ (
mrestr m1 =
mrestr m2).
Lemma in_block1:
forall lbnd hbnd l h k ba,
alloclist_hbound lbnd (
mkmobj l h k ::
ba) =
Some hbnd ->
0 <
lbnd ->
hbnd <=
Int.modulus ->
valid_access Mint8unsigned (
l mod Int.modulus) (
mkmobj l h k ::
ba).
Proof.
Lemma alloclist1:
forall lbnd hbnd l h k a,
alloclist_hbound lbnd (
mkmobj l h k ::
a) =
Some hbnd ->
lbnd <=
l /\
l <
h /\
h <=
hbnd /\ (
align_size (
h -
l) |
l).
Proof.
Lemma range_allocated_al_cons:
forall l h k l'
h'
k'
ba',
range_allocated_al l h k (
mkmobj l'
h'
k' ::
ba') ->
l =
l' /\
h =
h' /\
k =
k' \/
range_allocated_al l h k ba'.
Proof.
unfold range_allocated_al.
by inversion 1; clarify; [left|right].
Qed.
Lemma valid_access_bounded:
forall c ofs al lbnd hbnd,
alloclist_hbound lbnd al =
Some hbnd ->
valid_access c ofs al ->
lbnd <=
ofs <
hbnd.
Proof.
Lemma Zabs_nat_of_nat:
forall n,
Zabs_nat (
Z_of_nat n) =
n.
Proof.
Lemma contents_eq_ext:
forall bc bc'
ba,
block_valid (
mkblock bc ba) ->
block_valid (
mkblock bc'
ba) ->
(
forall c ofs,
valid_access c ofs ba ->
Val.load_result c (
getN (
pred_size_chunk c) (
ofs mod Int.modulus)
bc)
=
Val.load_result c (
getN (
pred_size_chunk c) (
ofs mod Int.modulus)
bc')) ->
bc =
bc'.
Proof.
intros bc bc'
ba (
UU &
OK &
hbnd &
B &
M) (
UU' &
OK' &
hbnd' &
B' &
M')
LD.
apply ZTree.ext;
intros ofs.
destruct (
ZTree.get ofs bc)
as [[]|]
_eqn:
G.
Case "
Datum".
pose proof (
proj1 (
proj2 OK _ _ _ G))
as [
c [
SZ [
VOK ACCOK]]].
generalize (
LD c ofs ACCOK).
assert (
ofsRNG: 0 <=
ofs <
Int.modulus)
by (
pose proof (
valid_access_bounded _ B ACCOK);
omega).
rewrite Zmod_small;
try done.
destruct ACCOK as [
k ? ?];
simpl in *.
unfold getN.
rewrite G,
SZ,
dec_eq_true,
value_chunk_ok1;
try done.
destruct (
ZTree.get ofs bc')
as [[]|]
_eqn:
G';
try done;
try destruct eq_nat_dec;
try rewrite load_result_undef;
intro X;
clarify;
try by revert VOK;
clear;
destruct c.
pose proof (
proj1 (
proj2 OK'
_ _ _ G'))
as [
c' [
SZ' [
VOK'
ACCOK']]].
rewrite value_chunk_ok1;
try done.
by revert VOK VOK'
SZ';
clear;
destruct c';
destruct c;
destruct v0.
Case "
Cont".
pose proof (
proj1 OK _ _ G)
as (
l &
v &
Gm).
pose proof (
proj1 (
proj2 OK _ _ _ Gm))
as [
c [
SZ [
VOK ACCOK]]].
generalize (
LD _ _ ACCOK).
assert (
ofsRNG: 0 <=
ofs -
Z_of_nat n <
Int.modulus)
by (
pose proof (
valid_access_bounded _ B ACCOK);
omega).
rewrite Zmod_small;
try done.
destruct ACCOK as [
k ? ?];
simpl in *.
unfold getN.
rewrite Gm,
SZ,
dec_eq_true,
value_chunk_ok1;
try done.
destruct (
ZTree.get (
ofs -
Z_of_nat n)
bc')
as [[]|]
_eqn:
G';
try done;
try destruct eq_nat_dec;
try rewrite load_result_undef;
intro X;
clarify;
try by revert VOK;
clear;
destruct c.
destruct n.
by simpl in *;
rewrite Zminus_0_r in *;
rewrite G in Gm.
pose proof (
proj1 (
proj2 OK'
_ _ _ G'))
as [
c' [
SZ' [
VOK'
ACCOK']]].
exploit (
check_cont_inside _ _ _ _ ofs (
proj2 (
proj2 OK'
_ _ _ G')));
unfold contents;
rewrite inj_S.
omega.
intros ->;
f_equal;
f_equal.
replace (
ofs - (
ofs -
Zsucc (
Z_of_nat n) + 1))
with (
Z_of_nat n); [
rewrite Zabs_nat_of_nat|];
omega.
Case "
None".
destruct (
ZTree.get ofs bc')
as [[]|]
_eqn:
G';
try done.
SCase "
Datum".
pose proof (
proj1 (
proj2 OK'
_ _ _ G'))
as [
c [
SZ [
VOK ACCOK]]].
generalize (
LD c ofs ACCOK).
assert (
ofsRNG: 0 <=
ofs <
Int.modulus)
by (
pose proof (
valid_access_bounded _ B ACCOK);
omega).
rewrite Zmod_small;
try done.
destruct ACCOK as [
k ? ?];
simpl in *.
unfold getN.
rewrite G,
G',
SZ,
dec_eq_true,
load_result_undef,
value_chunk_ok1;
try done.
by revert VOK;
clear;
destruct c;
destruct v.
SCase "
Cont".
pose proof (
proj1 OK'
_ _ G')
as (
l &
v &
Gm').
pose proof (
proj1 (
proj2 OK'
_ _ _ Gm'))
as [
c [
SZ [
VOK ACCOK]]].
generalize (
LD _ _ ACCOK).
assert (
ofsRNG: 0 <=
ofs -
Z_of_nat n <
Int.modulus)
by (
pose proof (
valid_access_bounded _ B ACCOK);
omega).
rewrite Zmod_small;
try done.
destruct ACCOK as [
k ? ?];
simpl in *.
unfold getN.
rewrite Gm',
SZ,
dec_eq_true.
destruct (
ZTree.get (
ofs -
Z_of_nat n)
bc)
as [[]|]
_eqn:
Gm;
try done;
try destruct eq_nat_dec;
try rewrite load_result_undef;
try (
by revert VOK;
destruct c;
destruct v).
intro X;
clarify.
destruct n.
by simpl in *;
rewrite Zminus_0_r in *;
rewrite G in Gm.
pose proof (
proj1 (
proj2 OK _ _ _ Gm))
as [
c' [
SZ' [
VOK'
ACCOK']]].
exploit (
check_cont_inside _ _ _ _ ofs (
proj2 (
proj2 OK _ _ _ Gm)));
unfold contents;
rewrite inj_S.
omega.
by rewrite G.
Qed.
Lemma range_allocated_implies_allocs_eq:
forall m m'
b bc bc',
(
forall (
r :
arange) (
k :
mobject_kind),
range_allocated r k m <->
range_allocated r k m') ->
ZTree.get b (
mcont m) =
Some bc ->
ZTree.get b (
mcont m') =
Some bc' ->
allocs bc =
allocs bc'.
Proof.
Theorem mem_eq_ext:
forall m1 m2,
mem_eq m1 m2 ->
m1 =
m2.
Proof.
Load equality on memories
Lemma load_eq_preserved_by_store:
forall {
c m mx p c'
p'
v'
m'
mx'}
(
Leq:
load_ptr c m p =
load_ptr c mx p)
(
ST:
store_ptr c'
m p'
v' =
Some m')
(
STx:
store_ptr c'
mx p'
v' =
Some mx'),
load_ptr c m'
p =
load_ptr c mx'
p.
Proof.
Lemma load_eq_preserved_by_alloc:
forall {
c m mx p r'
k'
m'
mx'}
(
Leq:
load_ptr c m p =
load_ptr c mx p)
(
AP:
alloc_ptr r'
k'
m =
Some m')
(
APx:
alloc_ptr r'
k'
mx =
Some mx'),
load_ptr c m'
p =
load_ptr c mx'
p.
Proof.
Lemma load_eq_preserved_by_free_same_size:
forall {
c m mx p p'
n'
k'
m'
mx'}
(
Leq:
load_ptr c m p =
load_ptr c mx p)
(
RA:
range_allocated (
p',
n')
k'
m)
(
FP:
free_ptr p'
k'
m =
Some m')
(
RAx:
range_allocated (
p',
n')
k'
mx)
(
FPx:
free_ptr p'
k'
mx =
Some mx'),
load_ptr c m'
p =
load_ptr c mx'
p.
Proof.
Lemma load_eq_preserved_by_free_diff_block:
forall {
c m mx p p'
k'
m'
mx'}
(
Leq:
load_ptr c m p =
load_ptr c mx p)
(
DB:
Ptr.block p <>
Ptr.block p')
(
FP:
free_ptr p'
k'
m =
Some m')
(
FPx:
free_ptr p'
k'
mx =
Some mx'),
load_ptr c m'
p =
load_ptr c mx'
p.
Proof.
intros.
destruct (
free_someD FP)
as [
n RA].
destruct (
free_someD FPx)
as [
nx RAx].
rewrite (
load_free_other FP RA);
[|
by destruct p;
destruct p';
simpl in *;
left].
by rewrite (
load_free_other FPx RAx);
[|
by destruct p;
destruct p';
simpl in *;
left].
Qed.
Commutativity properties of memory operations
Allocation commutes over successful stores
Lemma alloc_comm_store:
forall p c v r k m m1 m2 m'
(
A :
alloc_ptr r k m =
Some m1)
(
B1:
store_ptr c m1 p v =
Some m')
(
B2:
store_ptr c m p v =
Some m2),
alloc_ptr r k m2 =
Some m'.
Proof.
Allocation commutes over successful allocations
Lemma alloc_comm_alloc:
forall r k r'
k'
m m1 m2 m'
(
A :
alloc_ptr r k m =
Some m1)
(
B1:
alloc_ptr r'
k'
m1 =
Some m')
(
B2:
alloc_ptr r'
k'
m =
Some m2),
alloc_ptr r k m2 =
Some m'.
Proof.
Allocation commutes over successful frees
Lemma alloc_comm_free:
forall r k p k'
m m1 m2 m'
(
A :
alloc_ptr r k m =
Some m1)
(
B1:
free_ptr p k'
m1 =
Some m')
(
B2:
free_ptr p k'
m =
Some m2),
alloc_ptr r k m2 =
Some m'.
Proof.
intros.
pose proof (
alloc_someD A)
as (? & ? & ? &
HA).
pose proof (
free_someD B1)
as (
n1 &
HB1);
des.
pose proof (
free_someD B2)
as (
n2 &
HB2);
des.
destruct (
alloc_preserves_allocated_back A _ _ HB1)
as [[]|];
clarify.
-
edestruct HA;
try edone.
by eapply non_empty_same_ptr_overlap;
eauto using @
valid_alloc_range_non_empty, @
allocated_range_valid.
destruct (
alloc_ranges_same HB2 H2)
as [?
_];
clarify.
destruct (
ranges_disjoint_dec r (
p,
n1))
as [
DISJ|]; [|
eby edestruct HA].
clear H2.
destruct (
alloc_ptr r k m2)
as []
_eqn:
D;
clarify.
Case "
some".
pose proof (
alloc_someD D)
as (? &
_ &
_ &
HD);
des.
f_equal;
eapply mem_eq_ext;
red.
rewrite (
restr_of_free B1), (
restr_of_alloc D),
(
restr_of_free B2), (
restr_of_alloc A).
split; [|
split];
try done.
SCase "
load_eq".
intros c'
p'.
destruct (
range_inside_dec (
range_of_chunk p'
c')
r)
as [
RI |
RNI].
rewrite (
load_alloc_inside2 D RI);
try done.
erewrite (
load_free_other B1);
try edone.
2:
eby eapply disjoint_inside_disjoint.
by rewrite (
load_alloc_inside2 A RI).
destruct (
ranges_disjoint_dec (
range_of_chunk p'
c')
r)
as [
DISJ'|
OVER].
rewrite (
load_alloc_other D DISJ').
eapply load_eq_preserved_by_free_same_size;
try eapply B1;
try eapply B2;
try eassumption.
by rewrite (
load_alloc_other A DISJ').
rewrite (
load_alloc_overlap D RNI OVER);
symmetry.
destruct (
load_ptr c'
m'
p')
as []
_eqn:
X;
clarify.
destruct (
load_chunk_allocated_someD X)
as [(? & ? & ? &
RA) ?].
eapply free_preserves_allocated_back in RA;
try edone.
destruct (
load_chunk_allocated_noneD (
load_alloc_overlap A RNI OVER)).
by split;
vauto.
SCase "
ralloc".
intros.
eapply iff_trans,
iff_sym, (
free_allocated B1);
try edone.
eapply iff_trans,
iff_sym,
and_iff_compat_r, (
alloc_allocated A).
eapply iff_trans; [
eapply (
alloc_allocated D)|].
eapply iff_trans; [
eby eapply or_iff_compat_r;
eapply (
free_allocated B2)|].
destruct r0;
split;
intro;
des;
clarify;
vauto.
split;
vauto;
simpl;
intro;
clarify.
edestruct HA;
try edone.
by eapply non_empty_same_ptr_overlap;
eauto using @
valid_alloc_range_non_empty, @
allocated_range_valid.
Case "
none".
pose proof (
alloc_noneD D)
as [|[[]|(
r'' &
k'' &
RO &
RA)]];
clarify.
-
by destruct r as [[]];
destruct p;
simpl;
rewrite (
restr_of_free B2).
pose proof (
free_preserves_allocated_back B2 _ _ RA);
des;
clarify.
eby edestruct HA.
Qed.
Free commutes over successful stores
Lemma free_comm_store:
forall p c v r k m m1 m2 m'
(
A :
free_ptr r k m =
Some m1)
(
B1:
store_ptr c m1 p v =
Some m')
(
B2:
store_ptr c m p v =
Some m2),
free_ptr r k m2 =
Some m'.
Proof.
intros.
pose proof (
free_someD A)
as (
n &
RA).
destruct (
store_chunk_allocated_someD B1)
as [(
rr &
k' &
RI &
RA1)
_].
destruct (
free_ptr r k m2)
as [
m''|]
_eqn:
D;
clarify.
2:
eby eapply (
store_allocated B2)
in RA;
edestruct (
free_noneD D).
f_equal;
eapply mem_eq_ext;
red.
rewrite (
restr_of_store B1), (
restr_of_free D),
(
restr_of_store B2), (
restr_of_free A).
split; [|
split];
try done.
Case "
load_eq".
destruct (
ranges_are_disjoint RA (
free_preserves_allocated_back A _ _ RA1))
as [[]|
DISJ].
+
eby clarify;
edestruct (
free_not_allocated A).
intros c'
p'.
destruct (
ranges_disjoint_dec (
range_of_chunk p'
c')
(
r,
n))
as [
DISJ' |
OVER].
erewrite (
load_free_other D);
try edone;
try eby eapply store_allocated.
eapply load_eq_preserved_by_store;
try eassumption.
eby erewrite (
load_free_other A).
erewrite (
load_free_overlap D);
try edone;
try eby eapply store_allocated.
rewrite (
load_store_none B1);
try edone.
eby eapply (
load_free_overlap A).
Case "
ralloc".
intros.
eapply iff_trans,
iff_sym, (
store_allocated B1).
eapply iff_trans,
iff_sym, (
free_allocated A RA).
eapply iff_trans,
and_iff_compat_r, (
store_allocated B2).
eby eapply (
free_allocated D), (
store_allocated B2).
Qed.
Free commutes over successful allocations
Lemma free_comm_alloc:
forall p k r k'
m m1 m2 m'
(
A :
free_ptr p k m =
Some m1)
(
B1:
alloc_ptr r k'
m1 =
Some m')
(
B2:
alloc_ptr r k'
m =
Some m2),
free_ptr p k m2 =
Some m'.
Proof.
intros.
pose proof (
free_someD A)
as (
n &
pRA).
pose proof (
alloc_someD B1)
as (
RA' &
_ &
_ &
HB1).
pose proof (
alloc_someD B2)
as (
RA2 &
_ &
_ &
HB).
destruct (
free_ptr p k m2)
as [
m''|]
_eqn:
D;
clarify.
2:
eby edestruct (
free_noneD D);
eapply alloc_preserves_allocated.
f_equal;
eapply mem_eq_ext;
red.
rewrite (
restr_of_alloc B1), (
restr_of_free D),
(
restr_of_alloc B2), (
restr_of_free A).
split; [|
split];
try done.
Case "
load_eq".
intros c'
p'.
destruct (
ranges_disjoint_dec (
range_of_chunk p'
c') (
p,
n))
as [
DISJ' |
OVER].
erewrite (
load_free_other D);
try edone;
try eby eapply alloc_preserves_allocated.
eapply load_eq_preserved_by_alloc;
try eassumption.
eby erewrite (
load_free_other A).
erewrite (
load_free_overlap D);
try edone;
try eby eapply alloc_preserves_allocated.
erewrite load_alloc_not_inside2;
try edone.
eby erewrite (
load_free_overlap A).
intro.
destruct OVER.
eapply disjoint_inside_disjoint;
try edone.
edestruct (
ranges_are_disjoint RA2 (
alloc_preserves_allocated B2 _ _ pRA))
as [[]|];
clarify.
edestruct HB;
try edone.
by eapply non_empty_same_ptr_overlap;
eauto using @
valid_alloc_range_non_empty, @
allocated_range_valid.
Case "
ralloc".
intros.
eapply iff_trans,
iff_sym, (
alloc_allocated B1);
try done.
eapply iff_trans,
iff_sym,
or_iff_compat_r, (
free_allocated A pRA);
try done.
eapply iff_trans.
eapply (
free_allocated D);
try edone;
try eby eapply alloc_preserves_allocated.
eapply iff_trans; [
eby eapply and_iff_compat_r;
eapply (
alloc_allocated B2)|].
split;
intro;
des;
clarify;
vauto.
split;
vauto;
intro;
clarify.
destruct r;
edestruct HB;
try edone.
by eapply non_empty_same_ptr_overlap;
eauto using @
valid_alloc_range_non_empty, @
allocated_range_valid.
Qed.
Free commutes over successful frees
Lemma free_comm_free:
forall p k p'
k'
m m1 m2 m'
(
A :
free_ptr p k m =
Some m1)
(
B1:
free_ptr p'
k'
m1 =
Some m')
(
B2:
free_ptr p'
k'
m =
Some m2),
free_ptr p k m2 =
Some m'.
Proof.
Simple corollaries
Lemma alloc_comm_alloc_none:
forall r k r'
k'
m m1 m2
(
A :
alloc_ptr r k m =
Some m1)
(
B :
alloc_ptr r'
k'
m1 =
None)
(
C :
alloc_ptr r'
k'
m =
Some m2),
alloc_ptr r k m2 =
None.
Proof.
Lemma store_comm_alloc:
forall r k c p v m m1 m2
(
A :
store_ptr c m p v =
Some m1)
(
B :
alloc_ptr r k m1 =
Some m2),
exists m',
alloc_ptr r k m =
Some m' /\
store_ptr c m'
p v =
Some m2.
Proof.
Lemma free_comm_store2:
forall r k c p v m m1 m2
(
A :
free_ptr r k m =
Some m1)
(
B :
store_ptr c m1 p v =
Some m2),
exists m',
store_ptr c m p v =
Some m' /\
free_ptr r k m' =
Some m2.
Proof.