Rewriting theory involving symbolic memories in BTL symbolic execution.
Main contents:
-
Theory of mem_equiv_on: a stronger version of Mem.unchanged_on, specialized for reasoning within BTL blocs.
-
a new address type: combining informations on address ranges from symbolic execution and value analysis
for deciding disjointness.
-
and the rewriting rules...
Require Import Coqlib AST Values Integers Memory Maps.
Require Import RelationClasses.
Require Import OptionMonad.
Require Import Op.
Require Import BTL BTL_SEtheory BTL_SEsimuref Memcpy.
Require Import ValueDomain.
Require Import Impure.ImpHCons.
Require Import Decidableplus Datatypes.
Import SvalNotations.
Import ListNotations.
Local Open Scope option_monad_scope.
Local Open Scope lazy_bool_scope.
Local Notation "a #* b" := (
PXMap.get b a) (
at level 1).
Local Opaque Z.add Z.sub.
Section IsIndexedAddr.
Definition is_indexed_addr (
addr :
addressing) (
ofs :
ptrofs) :
Prop :=
forall F V (
genv:
Globalenvs.Genv.t F V) (
sp:
val) (
args:
list val) (
rb :
Values.block) (
rofs :
ptrofs),
eval_addressing genv sp addr args =
Some (
Vptr rb rofs) <->
exists bofs,
args =
Vptr rb bofs ::
nil /\
rofs =
Ptrofs.add bofs ofs.
Local Obligation Tactic :=
simpl;
intros.
Local Transparent Archi.ptr64.
Program Definition test_is_indexed (
addr :
addressing):
{
ofs :
ptrofs |
is_indexed_addr addr ofs} + {
True} :=
match addr with
|
Aindexed iofs =>
inleft (
exist _ _ _)
| _ =>
inright _
end.
Next Obligation.
Local Obligation Tactic :=
program_simpl.
Solve All Obligations.
Next Obligation.
Local Opaque Archi.ptr64.
Global Opaque test_is_indexed.
Lemma is_indexed_addr_case [
addr ofs] (
ADDR :
is_indexed_addr addr ofs)
[
F V] (
genv:
Globalenvs.Genv.t F V)
sp args
:
(
exists b bofs,
eval_addressing genv sp addr args =
Some (
Vptr b (
Ptrofs.add bofs ofs)) /\
args =
Vptr b bofs ::
nil) \/
(
match eval_addressing genv sp addr args with
|
Some (
Vptr b rofs) =>
False
| _ =>
True
end).
Proof.
specialize (
ADDR F V genv sp args).
revert ADDR.
destruct (
eval_addressing genv sp addr args)
as [[]|];
simpl;
eauto.
intro EQV.
destruct (
EQV b i)
as [[
bofs EQ] _].
reflexivity.
case EQ as [-> ->];
eauto.
Qed.
Lemma is_indexed_addr_eval [
addr ofs] (
ADDR :
is_indexed_addr addr ofs)
[
F V] (
genv:
Globalenvs.Genv.t F V)
sp b bofs:
eval_addressing genv sp addr (
Vptr b bofs ::
nil) =
Some (
Vptr b (
Ptrofs.add bofs ofs)).
Proof.
eapply proj2 in ADDR.
rewrite ADDR;
eauto.
Qed.
End IsIndexedAddr.
Additionnal properties of Mem
Section LemmasMemory.
Preservation of memory operations success
Lemma store_success_iff chk m b ofs v:
Mem.store chk m b ofs v <>
None <->
Mem.valid_access m chk b ofs Writable.
Proof.
Lemma store_fail_iff chk m b ofs v:
Mem.store chk m b ofs v =
None <-> ~
Mem.valid_access m chk b ofs Writable.
Proof.
Lemma load_success_iff chk m b ofs:
Mem.load chk m b ofs <>
None <->
Mem.valid_access m chk b ofs Readable.
Proof.
Lemma loadbytes_success_iff len m b ofs:
Mem.loadbytes m b ofs len <>
None <->
Mem.range_perm m b ofs (
ofs +
len)
Cur Readable.
Proof.
Lemma storebytes_success_iff bytes m b ofs:
Mem.storebytes m b ofs bytes <>
None <->
Mem.range_perm m b ofs (
ofs +
Z.of_nat (
Datatypes.length bytes))
Cur Writable.
Proof.
Lemma memmove_success_iff sz bdst odst bsrc osrc rm wm:
memmove sz bdst odst bsrc osrc rm wm <>
None <-> (
Mem.range_perm rm bsrc osrc (
osrc + (
Zpos sz))
Cur Readable
/\
Mem.range_perm wm bdst odst (
odst + (
Zpos sz))
Cur Writable ).
Proof.
Lemma memcpy_success_iff chk bmal bdst odst bsrc osrc rm wm:
memcpy chk bmal bdst odst bsrc osrc rm wm <>
None <-> (
memcpy_args_ok chk bmal bdst odst bsrc osrc
/\
Mem.range_perm rm bsrc osrc (
osrc + (
Zpos (
cpy_sz chk)))
Cur Readable
/\
Mem.range_perm wm bdst odst (
odst + (
Zpos (
cpy_sz chk)))
Cur Writable ).
Proof.
Lemma memcpy_fail_iff chk bmal bdst odst bsrc osrc rm wm:
memcpy chk bmal bdst odst bsrc osrc rm wm =
None <-> (
memcpy_args_ok chk bmal bdst odst bsrc osrc ->
~ (
Mem.range_perm rm bsrc osrc (
osrc + (
Zpos (
cpy_sz chk)))
Cur Readable
/\
Mem.range_perm wm bdst odst (
odst + (
Zpos (
cpy_sz chk)))
Cur Writable)).
Proof.
Lemma perm_store_iff [
chunk m1 b ofs v m2]:
Mem.store chunk m1 b ofs v =
Some m2 ->
forall (
b' :
Values.block) (
ofs' :
Z) (
k :
perm_kind) (
p :
permission),
Mem.perm m1 b' ofs' k p <->
Mem.perm m2 b' ofs' k p.
Proof.
Lemma store_valid_access_iff [
chunk m1 b ofs v m2]:
Mem.store chunk m1 b ofs v =
Some m2 ->
forall (
chunk' :
memory_chunk) (
b' :
Values.block) (
ofs' :
Z) (
p :
permission),
Mem.valid_access m1 chunk' b' ofs' p <->
Mem.valid_access m2 chunk' b' ofs' p.
Proof.
Lemma range_perm_store_iff [
chunk m1 b ofs v m2]:
Mem.store chunk m1 b ofs v =
Some m2 ->
forall (
b' :
Values.block) (
lo hi:
Z) (
k :
perm_kind) (
p :
permission),
Mem.range_perm m1 b' lo hi k p <->
Mem.range_perm m2 b' lo hi k p.
Proof.
Lemma memcpy_fail_store_iff [
chunk bmal m1 b ofs v m2]:
Mem.store chunk m1 b ofs v =
Some m2 ->
forall chk bdst odst bsrc osrc rm,
(
memcpy chk bmal bdst odst bsrc osrc rm m1 =
None) <-> (
memcpy chk bmal bdst odst bsrc osrc rm m2 =
None).
Proof.
Lemma memcpy_valid_access_iff [
chk bmal bdst odst bsrc osrc rm m1 m2]:
memcpy chk bmal bdst odst bsrc osrc rm m1 =
Some m2 ->
forall (
chunk' :
memory_chunk) (
b' :
Values.block) (
ofs' :
Z) (
p :
permission),
Mem.valid_access m1 chunk' b' ofs' p <->
Mem.valid_access m2 chunk' b' ofs' p.
Proof.
Lemma memcpy_fail_memcpy_iff [
chk bmal bdst odst bsrc osrc rm m1 m2]:
memcpy chk bmal bdst odst bsrc osrc rm m1 =
Some m2 ->
forall chk' bmal' bdst' odst' bsrc' osrc' rm',
(
memcpy chk' bmal' bdst' odst' bsrc' osrc' rm' m1 =
None) <-> (
memcpy chk' bmal' bdst' odst' bsrc' osrc' rm' m2 =
None).
Proof.
Theory of mem_equiv_on: a stronger version of Mem.unchanged_on, not *preserved* by alloc and free.
Thus typically for reasoning within BTL blocks.
Section Equiv_on.
Definition memct_t :=
PXMap.t (
ZXMap.xmap_default Mem.memval_default).
Definition memct_get (
b :
Values.block) (
ofs :
Z) (
m :
memct_t) :
memval :=
ZXMap.get ofs (
PXMap.get b m).
Definition memct_set (
b :
Values.block) (
ofs :
Z) (
v :
memval) (
m :
memct_t) :
memct_t :=
PXMap.set b (
ZXMap.set ofs v (
PXMap.get b m))
m.
Definition eq_on_frame :
Type := (
Values.block ->
Z ->
Prop).
Variable P :
eq_on_frame.
Definition memct_equiv_on (
m0 m1 :
memct_t) :
Prop :=
forall b ofs,
P b ofs ->
memct_get b ofs m0 =
memct_get b ofs m1.
Record mem_equiv_on (
m0 m1 :
mem) :
Prop :=
mk_mem_equiv_on {
EQ_ACCESS :
Mem.mem_access m0 =
Mem.mem_access m1;
EQ_ALIGN :
Mem.mem_align m0 =
Mem.mem_align m1;
EQ_NEXTBLOCK :
Mem.nextblock m0 =
Mem.nextblock m1;
EQ_CTNT :
memct_equiv_on (
Mem.mem_contents m0) (
Mem.mem_contents m1);
}.
Lemma mem_equiv_on_perm [
m0 m1] (
E:
mem_equiv_on m0 m1)
b ofs k p:
Mem.perm m0 b ofs k p <->
Mem.perm m1 b ofs k p.
Proof.
Lemma mem_equiv_on_valid_access [
m0 m1] (
E :
mem_equiv_on m0 m1)
chk b ofs p:
Mem.valid_access m0 chk b ofs p <->
Mem.valid_access m1 chk b ofs p.
Proof.
Lemma mem_equiv_on_range_perm [
m0 m1] (
E :
mem_equiv_on m0 m1)
b lo hi k p:
Mem.range_perm m0 b lo hi k p <->
Mem.range_perm m1 b lo hi k p.
Proof.
Lemma mem_equiv_on_memcpy_success [
m0 m1] (
E :
mem_equiv_on m0 m1)
chk bmal bdst odst bsrc osrc rm:
(
memcpy chk bmal bdst odst bsrc osrc rm m0 <>
None) <-> (
memcpy chk bmal bdst odst bsrc osrc rm m1 <>
None).
Proof.
Lemma mem_equiv_on_get [
m0 m1] (
E :
mem_equiv_on m0 m1)
b ofs
(
H :
P b ofs):
ZXMap.get ofs (
PXMap.get b (
Mem.mem_contents m0)) =
ZXMap.get ofs (
PXMap.get b (
Mem.mem_contents m1)).
Proof.
apply E in H. apply H.
Qed.
Lemma mem_equiv_on_all m0 m1
(
ALL :
forall b i,
P b i)
(
EQ :
mem_equiv_on m0 m1):
m0 =
m1.
Proof.
Lemma load_equiv_on m0 m1 chk b ofs:
mem_equiv_on m0 m1 ->
(
forall i,
ofs <=
i <
ofs +
size_chunk chk ->
P b i) ->
Mem.load chk m0 b ofs =
Mem.load chk m1 b ofs.
Proof.
Local Transparent Mem.loadbytes.
Lemma loadbytes_equiv_on m0 m1 b ofs len:
mem_equiv_on m0 m1 ->
(
forall i,
ofs <=
i <
ofs + (
Zpos len) ->
P b i) ->
Mem.loadbytes m0 b ofs (
Zpos len) =
Mem.loadbytes m1 b ofs (
Zpos len).
Proof.
Local Opaque Mem.loadbytes.
Lemma memcpy_read_equiv_on rm0 rm1 chk bmal bdst odst bsrc osrc wm:
mem_equiv_on rm0 rm1 ->
(
forall ofs,
osrc <=
ofs <
osrc +
Zpos (
cpy_sz chk) ->
P bsrc ofs) ->
memcpy chk bmal bdst odst bsrc osrc rm0 wm =
memcpy chk bmal bdst odst bsrc osrc rm1 wm.
Proof.
End Equiv_on.
Local Instance memct_equiv_on_Equivalence {
P}:
Equivalence (
memct_equiv_on P).
Proof.
unfold memct_equiv_on;
constructor.
-
repeat constructor.
-
intros x y H.
symmetry.
apply H;
auto.
-
intros x y z H H0; (
etransitivity; [
apply H|
apply H0]);
auto.
Qed.
Global Instance mem_equiv_on_Equivalence {
P}:
Equivalence (
mem_equiv_on P).
Proof.
constructor.
- constructor; reflexivity.
- constructor; symmetry; apply H.
- constructor; (etransitivity; [apply H|apply H0]).
Qed.
Lemma memct_equiv_on_weaken (
P0 P1 :
eq_on_frame)
m0 m1
(
E :
memct_equiv_on P0 m0 m1)
(
HP :
forall b p,
P1 b p ->
P0 b p):
memct_equiv_on P1 m0 m1.
Proof.
Lemma mem_equiv_on_weaken (
P0 P1 :
eq_on_frame)
m0 m1
(
E :
mem_equiv_on P0 m0 m1)
(
HP :
forall b p,
P1 b p ->
P0 b p):
mem_equiv_on P1 m0 m1.
Proof.
Lemma memct_gsspec b ofs v m0 b' ofs':
memct_get b' ofs' (
memct_set b ofs v m0) =
if peq b' b &&
zeq ofs' ofs then v else memct_get b' ofs' m0.
Proof.
Lemma memct_set_eq1 b ofs v m0:
memct_equiv_on (
fun b' ofs' => ~(
b' =
b /\
ofs' =
ofs))
m0 (
memct_set b ofs v m0).
Proof.
intros b' ofs' NEQ;
simpl in NEQ.
rewrite memct_gsspec.
unfold proj_sumbool;
do 2 (
autodestruct;
simpl;
auto).
tauto.
Qed.
Lemma memct_set_eq2 P b ofs v m0 m1
(
E :
memct_equiv_on P m0 m1):
memct_equiv_on
(
fun b' ofs' =>
P b' ofs' \/ (
b' =
b /\
ofs' =
ofs))
(
memct_set b ofs v m0) (
memct_set b ofs v m1).
Proof.
intros b' ofs' H;
simpl in H.
rewrite !
memct_gsspec.
unfold proj_sumbool.
do 2
try (
autodestruct;
simpl;
intros _).
auto.
all:
apply E;
tauto.
Qed.
Fixpoint memct_setN (
b :
Values.block) (
vl :
list memval) (
p :
Z) (
m :
memct_t) :
memct_t :=
match vl with
|
nil =>
m
|
v ::
vl =>
memct_setN b vl (
p + 1) (
memct_set b p v m)
end.
Lemma mem_setN_ctnt (
m :
memct_t) (
mb :
ZXMap.t Mem.memval_default) (
b :
Values.block) (
vl :
list memval) (
p :
Z):
PXMap.set b (
Mem.setN vl p mb)
m =
memct_setN b vl p (
PXMap.set b mb m).
Proof.
revert mb p;
induction vl;
simpl;
intros.
-
reflexivity.
-
rewrite IHvl;
f_equal.
unfold memct_set.
rewrite PXMap.gss,
PXMap.set2.
reflexivity.
Qed.
Lemma memct_setN_equiv_on1 b bytes:
forall ofs c,
memct_equiv_on
(
fun b' ofs' => ~(
b' =
b /\
ofs <=
ofs' <
ofs +
Z.of_nat (
Datatypes.length bytes)))
c (
memct_setN b bytes ofs c).
Proof.
Lemma store_equiv_on1 chk m b p v m'
(
ST :
Mem.store chk m b p v =
Some m'):
mem_equiv_on (
fun b' p' => ~(
b' =
b /\
p <=
p' <
p +
size_chunk chk))
m m'.
Proof.
Lemma storebytes_equiv_on1 m b ofs bytes m'
(
ST :
Mem.storebytes m b ofs bytes =
Some m'):
mem_equiv_on (
fun b' ofs' => ~(
b' =
b /\
ofs <=
ofs' <
ofs +
Z.of_nat (
List.length bytes)))
m m'.
Proof.
Lemma memcpy_equiv_on1 chk bmal bdst odst bsrc osrc rm m m':
memcpy chk bmal bdst odst bsrc osrc rm m =
Some m' ->
mem_equiv_on (
fun b' ofs' => ~(
b' =
bdst /\
odst <=
ofs' <
odst +
Zpos (
cpy_sz chk)))
m m'.
Proof.
Lemma memct_setN_equiv_on2 b bytes:
forall P ofs c0 c1
(
EQ:
memct_equiv_on P c0 c1),
memct_equiv_on (
fun b' ofs' =>
P b' ofs' \/ (
b' =
b /\
ofs <=
ofs' <
ofs +
Z.of_nat (
Datatypes.length bytes)))
(
memct_setN b bytes ofs c0) (
memct_setN b bytes ofs c1).
Proof.
Lemma store_equiv_on2 P chk m0 m1 b p v m0' m1'
(
E :
mem_equiv_on P m0 m1)
(
ST0 :
Mem.store chk m0 b p v =
Some m0')
(
ST1 :
Mem.store chk m1 b p v =
Some m1'):
mem_equiv_on
(
fun b' p' =>
P b' p' \/ (
b' =
b /\
p <=
p' <
p +
size_chunk chk))
m0' m1'.
Proof.
Lemma store_morph_equiv_on P chk m0 m1 b ofs v m0' m1'
(
E :
mem_equiv_on P m0 m1)
(
ST0 :
Mem.store chk m0 b ofs v =
Some m0')
(
ST1 :
Mem.store chk m1 b ofs v =
Some m1'):
mem_equiv_on P m0' m1'.
Proof.
Lemma storebytes_equiv_on2 P m0 m1 b ofs bytes m0' m1'
(
E :
mem_equiv_on P m0 m1)
(
ST0 :
Mem.storebytes m0 b ofs bytes =
Some m0')
(
ST1 :
Mem.storebytes m1 b ofs bytes =
Some m1'):
mem_equiv_on
(
fun b' ofs' =>
P b' ofs' \/ (
b' =
b /\
ofs <=
ofs' <
ofs +
Z.of_nat (
List.length bytes)))
m0' m1'.
Proof.
Lemma memcpy_equiv_on2 P m0 m1 chk bmal bdst odst bsrc osrc rm m0' m1'
(
EQ :
mem_equiv_on P m0 m1):
(
memcpy chk bmal bdst odst bsrc osrc rm m0 =
Some m0') ->
(
memcpy chk bmal bdst odst bsrc osrc rm m1 =
Some m1') ->
mem_equiv_on (
fun b' ofs' =>
P b' ofs' \/ (
b' =
bdst /\
odst <=
ofs' <
odst +
Zpos (
cpy_sz chk)))
m0' m1'.
Proof.
Lemma memcpy_morph_equiv_on P m0 m1 chk bmal bdst odst bsrc osrc rm m0' m1'
(
EQ :
mem_equiv_on P m0 m1)
(
CPY1:
memcpy chk bmal bdst odst bsrc osrc rm m0 =
Some m0')
(
CPY2:
memcpy chk bmal bdst odst bsrc osrc rm m1 =
Some m1'):
mem_equiv_on P m0' m1'.
Proof.
End LemmasMemory.
Symbolic & abstract address in a memory/memcpy chunk of size a_size
Record address :
Set :=
mk_addr {
a_size:
positive;
a_addr:
addressing;
a_args:
list_sval;
a_aval:
option aval
}.
Definition psize_chunk (
chunk:
memory_chunk) :
positive :=
Z.to_pos (
size_chunk chunk).
Lemma psize_chunk_Zpos chunk:
Zpos (
psize_chunk chunk) =
size_chunk chunk.
Proof.
Definition eval_address (
ctx :
iblock_common_context) (
a :
address):
option (
Values.block *
ptrofs) :=
SOME args <-
eval_list_sval ctx (
a_args a)
IN
SOME v <-
eval_addressing (
cge ctx) (
csp ctx) (
a_addr a)
args IN
ASSERT (
if_Some_dec (
a_aval a) (
fun av =>
vmatch_dec (
cbc ctx)
v av))
IN
match v with
|
Vptr b o =>
Some (
b,
o)
| _ =>
None
end.
Section DisjointnessCriteria.
Definition vaddr_disjoint (
v0 :
Values.block *
ptrofs) (
sz0 :
positive)
(
v1 :
Values.block *
ptrofs) (
sz1 :
positive):
Prop :=
let (
b0,
ofs0) :=
v0 in
let (
b1,
ofs1) :=
v1 in
b0 <>
b1 \/
Ptrofs.unsigned ofs0 + (
Zpos sz0) <=
Ptrofs.unsigned ofs1 \/
Ptrofs.unsigned ofs1 + (
Zpos sz1) <=
Ptrofs.unsigned ofs0.
Definition addr_disjoint (
ctx :
iblock_common_context) (
a0 a1 :
address) :=
if_Some (
eval_address ctx a0) (
fun v0 =>
if_Some (
eval_address ctx a1) (
fun v1 =>
vaddr_disjoint v0 (
a_size a0)
v1 (
a_size a1))).
Lemma addr_disjoint_sym ctx a0 a1:
addr_disjoint ctx a0 a1 ->
addr_disjoint ctx a1 a0.
Proof.
Remark addr_disjoint_irrefl ctx a:
addr_disjoint ctx a a ->
eval_address ctx a =
None.
Proof.
Let u :=
Ptrofs.unsigned.
Definition offset_chunk_lt (
ofs0 :
ptrofs) (
sz0 :
positive)
(
ofs1 :
ptrofs) (
sz1 :
positive)
:= (
u ofs0 +
Zpos sz0) <=
u ofs1 /\
(
u ofs1 +
Zpos sz1) <=
u ofs0 +
Ptrofs.modulus.
Definition offset_disjoint (
ofs0 :
ptrofs) (
sz0 :
positive)
(
ofs1 :
ptrofs) (
sz1 :
positive)
:=
offset_chunk_lt ofs0 sz0 ofs1 sz1 \/
offset_chunk_lt ofs1 sz1 ofs0 sz0.
Lemma disjoint_interval_modulo (
m :
Z) (
a b :
Z) (
al bl :
Z) (
c :
Z):
0 <
m ->
0 <=
al -> 0 <=
bl ->
a +
al <=
b ->
b +
bl <=
a +
m ->
(
c +
a)
mod m +
al <= (
c +
b)
mod m \/ (
c +
b)
mod m +
bl <= (
c +
a)
mod m.
Proof.
intros Hmpos Le0 Le1 Le2 Le3.
rewrite !
Z.mod_eq by lia.
case (
Z_le_lt_eq_dec ((
c +
a) /
m) ((
c +
b) /
m))
as [
Wrap|
NoWrap].
{
apply Z.div_le_mono;
lia. }
-
right.
assert (
Le: (
c +
a) /
m + 1 <= (
c +
b) /
m)
by lia.
apply Zmult_le_compat_l with (
p:=
m)
in Le;
lia.
-
left.
lia.
Qed.
Lemma offset_disjoint_computed_addr (
bo :
Z)
ofs0 sz0 ofs1 sz1:
offset_disjoint ofs0 sz0 ofs1 sz1 ->
(
bo +
u ofs0)
mod Ptrofs.modulus +
Zpos sz0 <= (
bo +
u ofs1)
mod Ptrofs.modulus \/
(
bo +
u ofs1)
mod Ptrofs.modulus +
Zpos sz1 <= (
bo +
u ofs0)
mod Ptrofs.modulus.
Proof.
Lemma offset_disjoint_sound ctx a0 ofs0 a1 ofs1
(
A0:
is_indexed_addr (
a_addr a0)
ofs0)
(
A1:
is_indexed_addr (
a_addr a1)
ofs1)
(
B:
list_sval_equiv ctx (
a_args a0) (
a_args a1))
(
D:
offset_disjoint ofs0 (
a_size a0)
ofs1 (
a_size a1)):
addr_disjoint ctx a0 a1.
Proof.
Static criteria using the result of the abstract analysis, for -fprepass-alias-abs, the LCT
and the store-motion.
Lemma abs_disjoint_sound ctx a0 a1 aa0 aa1
(
AA0 :
a_aval a0 =
Some aa0)
(
AA1 :
a_aval a1 =
Some aa1)
(
D:
vdisjoint aa0 (
Zpos (
a_size a0))
aa1 (
Zpos (
a_size a1)) =
true):
addr_disjoint ctx a0 a1.
Proof.
End DisjointnessCriteria.
Section MemcpyLib.
Handling of fake smem from memcpy sequences
Definition fmcpy (
mc:
memcpy_args list_sval) (
sm:
smem)
:=
fSmemcpy sm (
mcpy_chk mc) (
mcpy_daddr mc) (
mcpy_dargs mc) (
mcpy_saddr mc) (
mcpy_sargs mc)
sm (
mcpy_info mc).
Lemma fmcpy_alive_monotonic ctx mc:
forall sm,
eval_smem ctx sm =
None ->
eval_smem ctx (
fmcpy mc sm) =
None.
Proof.
unfold fmcpy;
simplify_option.
Qed.
Lemma fmcpy_morph_smem_equiv ctx mc:
forall sm1 sm2,
smem_equiv ctx sm1 sm2 ->
smem_equiv ctx (
fmcpy mc sm1) (
fmcpy mc sm2).
Proof.
unfold fmcpy;
cbn.
simplify_option.
Qed.
Fixpoint fmcpy_merge (
seq:
list (
memcpy_args list_sval)) (
sm:
smem) :
smem :=
match seq with
|
nil =>
sm
|
mc::
seq0 =>
fmcpy_merge seq0 (
fmcpy mc sm)
end.
Local Hint Resolve fmcpy_alive_monotonic fmcpy_morph_smem_equiv:
core.
Lemma fmcpy_merge_alive_monotonic ctx seq:
forall sm,
eval_smem ctx sm =
None ->
eval_smem ctx (
fmcpy_merge seq sm) =
None.
Proof.
induction seq; cbn; eauto.
Qed.
Lemma fmcpy_merge_alive_back ctx seq sm:
alive (
eval_smem ctx (
fmcpy_merge seq sm)) ->
alive (
eval_smem ctx sm).
Proof.
Lemma fmcpy_merge_morph_smem_equiv ctx seq:
forall sm1 sm2,
smem_equiv ctx sm1 sm2 ->
smem_equiv ctx (
fmcpy_merge seq sm1) (
fmcpy_merge seq sm2).
Proof.
induction seq; cbn; eauto.
Qed.
Definition mcpy_da (
mc:
memcpy_args list_sval):
address :=
mk_addr (
cpy_sz (
mcpy_chk mc)) (
mcpy_daddr mc) (
mcpy_dargs mc) (
memcpy_daaddr (
mcpy_info mc)).
Definition mcpy_sa (
mc:
memcpy_args list_sval):
address :=
mk_addr (
cpy_sz (
mcpy_chk mc)) (
mcpy_saddr mc) (
mcpy_sargs mc) (
memcpy_saaddr (
mcpy_info mc)).
Lemma fmcpy_alive_eval_address ctx mc sm:
alive (
eval_smem ctx (
fmcpy mc sm)) ->
exists dst src m,
eval_address ctx (
mcpy_da mc) =
Some dst
/\
eval_address ctx (
mcpy_sa mc) =
Some src
/\
eval_smem ctx sm =
Some m
/\
eval_smem ctx (
fmcpy mc sm) =
memcpy (
mcpy_chk mc) (
bmal_of (
Mem.block_align (
cm1 ctx)) (
fst dst) (
fst src)) (
fst dst) (
Ptrofs.unsigned (
snd dst)) (
fst src) (
Ptrofs.unsigned (
snd src))
m m.
Proof.
unfold fmcpy,
eval_address;
cbn;
do 8
autodestruct.
destruct a.
intros;
do 3
eexists;
split;
autodestruct.
cbn.
repeat (
econstructor;
eauto).
Qed.
Lemma eval_address_fmcpy ctx mc sm dst src m:
eval_smem ctx sm =
Some m ->
eval_address ctx (
mcpy_da mc) =
Some dst ->
eval_address ctx (
mcpy_sa mc) =
Some src ->
eval_smem ctx (
fmcpy mc sm) =
memcpy (
mcpy_chk mc) (
bmal_of (
Mem.block_align (
cm1 ctx)) (
fst dst) (
fst src)) (
fst dst) (
Ptrofs.unsigned (
snd dst)) (
fst src) (
Ptrofs.unsigned (
snd src))
m m.
Proof.
End MemcpyLib.
Section EqualityTests.
address oa is a shift of address ta by offset ofs
Definition shift_address (
ctx :
iblock_common_context) (
oa ta:
address) (
ofs:
ptrofs) :=
if_Some (
eval_address ctx oa) (
fun ov =>
if_Some (
eval_address ctx ta) (
fun tv =>
fst ov =
fst tv
/\
snd ov =
Ptrofs.add (
snd tv)
ofs
)).
Definition pure_fast_eq [
A:
Set] (
h :
A ->
hashcode) (
x0 x1 :
A) : {
x0 =
x1}+{
True}.
Proof.
Definition test_shift_rel (
oa ta:
address) (
ofs:
ptrofs):
bool :=
if pure_fast_eq list_sval_get_hid (
a_args oa) (
a_args ta)
then
match test_is_indexed (
a_addr oa)
with
|
inright _ =>
false
|
inleft oo =>
match test_is_indexed (
a_addr ta)
with
|
inright _ =>
false
|
inleft to =>
Ptrofs.eq_dec (`
oo) (
Ptrofs.add (`
to)
ofs) |||
false
end end
else false.
Lemma test_shift_rel_correct ctx oa ta ofs:
test_shift_rel oa ta ofs =
true ->
shift_address ctx oa ta ofs.
Proof.
unfold test_shift_rel.
repeat autodestruct.
intros _ _ _ _ _.
destruct s as (
oo &
Hoo),
s0 as (
to &
Hto).
cbn in *.
unfold shift_address,
eval_address.
unfold if_Some.
do 4
autodestruct.
cbn.
intros EQ _
EVALo.
eapply is_indexed_addr_case in Hoo.
erewrite EVALo in Hoo.
destruct Hoo as [(
ob &
oo0 &
EQo &
EQl)|];
contradiction ||
subst.
rewrite e;
clear e.
try_simplify_someHyps.
intros EVALoa EVALov.
erewrite is_indexed_addr_eval;
eauto.
autodestruct.
cbn.
intros.
repeat (
split;
auto with zarith).
rewrite Ptrofs.add_assoc.
auto.
Qed.
Global Opaque test_shift_rel.
Definition test_pshift (
op tp:
aptr) (
ofs:
ptrofs) :
bool :=
match op,
tp with
|
Pbot, _ =>
true
| _,
Pbot =>
true
|
Gl oid oo,
Gl tid to =>
QualIdent.eq oid tid
&&& (
Ptrofs.eq_dec oo (
Ptrofs.add to ofs) |||
false)
|
Stk oo,
Stk to =>
Ptrofs.eq_dec oo (
Ptrofs.add to ofs) |||
false
| _, _ =>
false
end.
Lemma test_pshift_correct (
bc:
block_classification)
op tp ofs ob oo tb to:
pmatch bc ob oo op ->
pmatch bc tb to tp ->
test_pshift op tp ofs =
true ->
ob =
tb /\
oo =
Ptrofs.add to ofs.
Proof.
unfold test_pshift.
destruct bc.
cbn.
destruct 1;
destruct 1;
try congruence;
repeat autodestruct;
cbn in *;
subst;
intuition eauto.
Qed.
Definition test_ashift (
oav tav:
aval) (
ofs:
ptrofs):
bool :=
match oav with
|
Uns op _ |
Sgn op _ |
Ptr op |
Ifptr op =>
match tav with
|
Uns tp _ |
Sgn tp _ |
Ptr tp |
Ifptr tp =>
test_pshift op tp ofs
| _ =>
true
end
| _ =>
true
end.
Lemma test_ashift_correct bc oav tav ofs ob oo tb to:
vmatch bc (
Vptr ob oo)
oav ->
vmatch bc (
Vptr tb to)
tav ->
test_ashift oav tav ofs =
true ->
ob =
tb /\
oo =
Ptrofs.add to ofs.
Proof.
Global Opaque test_ashift.
Definition test_shift_addr (
oa ta:
address) (
ofs:
ptrofs):
bool :=
test_shift_rel oa ta ofs |||
match a_aval oa,
a_aval ta with
|
Some oav,
Some tav =>
test_ashift oav tav ofs
| _, _ =>
false
end.
Lemma test_shift_addr_correct ctx oa ta ofs:
test_shift_addr oa ta ofs =
true ->
shift_address ctx oa ta ofs.
Proof.
Definition test_eq_live_abs (
oa ta:
address):
bool :=
match a_aval oa,
a_aval ta with
|
Some oav,
Some tav =>
test_ashift oav tav Ptrofs.zero
| _, _ =>
false
end.
Lemma test_eq_live_abs_correct ctx oa ta:
alive (
eval_address ctx oa) ->
alive (
eval_address ctx ta) ->
test_eq_live_abs oa ta =
true ->
eval_address ctx oa =
eval_address ctx ta.
Proof.
Global Opaque test_eq_live_abs.
Definition test_eq_addr (
oa ta :
address):
bool :=
pure_fast_eq list_sval_get_hid (
a_args oa) (
a_args ta)
&&& (
eq_addressing (
a_addr oa) (
a_addr ta)
&&& (
option_eq eq_aval (
a_aval oa) (
a_aval ta) |||
false))
.
Lemma test_eq_addr_correct ctx oa ta:
test_eq_addr oa ta =
true ->
eval_address ctx oa =
eval_address ctx ta.
Proof.
Global Opaque test_eq_addr.
Definition test_eq_live_addr (
oa ta :
address):
bool :=
test_eq_live_abs oa ta
|||
test_eq_addr oa ta
.
Lemma test_eq_live_addr_correct ctx oa ta:
test_eq_live_addr oa ta =
true ->
alive (
eval_address ctx oa) ->
alive (
eval_address ctx ta) ->
eval_address ctx oa =
eval_address ctx ta.
Proof.
Global Opaque test_eq_live_addr.
Definition test_pcmp (
p1 p2:
aptr):
option comparison :=
match p1,
p2 with
|
Gl id1 o1,
Gl id2 o2 =>
ASSERT QualIdent.eq id1 id2 IN
Some (
Ptrofs.unsigned o1 ?=
Ptrofs.unsigned o2)
|
Stk o1,
Stk o2 =>
Some (
Ptrofs.unsigned o1 ?=
Ptrofs.unsigned o2)
| _, _ =>
None
end.
Lemma test_pcmp_correct (
bc:
block_classification)
p1 p2 b1 o1 b2 o2 cmp:
pmatch bc b1 o1 p1 ->
pmatch bc b2 o2 p2 ->
test_pcmp p1 p2 =
Some cmp ->
b1 =
b2 /\ (
Ptrofs.unsigned o1 ?=
Ptrofs.unsigned o2) =
cmp.
Proof.
unfold test_pcmp.
destruct bc.
cbn.
destruct 1;
destruct 1;
try congruence;
simplify_option.
Qed.
Definition test_acmp (
av1 av2:
aval):
option comparison :=
match av1 with
|
Uns p1 _ |
Sgn p1 _ |
Ptr p1 |
Ifptr p1 =>
match av2 with
|
Uns p2 _ |
Sgn p2 _ |
Ptr p2 |
Ifptr p2 =>
test_pcmp p1 p2
| _ =>
None
end
| _ =>
None
end.
Lemma test_acmp_correct bc av1 av2 b1 o1 b2 o2 cmp:
vmatch bc (
Vptr b1 o1)
av1 ->
vmatch bc (
Vptr b2 o2)
av2 ->
test_acmp av1 av2 =
Some cmp ->
b1 =
b2 /\ (
Ptrofs.unsigned o1 ?=
Ptrofs.unsigned o2) =
cmp.
Proof.
Global Opaque test_acmp.
Definition test_cmp_addr (
oa1 oa2:
address):
option comparison :=
SOME av1 <-
a_aval oa1 IN
SOME av2 <-
a_aval oa2 IN
test_acmp av1 av2.
Lemma test_cmp_addr_correct ctx oa1 oa2 r1 r2 cmp:
test_cmp_addr oa1 oa2 =
Some cmp ->
eval_address ctx oa1 =
Some r1 ->
eval_address ctx oa2 =
Some r2 ->
fst r1 =
fst r2 /\ (
Ptrofs.unsigned (
snd r1) ?=
Ptrofs.unsigned (
snd r2)) =
cmp.
Proof.
Global Opaque test_cmp_addr.
End EqualityTests.
Section RewritingRules.
Definition aSload sm trap chk addr args aaddr :=
fSmayUndef_opt
(
SOME aaddr <-
aaddr IN Some (
fOKaddrMatch addr args aaddr))
(
fSload sm trap chk addr args).
Definition eval_aSload_def_0 trap (
v :
option val) :
option val :=
match v with
|
Some v =>
Some v
|
None =>
match trap with
|
TRAP =>
None
|
NOTRAP =>
Some Vundef
end
end.
Definition eval_aSload_def_1 ctx trap chk addr args m :=
SOME args <-
eval_list_sval ctx args IN
match trap with
|
TRAP =>
SOME v <-
eval_addressing (
cge ctx) (
csp ctx)
addr args IN
match v with
|
Vptr b ofs =>
match Mem.load chk m b (
Ptrofs.unsigned ofs)
with
|
Some v =>
Some Vundef
|
None =>
None
end
| _ =>
None
end
|
NOTRAP =>
Some Vundef
end.
Lemma eval_aSload_def_1_unchanged ctx trap chk addr args m0 m1
(
EQ_PERM :
forall b ofs k p,
Mem.perm m0 b ofs k p <->
Mem.perm m1 b ofs k p):
eval_aSload_def_1 ctx trap chk addr args m0 =
eval_aSload_def_1 ctx trap chk addr args m1.
Proof.
Lemma eval_aSload_eq ctx sm m trap chk addr args aaddr
(
MEM :
eval_smem ctx sm =
Some m):
eval_sval ctx (
aSload sm trap chk addr args aaddr) =
match eval_address ctx (
mk_addr (
psize_chunk chk)
addr args aaddr)
with
|
Some (
b,
ofs) =>
eval_aSload_def_0 trap (
Mem.load chk m b (
Ptrofs.unsigned ofs))
|
None =>
eval_aSload_def_1 ctx trap chk addr args m
end.
Proof.
Lemma eval_aSstore_eq ctx sm chk addr args sinfo sv hc:
eval_smem ctx (
Sstore sm chk addr args sinfo sv hc) =
SOME a <-
eval_address ctx (
mk_addr (
psize_chunk chk)
addr args (
store_aaddr sinfo))
IN
let (
b,
ofs) :=
a in
SOME v <-
eval_sval ctx sv IN
SOME m <-
eval_smem ctx sm IN
Mem.store chk m b (
Ptrofs.unsigned ofs)
v.
Proof.
Lemma eval_aSmemcpy_eq ctx sm chk daddr dargs saddr sargs rom minfo hc:
eval_smem ctx (
Smemcpy sm chk daddr dargs saddr sargs rom minfo hc) =
SOME da <-
eval_address ctx (
mk_addr (
cpy_sz chk)
daddr dargs (
memcpy_daaddr minfo))
IN
SOME sa <-
eval_address ctx (
mk_addr (
cpy_sz chk)
saddr sargs (
memcpy_saaddr minfo))
IN
let (
bdst,
odst) :=
da in
let (
bsrc,
osrc) :=
sa in
SOME rm <-
eval_smem ctx rom IN
SOME wm <-
eval_smem ctx sm IN
memcpy chk (
bmal_of (
Mem.block_align (
cm1 ctx))
bdst bsrc)
bdst (
Ptrofs.unsigned odst)
bsrc (
Ptrofs.unsigned osrc)
rm wm.
Proof.
unfold eval_address.
cbn.
symmetry.
repeat autodestruct.
Qed.
Rules to reorder stores
Definition smem_reorderable (
a0:
address) (
rew0:
smem ->
hashcode ->
smem) (
a1:
address) (
rew1:
smem ->
hashcode ->
smem) :
Prop :=
forall ctx sm hc0 hc1 hc0' hc1',
addr_disjoint ctx a0 a1 ->
smem_equiv ctx (
rew0 (
rew1 sm hc1)
hc0) (
rew1 (
rew0 sm hc0')
hc1').
Definition store_reorderable (
a0:
address) (
rew0:
smem ->
smem):
Prop
:=
forall chk1 addr1 args1 sv1 sinfo1,
smem_reorderable a0 (
fun sm _ =>
rew0 sm) (
mk_addr (
psize_chunk chk1)
addr1 args1 (
store_aaddr sinfo1))
(
fun sm =>
Sstore sm chk1 addr1 args1 sinfo1 sv1).
Lemma store_store_reorderable chk0 addr0 args0 sv0 sinfo0:
store_reorderable (
mk_addr (
psize_chunk chk0)
addr0 args0 (
store_aaddr sinfo0))
(
fun sm =>
fSstore sm chk0 addr0 args0 sinfo0 sv0).
Proof.
Lemma store_memcpy_reorderable_aux (
sm :
smem) (
chk0:
memory_chunk)
chk1
addr args sv sinfo daddr dargs saddr sargs rom minfo:
smem_reorderable (
mk_addr (
psize_chunk chk0)
addr args (
store_aaddr sinfo))
(
fun sm =>
Sstore sm chk0 addr args sinfo sv)
(
mk_addr (
cpy_sz chk1)
daddr dargs (
memcpy_daaddr minfo))
(
fun sm =>
Smemcpy sm chk1 daddr dargs saddr sargs rom minfo).
Proof.
Definition memcpy_reorderable (
a0:
address) (
rew0:
smem ->
smem):
Prop
:=
forall chk1 daddr dargs saddr sargs rom minfo,
smem_reorderable a0 (
fun sm _ =>
rew0 sm)
(
mk_addr (
cpy_sz chk1)
daddr dargs (
memcpy_daaddr minfo))
(
fun sm =>
Smemcpy sm chk1 daddr dargs saddr sargs rom minfo).
Lemma store_memcpy_reorderable chk0 addr0 args0 sv0 sinfo0:
memcpy_reorderable (
mk_addr (
psize_chunk chk0)
addr0 args0 (
store_aaddr sinfo0))
(
fun sm =>
fSstore sm chk0 addr0 args0 sinfo0 sv0).
Proof.
Lemma memcpy_store_reorderable chk daddr dargs saddr sargs rom minfo:
store_reorderable (
mk_addr (
cpy_sz chk)
daddr dargs (
memcpy_daaddr minfo))
(
fun sm =>
fSmemcpy sm chk daddr dargs saddr sargs rom minfo).
Proof.
Lemma memcpy_memcpy_reorderable chk daddr dargs saddr sargs rom minfo:
memcpy_reorderable (
mk_addr (
cpy_sz chk)
daddr dargs (
memcpy_daaddr minfo))
(
fun sm =>
fSmemcpy sm chk daddr dargs saddr sargs rom minfo).
Proof.
Definition sm_reorderable (
a0:
address) (
rew0:
smem ->
smem) :=
store_reorderable a0 rew0
/\
memcpy_reorderable a0 rew0
.
Lemma store_sm_reorderable chk0 addr0 args0 sv0 sinfo0:
sm_reorderable (
mk_addr (
psize_chunk chk0)
addr0 args0 (
store_aaddr sinfo0))
(
fun sm =>
fSstore sm chk0 addr0 args0 sinfo0 sv0).
Proof.
Lemma memcpy_sm_reorderable chk daddr dargs saddr sargs rom minfo:
sm_reorderable (
mk_addr (
cpy_sz chk)
daddr dargs (
memcpy_daaddr minfo))
(
fun sm =>
fSmemcpy sm chk daddr dargs saddr sargs rom minfo).
Proof.
Rules to rewrite under loads and stores
Inductive smem_equiv_on (
P :
eq_on_frame) (
ctx :
iblock_common_context) (
sm0 sm1 :
smem)
:
Prop
:=
Smem_equiv_on m0 m1
(
EVAL_M0 :
eval_smem ctx sm0 =
Some m0)
(
EVAL_M1 :
eval_smem ctx sm1 =
Some m1)
(
EQ_ON :
mem_equiv_on P m0 m1).
Lemma smem_equiv_on_refl P ctx sm:
alive (
eval_smem ctx sm) ->
smem_equiv_on P ctx sm sm.
Proof.
case eval_smem as [
m|]
eqn:
M. 2:
congruence.
exists m m;
auto.
reflexivity.
Qed.
Global Instance smem_equiv_on_PER {
P ctx}:
PER (
smem_equiv_on P ctx).
Proof.
split.
- intros ? ? []. econstructor; eauto. symmetry; assumption.
- intros ? ? ? [m0 m1 E0 E1 EQ0] [m1' m2 E1' E2 EQ1].
rewrite E1 in E1'. injection E1' as ?. subst m1'.
exists m0 m2; eauto.
etransitivity; eassumption.
Qed.
Lemma apply_store_smem_equiv_on P ctx sm0 sm1 chk addr sargs sinfo sv hc0 hc1:
smem_equiv_on P ctx sm0 sm1 ->
let sm0' :=
Sstore sm0 chk addr sargs sinfo sv hc0 in
let sm1' :=
Sstore sm1 chk addr sargs sinfo sv hc1 in
alive (
eval_smem ctx sm0') ->
smem_equiv_on P ctx sm0' sm1'.
Proof.
Lemma apply_memcpy_smem_equiv_on P ctx sm0 sm1 chk daddr dargs saddr sargs rm minfo hc0 hc1:
smem_equiv_on P ctx sm0 sm1 ->
let sm0' :=
Smemcpy sm0 chk daddr dargs saddr sargs rm minfo hc0 in
let sm1' :=
Smemcpy sm1 chk daddr dargs saddr sargs rm minfo hc1 in
alive (
eval_smem ctx sm0') ->
smem_equiv_on P ctx sm0' sm1'.
Proof.
Definition store_crange (
ctx :
iblock_common_context) (
a :
address) :
eq_on_frame :=
(
fun b' p' =>
if_Some (
eval_address ctx a) (
fun av =>
let (
b,
ofs) :=
av in
let p :=
Ptrofs.unsigned ofs in
~(
b' =
b /\
p <=
p' <
p +
Zpos (
a_size a)))).
Lemma rewrite_store_equiv_on ctx sm0 sm1 (
chk:
memory_chunk)
addr sargs sinfo sv hc0 hc1 :
let a :=
mk_addr (
psize_chunk chk)
addr sargs (
store_aaddr sinfo)
in
let sm0' :=
Sstore sm0 chk addr sargs sinfo sv hc0 in
let sm1' :=
Sstore sm1 chk addr sargs sinfo sv hc1 in
smem_equiv_on (
store_crange ctx a)
ctx sm0 sm1 ->
smem_equiv ctx sm0' sm1'.
Proof.
Lemma remove_store_smem_equiv_on ctx sm0 (
chk:
memory_chunk)
addr sargs sinfo sv hc:
let a :=
mk_addr (
psize_chunk chk)
addr sargs (
store_aaddr sinfo)
in
let sm1 :=
Sstore sm0 chk addr sargs sinfo sv hc in
forall (
MALIVE:
alive (
eval_smem ctx sm1)),
smem_equiv_on (
store_crange ctx a)
ctx sm0 sm1.
Proof.
Lemma remove_memcpy_smem_equiv_on ctx sm0 chk daddr dargs saddr sargs rom minfo hc:
let a :=
mk_addr (
cpy_sz chk)
daddr dargs (
memcpy_daaddr minfo)
in
let sm1 :=
Smemcpy sm0 chk daddr dargs saddr sargs rom minfo hc in
forall (
MALIVE:
alive (
eval_smem ctx sm1)),
smem_equiv_on (
store_crange ctx a)
ctx sm0 sm1.
Proof.
Definition load_range (
ctx :
iblock_common_context) (
a :
address) :
eq_on_frame :=
(
fun b i =>
exists ofs,
eval_address ctx a =
Some (
b,
ofs) /\
Ptrofs.unsigned ofs <=
i <
Ptrofs.unsigned ofs +
Zpos (
a_size a)).
Lemma rewrite_load_equiv_on ctx sm0 sm1 trap (
chk:
memory_chunk)
addr sargs aaddr:
let a :=
mk_addr (
psize_chunk chk)
addr sargs aaddr in
smem_equiv_on (
load_range ctx a)
ctx sm0 sm1 ->
sval_equiv ctx (
aSload sm0 trap chk addr sargs aaddr)
(
aSload sm1 trap chk addr sargs aaddr).
Proof.
Lemma rewrite_memcpy_read_equiv_on ctx rm0 rm1 chk daddr dargs saddr sargs sm minfo:
let sa :=
mk_addr (
cpy_sz chk)
saddr sargs (
memcpy_saaddr minfo)
in
smem_equiv_on (
load_range ctx sa)
ctx rm0 rm1 ->
smem_equiv ctx (
fSmemcpy sm chk daddr dargs saddr sargs rm0 minfo)
(
fSmemcpy sm chk daddr dargs saddr sargs rm1 minfo).
Proof.
Lemma disjoint_store_smem_equiv_on ctx a sm0 (
chk:
memory_chunk)
addr sargs sinfo sv hc
(
DJ :
addr_disjoint ctx a (
mk_addr (
psize_chunk chk)
addr sargs (
store_aaddr sinfo))):
let range :=
load_range ctx a in
let sm1 :=
Sstore sm0 chk addr sargs sinfo sv hc in
forall (
MALIVE:
alive (
eval_smem ctx sm1)),
smem_equiv_on range ctx sm0 sm1.
Proof.
Lemma disjoint_memcpy_smem_equiv_on ctx a sm0 chk daddr dargs saddr sargs rom minfo hc
(
DJ :
addr_disjoint ctx a (
mk_addr (
cpy_sz chk)
daddr dargs (
memcpy_daaddr minfo))):
let range :=
load_range ctx a in
let sm1 :=
Smemcpy sm0 chk daddr dargs saddr sargs rom minfo hc in
forall (
MALIVE:
alive (
eval_smem ctx sm1)),
smem_equiv_on range ctx sm0 sm1.
Proof.
End RewritingRules.
Section DisjointnessTest.
Program Definition test_offset_lt (
ofs0 :
ptrofs) (
sz0 :
positive)
(
ofs1 :
ptrofs) (
sz1 :
positive)
: {
offset_chunk_lt ofs0 sz0 ofs1 sz1}+{
True} :=
if zle (
Ptrofs.unsigned ofs0 +
Zpos sz0) (
Ptrofs.unsigned ofs1)
then if zle (
Ptrofs.unsigned ofs1 +
Zpos sz1) (
Ptrofs.unsigned ofs0 +
Ptrofs.modulus)
then left _
else right _
else right _.
Next Obligation.
Program Definition test_offset_disjoint (
ofs0 :
ptrofs) (
sz0 :
positive)
(
ofs1 :
ptrofs) (
sz1 :
positive)
: {
offset_disjoint ofs0 sz0 ofs1 sz1}+{
True} :=
if test_offset_lt ofs0 sz0 ofs1 sz1
then left _
else if test_offset_lt ofs1 sz1 ofs0 sz0
then left _
else right _.
Solve All Obligations with (
unfold offset_disjoint;
auto).
Program Definition test_disjoint_rel (
a0 a1 :
address)
: {
forall ctx,
addr_disjoint ctx a0 a1}+{
True} :=
if pure_fast_eq list_sval_get_hid (
a_args a0) (
a_args a1)
then
match test_is_indexed (
a_addr a0)
with
|
inright _ =>
right _
|
inleft ofs0 =>
match test_is_indexed (
a_addr a1)
with
|
inright _ =>
right _
|
inleft ofs1 =>
if test_offset_disjoint ofs0 (
a_size a0)
ofs1 (
a_size a1)
then left _
else right _
end end
else right _.
Next Obligation.
Global Opaque test_disjoint_rel.
Definition test_disjoint_abs (
a0 a1 :
address)
: {
forall ctx,
addr_disjoint ctx a0 a1}+{
True}.
case (
a_aval a0)
as [
aa0|]
eqn:
AA0; [|
right;
trivial].
case (
a_aval a1)
as [
aa1|]
eqn:
AA1; [|
right;
trivial].
case (
vdisjoint aa0 (
Zpos (
a_size a0))
aa1 (
Zpos (
a_size a1)))
eqn:
D;
[|
right;
trivial].
left;
intros.
eapply abs_disjoint_sound;
eauto.
Defined.