Require ArithLib.
Require ListAdom.
Require Mconvert.
Require Pun.
Require AbMemSignatureCsharpminor.
Require DebugCshm DebugAbMachineEnv.
Import
Utf8
String
Coqlib
Maps
Integers
Floats
Values
Memory
Globalenvs
AST
Cminor
Csharpminor
Util
AssocList
ToString
Sets
AdomLib
AlarmMon
ListAdom
AbMemSignatureCsharpminor
AbMachineEnv
PExpr
TypesDomain
MemChunkTree
Cells
Pun
NoError
PointsTo
Mconvert
FastArith.
Open Scope string.
Set Implicit Arguments.
Unset Elimination Schemes.
Definition injective_map {
A B} (
m:
A →
option B) :
Prop :=
∀
x x'
a,
m(
x) =
Some a →
m(
x') =
Some a →
x =
x'.
Definition stacks_tmp (
stk stk':
list (
temp_env *
env)) :
Prop :=
map snd stk =
map snd stk'.
Lemma stacks_tmp_in : ∀
stk stk',
stacks_tmp stk stk' →
∀
t e,
In (
t,
e)
stk' →
∃
t',
In (
t',
e)
stk.
Proof.
unfold stacks_tmp.
induction stk as [|(
t,
e)
stk IH];
intros stk'
H.
generalize (
map_nil_inv _ _ (
eq_sym H)).
intros -> ? ? ().
destruct stk'
as [|(
t',
e')
stk'].
apply map_nil_inv in H.
eq_some_inv.
simpl in H.
eq_some_inv.
subst.
intros t0 e [?|
H].
eq_some_inv.
subst.
vauto.
edestruct IH.
eassumption.
eassumption.
vauto.
Qed.
Lemma get_stk_tmp : ∀
stk stk',
stacks_tmp stk stk' →
∀
f,
option_map snd (
get_stk f stk) =
option_map snd (
get_stk f stk').
Proof.
Remark block_of_ablock_tmp ge : ∀
stk stk',
stacks_tmp stk stk' →
∀
ab,
block_of_ablock ge stk ab =
block_of_ablock ge stk'
ab.
Proof.
unfold stacks_tmp.
intros stk stk'
H.
intros [
f x|
b];
simpl;
auto.
generalize (
get_stk_tmp H f).
destruct (
get_stk f stk')
as [ (
t,
e) | ];
simpl;
intros X;
eq_some_inv.
destruct X as ((
t',
e') &
X & <-).
rewrite X.
reflexivity.
destruct (
get_stk _ _);
auto;
simpl in *;
eq_some_inv.
Qed.
Module N :=
Nconvert ACTree.
Module PT :=
N.PT.
Export PT.
Definition types :
Type :=
ACTreeDom.t AbTy.t.
Definition lvarset :
Type :=
PSet.t.
Definition tvarset :
Type :=
PSet.t.
Definition stack :
Type :=
list (
lvarset *
tvarset).
Instance fname_leb :
leb_op fname :=
flat_leb_op Pos.eqb.
Instance fname_join :
join_op fname (
fname+⊤) :=
flat_join_op Pos.eqb.
Instance lvarset_leb :
leb_op lvarset :=
flat_leb_op PSet.beq.
Instance lvarset_join :
join_op lvarset (
lvarset+⊤) :=
flat_join_op PSet.beq.
Instance types_leb :
leb_op types :=
ACTreeDom.leb_tree _ _.
Proof.
abstract (destruct x; auto). Defined.
Instance types_join :
join_op types types :=
ACTreeDom.join_tree _ _.
Proof.
abstract (destruct x; auto). Defined.
Definition types_widen :
types ->
types ->
types :=
join.
Definition sizes :
Type :=
ABTreeDom.t (
Z * (
permission *
bool)).
Definition sizes_gamma ge stk :
gamma_op sizes mem :=
λ
sz m,
∀
b hi perm vol b',
ABTreeDom.get b sz =
Just (
hi, (
perm,
vol)) →
block_of_ablock ge stk b =
Some b' →
Mem.range_perm m b' 0
hi Cur perm
∧
Bool.leb vol (
Senv.block_is_volatile ge b').
Instance BoolEqDec :
EqDec bool :=
eq_dec_of_beq _ Bool.eqb_true_iff.
Definition permission_beq (
x y:
permission) :
bool :=
match x,
y with
|
Freeable,
Freeable
|
Writable,
Writable
|
Readable,
Readable
|
Nonempty,
Nonempty
=>
true
|
_,
_ =>
false
end.
Lemma permission_beq_iff x y :
permission_beq x y =
true ↔
x =
y.
Proof.
split. now destruct x, y; intros; eq_some_inv. now intros <-; destruct x. Qed.
Instance PermissionEqDec :
EqDec permission :=
eq_dec_of_beq _ permission_beq_iff.
Instance PermissionToString :
ToString permission :=
λ
perm,
match perm with
|
Freeable => "
Freeable"
|
Writable => "
Writable"
|
Readable => "
Readable"
|
Nonempty => "
Nonempty"
end%
string.
Instance sizes_leb :
leb_op sizes :=
leb (
leb_op:=
ABTreeDom.leb_tree (
flat_leb_op eq_dec)
_).
Proof.
Instance sizes_join :
join_op sizes sizes :=
ABTreeDom.join_tree (
flat_join_op eq_dec)
_.
Proof.
Definition sizes_widen :
sizes ->
sizes ->
sizes :=
join.
Instance sizes_top_correct ge stk :
top_op_correct sizes mem (
G:=
sizes_gamma ge stk).
Proof.
Instance sizes_leb_correct ge stk :
leb_op_correct sizes mem (
G:=
sizes_gamma ge stk).
Proof.
Instance sizes_join_correct ge stk :
join_op_correct sizes sizes mem
(
GA:=
sizes_gamma ge stk) (
GB:=
sizes_gamma ge stk).
Proof.
intros x y a H b hi perm vol b'
G B'.
unfold join,
sizes_join in G.
rewrite ABTreeDom.get_joinwiden in G.
destruct (
ABTreeDom.get b x)
eqn:
Bx.
discriminate.
destruct (
ABTreeDom.get b y)
eqn:
By.
discriminate.
unfold flat_join_op in G.
simpl in G.
destruct (@
eq_dec _ _);
subst;
simpl in *;
inv G.
destruct H as [
H|
H];
specialize (
H b hi perm vol b');
first [
specialize (
H Bx) |
specialize (
H By) ];
exact (
H B').
Qed.
Lemma ptset_gamma_tmp ge : ∀
stk stk',
stacks_tmp stk stk' →
∀
bs,
ptset_gamma ge stk bs ⊆
ptset_gamma ge stk'
bs.
Proof.
intros stk stk'
H bs v.
destruct v;
try exact id.
intros (
b' &
Hb' &
K).
exists b'.
split.
exact Hb'.
erewrite <-
block_of_ablock_tmp;
eassumption.
Qed.
Lemma points_to_gamma_tmp ge : ∀
stk stk',
stacks_tmp stk stk' →
∀
ptr,
points_to_gamma ge stk ptr ⊆
points_to_gamma ge stk'
ptr.
Proof.
Lemma sizes_gamma_tmp ge stk stk' :
stacks_tmp stk stk' →
∀
sz,
sizes_gamma ge stk sz ⊆
sizes_gamma ge stk'
sz.
Proof.
intros H sz a A b hi b'
B B'
ofs Hofs.
apply (
A b hi b');
auto.
rewrite (
block_of_ablock_tmp ge H).
assumption.
Qed.
Section num.
Context
{
num num_iter:
Type}
`{
numToString:
ToString num}
`{
numIterToString:
ToString num_iter}
(
NumDom:
ab_machine_env (
var:=
cell)
num num_iter).
Lemma gamma_num_ext :
∀ ρ ρ' :
cell →
mach_num,
(∀
x :
cell, ρ
x = ρ'
x) → ∀
m :
num +⊥, γ
m ρ → γ
m ρ'.
Proof.
Definition compat := (λ ρ ρ
n,
N.compat _ (λ
x,
x) ρ ρ
n).
Variable ge :
genv.
Local Instance AblockToString :
ToString ablock :=
AblockToString ge.
Local Instance CellToString :
ToString cell :=
CellToString ge.
Record invariant (
cs:
concrete_state) :
Prop :=
{
localFreeable :
∀
t e,
In (
t,
e) (
fst cs) →
∀
b hi,
In (
b, 0,
hi) (
blocks_of_env e) →
Mem.range_perm (
snd cs)
b 0
hi Cur Freeable
;
localNotGlobal :
∀
t e,
In (
t,
e) (
fst cs) →
∀
x b y b'
z,
Genv.find_symbol ge x =
Some b →
e !
y =
Some (
b',
z) →
b ≠
b'
;
localInj :
injective_map (λ
x_v,
do t_e <-
get_stk (
fst x_v) (
fst cs);
fmap fst ((
snd t_e) ! (
snd x_v)))
;
globalValid:
∀
x b,
Genv.find_symbol ge x =
Some b →
b ∈
Mem.valid_block (
snd cs)
;
localValid:
∀
t e,
In (
t,
e) (
fst cs) →
∀
x b z,
e !
x =
Some (
b,
z) →
b ∈
Mem.valid_block (
snd cs)
;
noIntFragment:
∀
ab b,
block_of_ablock ge (
fst cs)
ab =
Some b →
∀
o,
match ZMap.get o (
Mem.mem_contents (
snd cs)) !!
b with Fragment (
Vint _)
_ _ =>
False |
_ =>
True end
}.
Lemma invariant_tmp : ∀
stk stk',
stacks_tmp stk stk' →
∀
m,
invariant (
stk,
m) →
invariant (
stk',
m).
Proof.
intros stk stk'
H m INV.
split.
-
intros t e H0.
apply (
stacks_tmp_in H)
in H0.
hsplit.
generalize (
INV.(
localFreeable)
t'
e H0).
auto.
-
intros t e H0.
apply (
stacks_tmp_in H)
in H0.
hsplit.
generalize (
INV.(
localNotGlobal)
t'
e H0).
auto.
-
intros (
f,
x) (
f',
x')
b.
generalize (
INV.(@
localInj _) (
f,
x) (
f',
x')
b).
clear -
H.
simpl.
generalize (
get_stk_tmp H f').
generalize (
get_stk_tmp H f).
destruct (
get_stk f stk')
as [ (
t,
e) |];
simpl;
intros X;
eq_some_inv;
hsplit;
subst;
rewrite X.
2:
intros;
eq_some_inv.
destruct (
get_stk f'
stk')
as [ (
t',
e') |];
simpl;
intros X';
eq_some_inv;
hsplit;
subst;
rewrite X'.
2:
intros;
eq_some_inv.
easy.
-
exact INV.(
globalValid).
-
intros t e H0.
apply (
stacks_tmp_in H)
in H0.
hsplit.
generalize (
INV.(
localValid)
_ _ H0).
auto.
-
intros ab b.
rewrite <- (
block_of_ablock_tmp ge H).
apply INV.
Qed.
Lemma invariant_block_of_ablock_inj stk m :
(
stk,
m) ∈
invariant →
∀
ab₁
b₁
ab₂
b₂,
block_of_ablock ge stk ab₁ =
Some b₁ →
block_of_ablock ge stk ab₂ =
Some b₂ →
ab₁ ≠
ab₂ →
b₁ ≠
b₂.
Proof.
intros INV [
f x|
b]
b₁ [
f'
x'|
b']
b₂;
simpl.
-
generalize (
INV.(
localInj) (
f,
x) (
f',
x')).
simpl.
destruct (
get_stk f stk)
as [(
t,
e)|]. 2:
intros;
eq_some_inv.
destruct (
get_stk f'
stk)
as [(
t',
e')|]. 2:
intros;
eq_some_inv.
simpl.
destruct (
e!
x)
as [(
b, ?)|]. 2:
intros;
eq_some_inv.
destruct (
e'!
x')
as [(
b', ?)|]. 2:
intros;
eq_some_inv.
simpl.
intros H H0 H1 H2 ?.
eq_some_inv.
subst.
apply H2.
specialize (
H _ eq_refl eq_refl).
congruence.
-
destruct (
get_stk f stk)
as [(
t,
e)|]
eqn:
A. 2:
intros;
eq_some_inv.
simpl.
destruct (
e!
x)
as [(
b, ?)|]
eqn:
Hx. 2:
intros;
eq_some_inv.
destruct (
Genv.invert_symbol ge b')
as [
q|]
eqn:
Q;
intros;
eq_some_inv.
subst.
apply not_eq_sym.
exact (
INV.(
localNotGlobal)
t e (
get_stk_in A)
_ _ (
Genv.invert_find_symbol _ _ Q)
Hx).
-
destruct (
Genv.invert_symbol ge b)
as [
q|]
eqn:
Q;
intro;
eq_some_inv.
destruct (
get_stk f'
stk)
as [(
t',
e')|]
eqn:
A. 2:
intros;
eq_some_inv.
simpl.
destruct (
e'!
x')
as [(
b', ?)|]
eqn:
Hy;
intros;
eq_some_inv.
subst.
exact (
INV.(
localNotGlobal)
t'
e' (
get_stk_in A)
_ _ (
Genv.invert_find_symbol _ _ Q)
Hy).
-
destruct (
Genv.invert_symbol ge b)
as [
q|]
eqn:
Q;
intro;
eq_some_inv.
destruct (
Genv.invert_symbol ge b')
as [
q'|]
eqn:
Q';
intros;
eq_some_inv.
congruence.
Qed.
Lemma assign_const c i (
nm :
num) :
∀ ρ, ρ ∈ γ(
nm) →
match AbMachineEnv.assign c (
me_const_i _ i)
nm with
|
Bot =>
False
|
NotBot nm' => (
upd ρ
c (
MNint i)) ∈ γ(
nm')
end.
Proof.
Definition tnum :
Type := (
types *
num)%
type.
Definition tnum_iter :
Type := (
types *
num_iter)%
type.
Instance tnum_gamma :
gamma_op tnum (
cell →
val) :=
λ τ
_ν ρ,
let '(τ, ν) := τ
_ν
in
ρ ∈ γ(τ) ∧
∃ ρ',
ρ' ∈ (
compat ρ ∩ γ ν).
Instance tnum_iter_gamma :
gamma_op tnum_iter (
cell →
val) :=
λ τ
_ν ρ,
let '(τ, ν) := τ
_ν
in
ρ ∈ γ(τ) ∧
∃ ρ',
ρ' ∈ (
compat ρ ∩ γ ν).
Instance tnum_leb_correct :
leb_op_correct (
types *
num) (
cell ->
val).
Proof.
Instance tnum_top_correct :
top_op_correct ((
types *
num)+⊥) (
cell ->
val).
Proof.
Instance tnum_join_correct :
join_op_correct (
types *
num) ((
types *
num)+⊥) (
cell ->
val).
Proof.
Section REALIZATION.
Definition is_int (
tp:
types) (
c:
cell) :
bool :=
ACTreeDom.get c tp ⊑
Just VI.
Lemma is_int_intro (
tp:
types) (ρ:
cell →
val) (
TP: ρ ∈ γ
tp) (
c:
cell) (
P:
bool →
Prop):
(
P false) →
(ρ
c ∈ γ
VI →
P true) →
P (
is_int tp c).
Proof.
intros F T.
generalize (
TP c).
unfold is_int.
case (
ACTreeDom.get).
intros _;
exact F.
intros (); (
exact T ||
intros _;
exact F ).
Qed.
Global Opaque is_int.
Definition realize_u8_from_κ (κ:
typed_memory_chunk) (
ab:
ablock) (
base:
Z) (
shift:
Z) (
tp:
types) (
nm:
num) :
tnum+⊥ :=
let uc :
cell :=
cell_from ab (
base +
shift,
exist _ Mint8unsigned I)
in
let c :
cell :=
cell_from ab (
base, κ)
in
do nm' <-
assign uc (
MEbinop Oand (
MEbinop Oshru (
MEvar MNTint c) (
MEconst _ (
MNint (
Int.repr (8 *
shift))))) (
MEconst _ (
MNint (
Int.repr 255))))
nm;
NotBot (
ACTreeDom.set tp uc (
Just VI),
nm').
Definition tnum_mono (
x y:
tnum) :
Prop :=
∀ ρ,
Pun.pun_u8 ρ →
ρ ∈ γ
x →
ρ ∈ γ (
fst y) ∧
∀ ρ',
compat ρ ρ' →
ρ' ∈ γ (
snd x) → ρ' ∈ γ (
snd y).
Lemma tnum_m_stronger :
∀
x y,
tnum_mono x y →
Pun.pun_u8 ∩ γ (
x) ⊆ γ (
y).
Proof.
intros (
tp,
nm) (
tp',
nm')
M ρ (
Hpun &
TP & ρ' &
CPT &
NM).
destruct (
M ρ
Hpun (
conj TP (
ex_intro _ _ (
conj CPT NM))))
as (
TP' &
K).
vauto.
Qed.
Lemma tnum_mono_refl x :
tnum_mono x x.
Proof.
destruct x as (tp, nm).
intros ρ Hpun (TP & NM). auto.
Qed.
Lemma tnum_mono_trans y x z :
tnum_mono x y →
tnum_mono y z →
tnum_mono x z.
Proof.
unfold tnum_mono.
intros Hxy Hyz ?
Hp Hx.
destruct (
Hxy _ Hp Hx)
as (
Hy1 &
Hxy').
assert (ρ ∈ γ
y)
as Hy.
destruct y;
split.
auto.
destruct x,
Hx.
hsplit.
eauto.
destruct (
Hyz _ Hp Hy)
as (
Hz1 &
Hyz').
eauto.
Qed.
Definition tnum_mono' (
x:
tnum) (
y':
tnum+⊥) :
Prop :=
∀ ρ,
Pun.pun_u8 ρ →
ρ ∈ γ
x →
match y'
with
|
Bot =>
False
|
NotBot y =>
ρ ∈ γ (
fst y) ∧
∀ ρ',
compat ρ ρ' →
ρ' ∈ γ (
snd x) → ρ' ∈ γ (
snd y)
end.
Lemma realize_u8_from_κ
_sound (κ:
typed_memory_chunk)
ab base shift (
tp:
types) (
nm:
num) :
(
Archi.big_endian =
false) →
(
align_chunk (
proj1_sig κ) |
base) →
0 <=
shift <
size_chunk (
proj1_sig κ) ∧
size_chunk (
proj1_sig κ) <= 4 →
let c :
cell :=
cell_from ab (
base, κ)
in
is_int tp c →
tnum_mono' (
tp,
nm) (
realize_u8_from_κ κ
ab base shift tp nm).
Proof.
intros LE AL Hshift c Hint ρ
Hpun (
TP & ρ' &
CPT &
NM).
assert (
Int.ltu (
Int.repr (8 *
shift))
Int.iwordsize)
as Hshift'.
{
set (
s :=
List.map Z.of_nat (
seq 0 4)).
apply (
forallb_forall (λ
x,
Int.ltu (
Int.repr (8 *
x))
Int.iwordsize)
s).
unfold s.
exact eq_refl.
unfold s.
apply in_map_iff.
exists (
Z.to_nat shift).
split.
apply Z2Nat.id.
easy.
apply In_seq.
Psatz.lia.
zify.
rewrite Z2Nat.id;
Psatz.lia.
}
unfold realize_u8_from_κ.
fold c.
set (
uc :=
cell_from ab (
base +
shift,
exist _ Mint8unsigned I)).
assert (∃
i, ρ
c =
Vint i)
as Hi.
{
revert Hint.
apply (
is_int_intro TP);
intros Hint.
exact (
false_not_true Hint _).
intros _.
AbTy.gamma_inv.
exact Hint.
}
clear Hint.
destruct Hi as (
i &
Hi).
assert (ρ'
c =
MNint i)
as Hi'.
{
specialize (
CPT c).
rewrite Hi in CPT.
auto. }
set (
me := (
MEbinop Oand
(
MEbinop Oshru (
MEvar MNTint c)
(
MEconst cell (
MNint (
Int.repr (8 *
shift)))))
(
MEconst cell (
MNint (
Int.repr 255))))).
set (
n :=
Int.and (
Int.shru i (
Int.repr (8 *
shift))) (
Int.repr 255)).
assert (
eval_mexpr ρ'
me (
MNint n))
as MEV.
{
econstructor;
vauto.
econstructor;
vauto. }
generalize (@
assign_correct _ _ _ _ NumDom uc me ρ' (
MNint n)
nm NM MEV).
destruct (
assign _ _ _)
as [ |
nm' ]
eqn:
Hassn.
exact id.
intros NM'.
assert (ρ
uc =
Vint n)
as Huc.
{
unfold n.
change (
Int.repr 255)
with (
Int.repr (
two_p 8 - 1)).
erewrite <-
Int.zero_ext_and. 2:
Psatz.lia.
destruct (
Hpun ab κ
base AL)
as (
bytes &
Hnof &
Hbytes &
Hlen &
Huc).
assert (
NPeano.ltb (
Z.to_nat shift) (
Datatypes.length bytes))
as LT.
{
rewrite Hlen.
apply NPeano.ltb_lt.
zify.
unfold size_chunk_nat.
rewrite !
Z2Nat.id;
Psatz.lia. }
specialize (
Huc (
Z.to_nat shift)
LT).
rewrite Z2Nat.id in Huc. 2:
easy.
fold uc in Huc.
rewrite Huc.
fold c in Hbytes.
rewrite Hi in Hbytes.
revert Hlen Hbytes.
clear -
LE Hshift Hnof.
Opaque Z.mul.
unfold decode_val.
destruct bytes as [ |
b₀ [ |
b₁ [ |
b₂ [ |
b₃ [ |
b₄
bytes ] ] ] ] ].
-
discriminate.
-
destruct κ
as [()];
try discriminate;
intros _;
simpl in Hshift;
assert (
shift = 0)
by Psatz.lia;
clear Hshift;
subst shift;
rewrite Int.shru_zero;
destruct b₀;
try discriminate;
intros X;
inv X;
simpl;
f_equal.
rewrite Int.zero_sign_ext_narrow.
reflexivity.
Psatz.lia.
rewrite Int.zero_ext_narrow.
reflexivity.
Psatz.lia.
-
destruct κ
as [()];
try discriminate;
intros _;
simpl in Hshift;
assert (
shift = 0 ∨
shift = 1)
as Hs by Psatz.lia;
clear Hshift;
destruct Hs;
subst shift;
destruct b₀;
try discriminate;
destruct b₁;
try discriminate;
intros X;
inv X;
simpl;
f_equal.
rewrite Int.shru_zero,
Int.zero_sign_ext_narrow. 2:
Psatz.lia.
rewrite decode_int_1, (
decode_int_LE_2 LE).
rewrite Z.mul_comm.
apply z8.
apply (
decode_shift_1s LE).
rewrite Int.shru_zero,
Int.zero_ext_narrow. 2:
Psatz.lia.
rewrite decode_int_1, (
decode_int_LE_2 LE).
rewrite Z.mul_comm.
apply z8.
rewrite <- (
decode_shift_1u LE).
reflexivity.
-
destruct κ
as [()];
discriminate.
-
assert (
shift = 0 ∨
shift = 1 ∨
shift = 2 ∨
shift = 3)
as Hs by Psatz.lia;
clear Hshift.
destruct κ
as [()];
try discriminate;
intros _;
destruct b₀;
try discriminate;
destruct b₁;
try discriminate;
destruct b₂;
try discriminate;
destruct b₃;
try discriminate;
simpl;
try (
rewrite !
andb_false_r;
discriminate);
intros X;
inversion X;
clear X;
subst;
simpl;
f_equal.
repeat (
destruct Hs as [
Hs |
Hs ]);
subst shift.
simpl.
f_equal.
rewrite Int.shru_zero.
unfold decode_int,
rev_if_be.
rewrite LE.
simpl.
rewrite Z.add_0_r.
apply z8.
simpl.
f_equal.
apply NS1,
LE.
simpl.
f_equal.
apply NS2,
LE.
simpl.
f_equal.
apply NS3,
LE.
exfalso.
revert H0 Hnof.
clear.
bif.
destruct v;
intros X;
inv X.
exact false_eq_true_False.
exfalso.
revert H0 Hnof.
clear.
bif.
destruct v;
intros X;
inv X.
exact false_eq_true_False.
-
destruct κ
as [()];
try discriminate;
exfalso;
simpl in Hshift;
clear -
Hshift;
Psatz.lia.
}
split.
-
intros c'.
unfold fst,
upd.
rewrite ACTreeDom.gsspec.
case (
ACTree.elt_eq).
intros ->.
rewrite Huc.
exact I.
intros _.
apply (
TP c').
-
clear ρ'
CPT NM Hi'
MEV NM'.
unfold snd.
intros ρ'
CPT NM.
assert (ρ'
c =
MNint i)
as Hi'.
{
specialize (
CPT c).
rewrite Hi in CPT.
auto. }
assert (
eval_mexpr ρ'
me (
MNint n))
as MEV.
{
econstructor;
vauto.
econstructor;
vauto. }
generalize (@
assign_correct _ _ _ _ NumDom uc me ρ' (
MNint n)
nm NM MEV).
rewrite Hassn.
assert (ρ' +[
uc =>
MNint n ] = ρ')
as EXT.
{
apply Axioms.extensionality.
intros c'.
unfold upd.
case eq_dec.
intros ->.
generalize (
CPT uc).
rewrite Huc.
exact id.
reflexivity. }
setoid_rewrite EXT.
exact id.
Qed.
Definition cell_mem_rect {
T:
Type} :
T →
(
ablock →
Z →
typed_memory_chunk →
T) →
cell →
T :=
λ
b r c,
match c with
|
AClocal f x ofs κ =>
r (
ABlocal f x)
ofs κ
|
ACglobal g ofs κ =>
r (
ABglobal g)
ofs κ
|
ACtemp _ _ =>
b
end.
Definition cell_mem_rect_intro {
T:
Type} (
P:
cell →
T →
Prop) :
∀
b r,
(∀
f r,
P (
ACtemp f r)
b) →
(∀
ab ofs κ,
P (
cell_from ab (
ofs, κ)) (
r ab ofs κ)) →
∀
c,
P c (
cell_mem_rect b r c) :=
λ
b r B R c,
match c with
|
AClocal f x ofs κ =>
R (
ABlocal f x)
ofs κ
|
ACglobal g ofs κ =>
R (
ABglobal g)
ofs κ
|
ACtemp f r =>
B f r
end.
Global Opaque cell_mem_rect.
Definition optimistic_realization_one (
c:
cell) (
tn:
tnum) :
tnum+⊥ :=
let '(
tp,
nm) :=
tn in
match ACTreeDom.get c tp with
|
Just _ =>
NotBot tn
|
All =>
cell_mem_rect
(
NotBot tn)
(λ
ab ofs κ,
match κ
with
|
exist Mint8unsigned _ =>
let (
base,
shift) :=
Z.div_eucl ofs 4
in
let base := 4 *
base in
let c32 :=
cell_from ab (
base,
exist _ Mint32 I)
in
if is_int tp c32
then realize_u8_from_κ (
exist _ Mint32 I)
ab base shift tp nm
else
let (
base,
shift) :=
Z.div_eucl ofs 2
in
let base := 2 *
base in
let c16u :=
cell_from ab (
base,
exist _ Mint16unsigned I)
in
if is_int tp c16u
then realize_u8_from_κ (
exist _ Mint16unsigned I)
ab base shift tp nm
else
let c16s :=
cell_from ab (
base,
exist _ Mint16signed I)
in
if is_int tp c16s
then realize_u8_from_κ (
exist _ Mint16signed I)
ab base shift tp nm
else
let c8s :=
cell_from ab (
ofs,
exist _ Mint8signed I)
in
if is_int tp c8s
then realize_u8_from_κ (
exist _ Mint8signed I)
ab ofs 0
tp nm
else NotBot tn
|
exist Mint32 _ =>
if ArithLib.divide ofs F4 then
let c :=
cell_from ab (
ofs, κ)
in
let c8 shift :=
cell_from ab (
ofs +
shift,
exist _ Mint8unsigned I)
in
if is_int tp (
c8 0)
then
if is_int tp (
c8 1)
then
if is_int tp (
c8 2)
then
if is_int tp (
c8 3)
then
do nm' <-
assign c
(
MEbinop Oadd (
MEvar MNTint (
c8 0))
(
MEbinop Oadd (
MEbinop Oshl (
MEvar MNTint (
c8 1)) (
MEconst _ (
MNint (
Int.repr 8))))
(
MEbinop Oadd (
MEbinop Oshl (
MEvar MNTint (
c8 2)) (
MEconst _ (
MNint (
Int.repr 16))))
(
MEbinop Oshl (
MEvar MNTint (
c8 3)) (
MEconst _ (
MNint (
Int.repr 24)))))))
nm;
NotBot (
ACTreeDom.set tp c (
Just VI),
nm')
else NotBot tn
else NotBot tn
else NotBot tn
else NotBot tn
else NotBot tn
|
_ =>
NotBot tn
end)
c
end.
Lemma optimistic_realization_one_sound (
c:
cell) (
tn:
tnum) :
tnum_mono'
tn (
optimistic_realization_one c tn).
Proof.
Global Opaque optimistic_realization_one.
Definition optimistic_realization (
cells:
CellSet.t) (
tn:
tnum) :
tnum+⊥ :=
CellSet.fold (λ
c tn,
bind tn (
optimistic_realization_one c))
cells (
NotBot tn).
Lemma optimistic_realization_sound cells tn:
tnum_mono'
tn (
optimistic_realization cells tn).
Proof.
destruct tn as (
tp,
nm).
intros ρ
Hpun (
TP &
NM).
unfold optimistic_realization.
apply CSO.foldspec;
auto.
clear -
Hpun NM.
intros cells cells'
tn tn'
c Hc Hrem TN.
destruct tn'
as [ |
tn' ].
exact TN.
destruct TN as [
TP'
NM'].
simpl.
generalize (
optimistic_realization_one_sound c tn'
Hpun).
destruct (
optimistic_realization_one _ _)
as [ | (
tp',
nm') ].
intros X;
apply X.
destruct tn'
as (
tp',
nm').
split.
exact TP'.
hsplit.
eauto.
intros [
TP''
NM'' ].
destruct tn'.
split.
auto.
hsplit;
eauto.
split.
exact TP''.
intros ρ'
CPT NMx.
simpl.
apply NM'';
auto.
Qed.
Global Opaque optimistic_realization.
End REALIZATION.
Variable max_concretize :
N.
Section CONVERT.
Current function.
Variable μ :
fname.
Set of local variables.
Variable ε :
lvarset.
Definition is_local (
v:
ident) :
bool :=
PSet.mem v ε.
Definition addr_of (
v:
ident) :
BlockSet.t :=
if is_local v
then BSO.singleton (
ABlocal μ
v)
else match Genv.find_symbol ge v with
|
Some b =>
BSO.singleton (
ABglobal b)
|
None =>
BlockSet.empty
end.
Variable sz :
sizes.
Variable pt :
points_to.
Definition me_of_pe (
nm:
num) (
pe:
pexpr cell) :
am_map_t (
mexpr cell) :=
match N.nconvert ge μ
_ _ (λ
x,
x)
_ _ NumDom sz nm pt pe with
|
inl me =>
if AbMachineEnv.noerror me nm
then Result me
else Error (
Some me)
("
me_of_pe(" ++
to_string pe ++ "):
error")
|
inr (
res,
msg) =>
Error res
("
me_of_pe(" ++
to_string pe ++ "):
conversion failed: " ++
msg)
end.
Definition check_align (
nm:
num) (
sz:
Z) (
me:
mexpr cell) :
bool :=
match is_one sz with
|
false =>
is_bot (
AbMachineEnv.assume
(
MEbinop (
Ocmp Cne)
(
MEbinop Omodu me (
me_const_i _ (
Int.repr sz)))
(
me_const_i _ Int.zero))
true nm)
|
e =>
e
end.
Definition deref_pexpr (
nm:
num) κ (
lpe:
list (
pexpr cell)) :
alarm_mon (
CellSet.t+⊤) :=
let al :=
align_chunk (
proj1_sig κ)
in
am_fold
(λ
acc pe,
do offs <-
match pexpr_get_ty pe with
|
VP =>
match me_of_pe nm pe with
|
Result me =>
do _ <-
am_assert (
check_align nm al me)
("
bad align (" ++
to_string (
proj1_sig κ) ++ "): " ++
to_string me);
ret (
concretize_int max_concretize me nm)
|
Errorc me e =>
do _ <-
alarm_am (
e tt);
ret match me with
|
Some me =>
concretize_int max_concretize me nm
|
None =>
NotBot All
end
end
|
ty =>
do _ <-
alarm_am ("
deref_pexpr:
maybe not a pointer (" ++
to_string ty ++ ")");
ret (
NotBot All)
end;
ret match acc with
|
All =>
All
|
Just acc =>
match pt_eval_pexpr ge μ
pt pe with
|
All =>
All
|
Just ptr =>
fmap (
CellSet.union acc) (
set_product ptr κ
offs)
end
end)
lpe
(
Just CellSet.empty).
Lemma deref_pexpr_inv nm κ
lpe :
match am_get (
deref_pexpr nm κ
lpe)
with
|
Some cells =>
let al :=
align_chunk (
proj1_sig κ)
in
∀
pe,
In pe lpe →
pexpr_get_ty pe =
VP ∧
∃
me,
me_of_pe nm pe =
Result me ∧
check_align nm al me =
true ∧
let ofs :=
concretize_int max_concretize me nm in
match cells with All =>
True |
Just cells =>
ofs ≠
NotBot All ∧
∃
ptr,
pt_eval_pexpr ge μ
pt pe =
Just ptr ∧
∀
b i,
BlockSet.mem b ptr →
i ∈ γ(
ofs) →
CellSet.mem (
cell_from b (
Int.unsigned i, κ))
cells
end
|
None =>
True
end.
Proof.
unfold deref_pexpr.
set (
al :=
align_chunk (
proj1_sig κ)).
match goal with |-
appcontext[
am_fold ?
f ] =>
set (
F :=
f )
end.
induction lpe as [|
pe lpe IH]
using rev_ind.
intros _ ();
fail.
unfold ACTree.elt in IH.
rewrite am_fold_app.
apply am_bind_case.
intros;
exact I.
intros acc REC.
rewrite REC in IH.
simpl in IH.
clear REC.
subst F.
unfold am_fold.
simpl.
destruct (
pexpr_get_ty pe)
eqn:
TY;
try exact I.
destruct (
me_of_pe nm pe)
as [
me|]
eqn:
ME. 2:
exact I.
destruct (
check_align nm al me)
eqn:
ALIGN. 2:
exact I.
intros pe'
IN.
rewrite in_app in IN.
destruct IN as [
IN| [ <- | () ]].
-
specialize (
IH _ IN).
destruct IH as (
Ty &
me' &
IH);
hsplit.
split.
assumption.
exists me'.
split.
assumption.
split.
assumption.
destruct acc as [|
acc].
exact I.
hsplit.
destruct (
pt_eval_pexpr _ _ _ pe)
as [ |
ptr' ].
exact I.
destruct (
set_product)
as [|
cells].
exact I.
split.
assumption.
exists ptr.
split.
assumption.
intros;
rewrite CellSet.mem_union;
bleft;
auto.
-
split.
assumption.
exists me.
split.
assumption.
split.
assumption.
destruct acc as [|
acc].
exact I.
destruct (
pt_eval_pexpr _ _ _ pe)
as [ |
ptr' ].
exact I.
destruct (
concretize_int _ me nm)
as [|[|
offs]]
eqn:
Hoffs.
+
split.
discriminate.
exists ptr'.
split.
reflexivity.
intros b i H ().
+
exact I.
+
split.
discriminate.
exists ptr'.
split.
reflexivity.
intros b i H H0.
generalize (
set_product_correct _ κ (@
NotBot _ (
Just offs))
_ _ H H0).
intros.
rewrite CellSet.mem_union.
bright.
auto.
Qed.
Definition constant_of_constant (
c:
Csharpminor.constant) :
constant :=
match c with
|
Csharpminor.Ointconst i =>
Ointconst i
|
Csharpminor.Olongconst i =>
Olongconst i
|
Csharpminor.Ofloatconst f =>
Ofloatconst f
|
Csharpminor.Osingleconst f =>
Osingleconst f
end.
Definition convert_err (
e:
expr)
msg :=
("
convert(" ++
to_string e ++ "): " ++
msg ++
new_line ++
"
Function: " ++
to_string μ ++
new_line ++
"
Locals: " ++
to_string ε ++
new_line ).
Opaque convert_err.
Definition convert_t A :=
tnum ->
alarm_mon (
tnum *
A).
Local Instance convert_monad :
monad convert_t :=
{
ret A := λ
a tn,
ret (
tn,
a);
bind A B := λ
m f tn,
do (
tn',
a) <-
m tn;
f a tn'
}.
Let get_tnum :
convert_t tnum := λ
tn,
ret (
tn,
tn).
Let lift {
A} (
m:
alarm_mon A) :
convert_t A :=
λ
tn,
fmap (λ
x, (
tn,
x))
m.
Local Notation "'
alarm'
e" := ((λ
tn, (((
tn,
tt), (λ
_,
e) ::
nil))):(
convert_t _)) (
at level 100).
Let convert_var (
e:
expr) (
c:
cell) :
convert_t (
list (
pexpr cell)) :=
λ
tn,
let '(
tp,
nm) :=
tn in
match ACTreeDom.get c tp with
|
Just ty =>
ret (
PEvar c ty ::
nil)
tn
|
All => (
do _ <-
alarm (
convert_err e ("
bad temp in " ++
to_string μ));
ret nil)
tn
end.
Let realize (
cells:
CellSet.t) :
convert_t (
list cell) :=
λ
tn,
match optimistic_realization cells tn with
|
Bot =>
ret nil tn
|
NotBot tn' =>
ret (
CellSet.elements cells)
tn'
end.
Fixpoint convert (
e:
expr) :
convert_t (
list (
pexpr cell)) :=
let err :=
convert_err e in
match e with
|
Evar v =>
convert_var e (
ACtemp μ
v)
|
Eaddrof i =>
if is_local i
then ret (
PElocal _ i ::
nil)
else match Genv.find_symbol ge i with
|
Some _ =>
ret (
PEconst _ (
Some (
Oaddrsymbol i Int.zero))
VP ::
nil)
|
None =>
do _ <-
alarm (
err "
bad global variable");
ret nil
end
|
Econst cst =>
let cst :=
constant_of_constant cst in
ret (
PEconst _ (
Some cst) (
AbTy.eval_constant cst) ::
nil)
|
Eunop op e1 =>
do e1' <-
convert e1;
ret (
rev_map (
fun e =>
PEunop op e (
AbTy.eval_unop op (
pexpr_get_ty e)))
e1')
|
Ebinop op e1 e2 =>
do e1' <-
convert e1;
do e2' <-
convert e2;
ret (
map2 (λ
e1 e2,
PEbinop op e1 e2
(
AbTy.eval_binop op (
pexpr_get_ty e1) (
pexpr_get_ty e2))
)
e1'
e2')
|
Eload κ
e1 =>
do e1' <-
convert e1;
do κ <-
match κ
return convert_t (
option typed_memory_chunk)
with
|
Many32 |
Many64 =>
do _ <-
alarm (
err "
Many32 or Many64");
ret None
| κ =>
ret (
Some (
exist _ κ
I:
typed_memory_chunk))
end;
do (
tp,
nm) <-
get_tnum;
do cells <-
match κ
with Some κ =>
lift (
deref_pexpr nm κ
e1') |
None =>
ret All end;
match cells with
|
All =>
do _ <-
alarm (
err "
too many cells");
ret nil
|
Just cells =>
do cells <-
realize cells;
λ
tn,
let '(
tp,
nm) :=
tn in
lift (
am_map' (λ
c,
match ACTreeDom.get c tp with
|
All =>
Error None (
err ("
bad cell: " ++
to_string c))
|
Just ty =>
Result (
PEvar c ty)
end)
cells
)
tn
end
end.
Definition me_of_pe_list nm :=
am_map' (
me_of_pe nm).
Definition nconvert (
e:
expr) :
convert_t (
list (
mexpr cell)) :=
do lpe <-
convert e;
λ
tn,
lift (
me_of_pe_list (
snd tn)
lpe)
tn.
Definition deref_expr_err (
nm:
num) (
e:
expr) (κ:
typed_memory_chunk) (
lpe:
list (
pexpr cell)) :=
("
deref_expr(" ++
to_string e ++ ", " ++
to_string (
proj1_sig κ) ++ ") " ++
to_string lpe )%
string.
Opaque deref_expr_err.
Definition deref_expr κ (
e:
expr) :
convert_t (
list cell) :=
do lpe <-
convert e;
λ
tn,
let '(
tp,
nm) :=
tn in
lift (
do cells <-
deref_pexpr nm κ
lpe;
match cells with
|
All =>
do _ <-
alarm_am (
deref_expr_err nm e κ
lpe);
ret nil
|
Just cell_set =>
ret (
CellSet.elements cell_set)
end
)
tn.
Section CONVERT_CORRECT.
Context (
e:
env) (
tmp:
temp_env) (
m:
mem).
Context (
stk:
list (
temp_env *
env)).
Context (
Hstk: μ =
plength stk).
Let ρ :=
mem_as_fun ge ((
tmp,
e) ::
stk,
m).
Local Instance pt_gamma :
gamma_op points_to _ :=
points_to_gamma ge ((
tmp,
e) ::
stk).
Hypothesis E: ∀
i,
is_local i =
true ↔
e !
i ≠
None.
Hypothesis INV :
invariant ((
tmp,
e) ::
stk,
m).
Hypothesis SZ:
m ∈
sizes_gamma ge ((
tmp,
e) ::
stk)
sz.
Hypothesis PT: ρ ∈ γ(
pt).
Lemma Tmp: ∀
i v,
tmp !
i =
Some v → ρ (
ACtemp μ
i) =
v.
Proof.
Hint Resolve Tmp.
Lemma me_of_pe_correct (
nm:
num) (ρ
n:
cell →
mach_num) (
NM: ρ
n ∈ γ(
nm))
pe :
match me_of_pe nm pe with
|
Result me =>
N.nconvert ge μ
_ _ (λ
x,
x)
_ _ NumDom sz nm pt pe =
inl me ∧ ¬
error_mexpr ρ
n me
|
Errorc _ _ =>
True
end.
Proof.
Ltac with_me_of_pe q :=
repeat match goal with
|
H :
appcontext[
me_of_pe ?
nm ?
pe ] |-
_ =>
generalize (
me_of_pe_correct pe);
destruct (
me_of_pe nm pe);
q
end.
Lemma me_of_pe_list_noerror (
nm:
num) (ρ
n:
cell →
mach_num) (
NM: ρ
n ∈ γ(
nm))
lpe :
match am_get (
me_of_pe_list nm lpe)
with
|
Some lme => (∀
me,
In me lme → ¬
error_mexpr ρ
n me)
∧ (∀
pe,
In pe lpe → ∃
me,
In me lme ∧
N.nconvert ge μ
_ _ (λ
x,
x)
_ _ NumDom sz nm pt pe =
inl me)
|
None =>
True
end.
Proof.
unfold me_of_pe_list.
with_am_map'.
intros (
H &
H').
split.
intros me ME.
destruct (
H me ME)
as (
pe &
PE &
K).
generalize (
me_of_pe_correct nm ρ
n NM pe).
rewrite PE.
intuition.
intros pe PE.
destruct (
H'
pe PE)
as (
me &
ME &
K).
generalize (
me_of_pe_correct nm ρ
n NM pe).
rewrite ME.
intros [?
_].
vauto.
Qed.
Lemma pexpr_get_ty_ok (
pe:
pexpr cell)
v :
eval_pexpr ge m ρ
e pe v →
v ≠
Vundef →
v ∈ γ(
pexpr_get_ty pe).
Proof.
Lemma check_align_correct (
nm:
num) (ρ
n:
cell →
mach_num) (
NM: ρ
n ∈ γ(
nm))
al me :
al = 1 ∨
al = 2 ∨
al = 4 ∨
al = 8 →
check_align nm al me =
true →
∀
n,
eval_mexpr ρ
n me (
MNint n) →
Int.unsigned n =
al *
Int.unsigned (
Int.divu n (
Int.repr al)).
Proof.
Ltac subs :=
repeat match goal with H : ?
a = ?
b |-
_ =>
subst a ||
subst b end.
Let Hpun : ρ ∈
pun_u8 :=
mem_as_fun_pun_u8 _ _ INV.(
noIntFragment).
Lemma convert_wf (
q:
expr):
∀ (
tn:
tnum) (
TN: ρ ∈ γ
tn),
match am_get (
convert q tn)
with
|
Some (
tn',
lp) =>
tnum_mono tn tn'
∧
∀
pe,
In pe lp →
N.nconvert_def_pre ge e ρ
pe
|
None =>
True
end.
Proof.
induction q;
intros (
tp,
nm)
TN.
-
simpl.
set (
c :=
ACtemp μ
i).
generalize (
proj1 TN c).
destruct (
ACTreeDom.get c tp)
as [
ty|].
exact id.
intros TY.
simpl.
split.
apply tnum_mono_refl.
intros pe [ <- | () ].
simpl.
intros X.
rewrite X in TY.
AbTy.gamma_inv.
auto.
-
simpl.
generalize (
E i).
destruct is_local.
intros (
A &
_).
split.
apply tnum_mono_refl.
intros pe [ <- | () ].
simpl.
unfold env_as_fun.
destruct (
e !
i)
as [()|].
intro;
eq_some_inv.
elim (
A eq_refl eq_refl).
intros _.
destruct (
Genv.find_symbol ge i)
eqn:
FS.
split.
apply tnum_mono_refl.
intros pe [ <- | () ].
simpl.
rewrite FS.
intro;
eq_some_inv.
exact I.
-
split.
apply tnum_mono_refl.
intros pe [ <- | () ].
destruct c;
exact I.
-
simpl.
unfold bind.
simpl.
apply am_bind_case.
intros;
exact I.
intros ((
tp',
nm'),
lp)
LP.
specialize (
IHq (
tp,
nm)
TN).
rewrite LP in IHq.
destruct IHq as (
MONO &
IHq ).
split.
easy.
intros pe PE.
rewrite rev_map_correct, <-
in_rev,
in_map_iff in PE.
destruct PE as (
pe' & <- &
PE).
simpl.
apply IHq;
auto.
-
simpl.
unfold bind.
simpl.
apply am_bind_case.
intros;
exact I.
intros ((
tp1,
nm1),
lp1)
LP1.
specialize (
IHq1 (
tp,
nm)
TN).
rewrite LP1 in IHq1.
destruct IHq1 as (
MONO1 &
IHq1 ).
apply am_bind_case.
intros;
exact I.
intros ((
tp2,
nm2),
lp2)
LP2.
specialize (
IHq2 (
tp1,
nm1) (
tnum_m_stronger MONO1 (
conj (
mem_as_fun_pun_u8 _ _ INV.(
noIntFragment))
TN))).
rewrite LP2 in IHq2.
destruct IHq2 as (
MONO2 &
IHq2 ).
split.
eauto using tnum_mono_trans.
destruct b;
try (
intros pe PE;
rewrite map2_correct in PE;
unfold map2_spec in PE;
rewrite <-
in_rev,
in_flat_map in PE;
destruct PE as (
pe1 &
PE1 &
PE);
rewrite in_map_iff in PE;
destruct PE as (
pe2 & <- &
PE);
vauto).
-
rename m0 into κ.
simpl.
unfold bind.
simpl.
apply am_bind_case.
intros;
exact I.
intros ((
tp1,
nm1),
lp)
LP.
apply am_bind_case.
intros;
exact I.
intros ((
tp2,
nm2), κ')
K.
assert (
Hκ:
tp2 =
tp1 ∧
nm2 =
nm1 ∧ ∃
Hκ, κ' =
Some (
exist _ κ
Hκ))
by (
destruct κ;
eq_some_inv;
subs;
eauto).
destruct Hκ
as (-> & -> & [
Hκ ->]).
clear K.
apply am_bind_case.
intros;
exact I.
intros (
nm3, [|
cells]).
intros;
exact I.
unfold lift,
fmap.
apply am_bind_case.
discriminate.
intros x Hcells Q.
simpl in Q.
eq_some_inv;
subs.
generalize (
deref_pexpr_inv nm1 (
exist _ κ
Hκ)
lp).
rewrite Hcells.
intros K.
specialize (
IHq (
tp,
nm)
TN).
rewrite LP in IHq.
destruct IHq as (
MONO1 &
IHq ).
assert (ρ ∈ γ (
tp1,
nm1))
as H1.
apply (
tnum_m_stronger MONO1);
auto.
unfold realize.
generalize (@
optimistic_realization_sound cells (
tp1,
nm1)).
destruct (
optimistic_realization _ _)
as [ | (
tp',
nm') ];
simpl;
intros Hreal;
elim (
Hreal ρ
Hpun H1).
intros TP'
NM'.
with_am_map'.
simpl.
intros (
X &
Y).
split.
eauto using tnum_mono_trans.
clear Hreal.
intros pe PE.
destruct (
X pe PE)
as (
c &
C &
C').
simpl in *.
destruct (
ACTreeDom.get c _)
as [|
ty]
eqn:
TY;
inversion C.
unfold N.nconvert_def_pre.
generalize (
TP'
c).
rewrite TY.
fold ρ.
intros A L.
rewrite L in A.
AbTy.gamma_inv.
auto.
Qed.
Lemma convert_free_def (
q:
expr) :
∀ (
tn:
tnum) (
TN: ρ ∈ γ
tn),
match am_get (
convert q tn)
with
|
Some (
tn',
lp) =>
∀
pe,
In pe lp ->
∀
x,
pe_free_var pe x -> ρ
x ≠
Vundef
|
None =>
True
end.
Proof.
induction q;
intros tn TN.
-
destruct tn as (
tp,
nm).
destruct TN as (
TP,
NM).
simpl.
set (
c :=
ACtemp μ
i).
generalize (
TP c).
destruct (
ACTreeDom.get c tp).
exact id.
intros H pe [<-|[]]
x ->
EQ.
rewrite EQ in H.
AbTy.gamma_inv.
exact H.
-
simpl.
destruct is_local.
now intros pe [<-|[]]
x [].
destruct (
Genv.find_symbol ge i).
now intros pe [<-|[]]
x [].
exact I.
-
now intros pe [<-|[]]
x [].
-
simpl.
unfold bind.
simpl.
apply am_bind_case.
intros;
exact I.
intros ((
tp1,
nm1),
lp)
LP pe PE.
rewrite rev_map_correct, <-
in_rev,
in_map_iff in PE.
destruct PE as (
pe' & <- &
PE).
specialize (
IHq _ TN).
rewrite LP in IHq.
simpl.
apply IHq;
auto.
-
simpl.
unfold bind.
simpl.
apply am_bind_case.
intros;
exact I.
intros ((
tp1,
nm1),
lp1)
LP1.
apply am_bind_case.
intros;
exact I.
intros ((
tp2,
nm2),
lp2)
LP2.
specialize (
IHq1 _ TN).
rewrite LP1 in IHq1.
generalize (
convert_wf q1 _ TN).
rewrite LP1.
intros [
MONO1 _].
specialize (
IHq2 _ (
tnum_m_stronger MONO1 (
conj Hpun TN))).
generalize (
convert_wf q2 _ (
tnum_m_stronger MONO1 (
conj Hpun TN))).
rewrite LP2.
intros [
MONO2 _].
rewrite LP2 in IHq2.
simpl in IHq1,
IHq2.
destruct b;
try (
intros pe PE;
rewrite map2_correct in PE;
unfold map2_spec in PE;
rewrite <-
in_rev,
in_flat_map in PE;
destruct PE as (
pe1 &
PE1 &
PE);
rewrite in_map_iff in PE;
destruct PE as (
pe2 & <- &
PE);
intros x [
Hx|
Hx];
eauto).
-
rename m0 into κ.
simpl.
unfold bind.
simpl.
apply am_bind_case.
intros;
exact I.
intros ((
tp1,
nm1),
lp)
LP.
generalize (
convert_wf q _ TN).
rewrite LP.
intros [
MONO1 _].
apply am_bind_case.
intros;
exact I.
intros ((
tp2,
nm2), κ')
K.
assert (
Hκ:
tp2 =
tp1 ∧
nm2 =
nm1 ∧ ∃
Hκ, κ' =
Some (
exist _ κ
Hκ))
by (
destruct κ;
eq_some_inv;
eauto).
destruct Hκ
as (-> & -> & [
Hκ ->]).
clear K.
apply am_bind_case.
intros;
exact I.
intros (
nm3, [|
cells]).
intros;
exact I.
unfold lift,
fmap.
apply am_bind_case.
discriminate.
intros x Hcells Q.
simpl in Q.
eq_some_inv;
subs.
generalize (
deref_pexpr_inv nm1 (
exist _ κ
Hκ)
lp).
rewrite Hcells.
clear Hcells.
intros K.
assert (ρ ∈ γ (
tp1,
nm1))
as H1.
apply (
tnum_m_stronger MONO1);
auto.
unfold realize.
generalize (@
optimistic_realization_sound cells (
tp1,
nm1)).
destruct (
optimistic_realization _ _)
as [ | (
tp',
nm') ];
simpl;
intros Hreal;
elim (
Hreal ρ
Hpun H1).
intros TP'
NM'.
with_am_map'.
simpl in *.
intros (
X &
Y)
pe PE.
destruct (
X pe PE)
as (
c &
C &
C').
destruct (
ACTreeDom.get c _)
as [|
ty]
eqn:
TY;
inversion C.
intros ? <-
Hdef.
generalize (
TP'
c).
fold ρ.
rewrite TY,
Hdef.
intro;
AbTy.gamma_inv.
easy.
Qed.
Remark align_chunk_4_cases (κ:
memory_chunk) :
align_chunk κ = 1 ∨
align_chunk κ = 2 ∨
align_chunk κ = 4 ∨
align_chunk κ = 8.
Proof.
destruct κ; vauto. Qed.
Lemma convert_correct (
q:
expr) :
∀ (
tn:
tnum) (
TN: ρ ∈ γ
tn),
match am_get (
convert q tn)
with
|
Some (
tn',
lp) =>
∀
v,
eval_expr ge e tmp m q v →
∃
a,
In a lp ∧
eval_pexpr ge m ρ
e a v
|
None =>
True
end.
Proof.
Ltac ok :=
let K :=
fresh in
intros ?
K;
eexists;
split; [
left;
reflexivity|
eval_expr_inv;
try econstructor;
eauto].
induction q;
intros (
tp,
nm)
TN;
simpl;
try (
split;[
ok|
auto]).
-
set (
c :=
ACtemp μ
i).
destruct TN as (
TP &
NM).
specialize (
TP c).
destruct (
ACTreeDom.get c tp).
exact I.
subst c.
intros ?
K.
eval_expr_inv.
rewrite (
Tmp _ K)
in TP.
vauto2.
-
bif'.
ok.
unfold env_as_fun.
apply E in Heqb.
subs.
constructor.
inversion H;
clear H;
subs.
rewrite H0.
auto.
congruence.
bif.
simpl.
ok.
inversion H;
clear H;
subs.
exfalso.
generalize (
proj2 (
E i)).
intuition congruence.
simpl.
rewrite H1.
reflexivity.
subs.
simpl.
auto.
exact I.
-
intros v V.
eval_expr_inv.
eexists.
split.
left;
reflexivity.
destruct c;
simpl in *;
eq_some_inv;
subs;
econstructor;
simpl;
eauto.
-
unfold bind.
simpl.
apply am_bind_case.
intros;
exact I.
intros ((
tp',
nm'),
lp)
Hlp.
specialize (
IHq _ TN).
rewrite Hlp in IHq.
intros v K.
eval_expr_inv.
destruct (
IHq _ H)
as (
a &
A &
B).
clear IHq.
exists (
PEunop u a (
AbTy.eval_unop u (
pexpr_get_ty a))).
split.
rewrite rev_map_correct, <-
in_rev.
exact (
in_map _ _ _ A).
econstructor;
eauto.
assert (
v =
Vundef \/
v ≠
Vundef)
as D by (
destruct v;
auto;
right;
discriminate).
destruct D.
auto.
right.
eapply AbTy.eval_unop_correct;
eauto.
apply pexpr_get_ty_ok.
auto.
intros ->.
destruct u;
simpl in *;
congruence.
-
unfold bind.
simpl.
apply am_bind_case.
intros;
exact I.
intros ((
tp1,
nm1),
lp1)
Hq1.
apply am_bind_case.
intros;
exact I.
intros ((
tp2,
nm2),
lp2)
Hq2.
specialize (
IHq1 _ TN).
generalize (
convert_wf q1 (
tp,
nm)
TN).
rewrite Hq1.
intros [
MONO1 _].
rewrite Hq1 in IHq1.
specialize (
IHq2 _ (
tnum_m_stronger MONO1 (
conj Hpun TN))).
rewrite Hq2 in IHq2.
simpl in *.
assert (∀
v (
P:
Prop), (
v ≠
Vundef →
P) → (
v =
Vundef ∨
P))
as X by (
clear;
intuition tauto).
destruct b;
try (
intros v V;
eval_expr_inv;
destruct (
IHq1 _ H)
as (
a1 &
A1 &
A1');
destruct (
IHq2 _ H0)
as (
a2 &
A2 &
A2');
try (
eexists;
split; [
eapply in_map2;
eassumption |
econstructor;
eauto];
apply X;
intros Hv;
eapply AbTy.eval_binop_correct;
eauto;
apply pexpr_get_ty_ok;
eauto;
intros ->;
simpl in *;
eq_some_inv;
try (
destruct v1);
try (
unfold Val.cmp,
Val.cmpu,
Val.cmpf,
Val.cmpfs,
Val.cmpl,
Val.cmplu in *;
destruct c);
simpl in *;
eq_some_inv;
hsplit;
congruence)).
-
unfold bind.
simpl.
rename m0 into κ.
apply am_bind_case.
intros;
exact I.
intros ((
tp1,
nm1),
lp)
Hlp.
specialize (
IHq _ TN).
rewrite Hlp in IHq.
generalize (
convert_wf q (
tp,
nm)
TN).
rewrite Hlp.
intros [
MONO1 _].
apply am_bind_case.
intros;
exact I.
intros ((
tp2,
nm2), κ')
K.
assert (
Hκ:
tp2 =
tp1 /\
nm2 =
nm1 /\ ∃
Hκ, κ' =
Some (
exist _ κ
Hκ))
by (
destruct κ;
eq_some_inv;
eauto).
destruct Hκ
as (-> & -> & [
Hκ ->]).
clear K.
apply am_bind_case.
intros;
exact I.
intros (
nm3, [|
cells]).
intros;
exact I.
unfold lift,
fmap.
apply am_bind_case.
discriminate.
intros x Hcells Q.
simpl in Q.
eq_some_inv;
subs.
generalize (
deref_pexpr_inv nm1 (
exist _ κ
Hκ)
lp).
rewrite Hcells.
clear Hcells.
intros Q.
assert (ρ ∈ γ (
tp1,
nm1))
as Hρ1.
apply (
tnum_m_stronger MONO1);
auto.
unfold realize.
generalize (@
optimistic_realization_sound cells (
tp1,
nm1)).
destruct (
optimistic_realization _ _)
as [ | (
tp',
nm') ];
simpl;
intros Hreal;
elim (
Hreal ρ
Hpun Hρ1).
intros TP'
NM'.
with_am_map'.
intros (
X &
Y).
intros v H.
eval_expr_inv.
destruct v1;
try discriminate.
specialize (
IHq _ H1).
destruct IHq as (
a &
A &
B).
specialize (
Q _ A).
destruct Q as (
Q &
me &
ME &
CA &
CI &
CS).
destruct CS as (
ptr &
Hptr &
CS).
generalize (
pt_eval_pexpr_correct Hstk PT B).
rewrite Hptr;
clear Hptr.
intros (
ab &
IN &
BA).
destruct (
proj2 (
tnum_m_stronger MONO1 (
conj Hpun TN)))
as (ρ
n &
Nc &
NM).
generalize (
me_of_pe_correct _ ρ
n NM a).
rewrite ME.
intros (
NC &
NB).
destruct (
N.nconvert_correct ge m _ _ _ _ Hstk _ _ (λ
x,
x)
_ _ NumDom sz nm1 ρ ρ
n Nc (@
invariant_block_of_ablock_inj _ _ INV)
_ _ B _ PT _ NC)
as (
n &
Z &
EV & ?).
discriminate.
simpl in Z.
subst n.
set (
c :=
cell_from ab (
Int.unsigned i,
exist _ κ
Hκ)).
edestruct (
Y c)
as (
pe &
PE).
apply CellSet.elements_spec.
subst c.
apply CS.
apply IN.
eapply concretize_int_correct.
eauto.
assumption.
destruct PE as [
PE PE'].
specialize (
TP'
c).
destruct (
ACTreeDom.get c _);
inversion PE;
clear PE.
subst pe.
exists (
PEvar c t).
split.
exact PE'.
assert (ρ
c =
v).
{
subst c.
simpl in H.
destruct ab as [
f loc|
b'].
-
simpl in BA.
unfold ρ.
simpl.
destruct (
get_stk _ _)
as [ (? &
e') | ];
eq_some_inv.
simpl.
destruct (
e' !
loc)
as [(
b' & ?)|];
eq_some_inv.
simpl.
subs.
rewrite H.
reflexivity.
-
unfold ρ.
simpl in *.
destruct (
Genv.invert_symbol);
eq_some_inv.
subs.
rewrite H.
reflexivity. }
constructor.
auto.
right.
subs.
auto.
Qed.
Lemma SZ' :
∀ (
b :
ABTree.elt) (
hi :
Z) (
md :
permission *
bool)
(
b' :
block),
ABTreeDom.get b sz =
Just (
hi,
md)
→
block_of_ablock ge ((
tmp,
e) ::
stk)
b =
Some b'
→
Mem.range_perm m b' 0
hi Cur Nonempty.
Proof.
Lemma convert_noerror (
q:
expr) :
∀ (
tn:
tnum) (
TN: ρ ∈ γ
tn),
match am_get (
convert q tn)
with
|
Some (
tn',
lp) => (∀
pe,
In pe lp → ¬
error_pexpr ge m ρ
e pe) → ¬
error_expr ge e tmp m q
|
None =>
True
end.
Proof.
unfold ρ.
induction q;
intros (
tp,
nm)
TN.
-
simpl.
set (
c :=
ACtemp μ
i).
destruct (
ACTreeDom.get c tp)
eqn:
TY.
exact I.
intros NB.
specialize (
NB _ (
or_introl eq_refl)).
intros B.
subst c.
inv B;
apply NB.
simpl.
rewrite get_stk_length.
simpl.
rewrite H0.
reflexivity.
simpl.
rewrite get_stk_length.
simpl.
rewrite H0.
reflexivity.
-
generalize (
E i).
simpl.
destruct is_local.
intros [
K _].
specialize (
K eq_refl).
intros _ B.
inversion B.
intuition.
intros [
_ K].
destruct (
Genv.find_symbol ge i)
eqn:
FS.
intros _ B;
inversion B.
congruence.
exact I.
-
intros _ B.
inversion B.
-
simpl.
unfold bind.
simpl.
apply am_bind_case.
intros;
exact I.
intros ((
tp',
nm'),
lp)
LP.
specialize (
IHq _ TN).
rewrite LP in IHq.
simpl in IHq.
simpl.
intros NB.
assert ( ∀
pe,
In pe lp → ¬
error_pexpr ge m ρ
e pe)
as NB'.
{
intros pe PE B.
eapply NB.
rewrite rev_map_correct, <-
in_rev,
in_map_iff.
eexists.
split.
reflexivity.
exact PE.
vauto.
}
specialize (
IHq NB').
intros B.
apply error_expr_Unop_inv in B.
destruct B as [(
v &
V &
B) |
B]. 2:
auto.
generalize (
convert_correct q _ TN).
rewrite LP.
simpl.
intros X.
specialize (
X _ V).
destruct X as (
pe &
PE &
EV).
eapply NB.
rewrite rev_map_correct, <-
in_rev,
in_map_iff.
eexists.
split.
reflexivity.
exact PE.
vauto.
-
simpl.
unfold bind.
simpl.
apply am_bind_case.
intros;
exact I.
intros ((
tp1,
nm1),
lp1)
LP1.
specialize (
IHq1 _ TN).
rewrite LP1 in IHq1.
simpl in IHq1.
generalize (
convert_wf q1 (
tp,
nm)
TN).
rewrite LP1.
intros [
MONO1 _].
generalize (
convert_correct q1 _ TN).
rewrite LP1.
intros H1.
apply am_bind_case.
intros;
exact I.
intros ((
tp2,
nm2),
lp2)
LP2.
generalize (
convert_correct q2 _ (
tnum_m_stronger MONO1 (
conj Hpun TN))).
rewrite LP2.
intros H2.
specialize (
IHq2 _ (
tnum_m_stronger MONO1 (
conj Hpun TN))).
rewrite LP2 in IHq2.
simpl in IHq2.
destruct lp2 as [|
pe2 lp2].
destruct (
noerror_eval_expr (
IHq2 (λ
_ K,
False_ind _ K)))
as (
v2 &
Hv2).
destruct (
H2 v2 Hv2)
as (? & () &
_).
destruct lp1 as [|
pe1 lp1].
destruct (
noerror_eval_expr (
IHq1 (λ
_ K,
False_ind _ K)))
as (
v1 &
Hv1).
destruct (
H1 v1 Hv1)
as (? & () &
_).
unfold am_get in H1,
H2.
destruct b;
try (
with_am_map';
intros [
_ Y]);
intros NB;
try (
assert ( ∀
pe,
In pe (
pe1::
lp1) → ¬
error_pexpr ge m ρ
e pe)
as NB1
by (
intros pe PE B;
eapply NB; [
apply in_map2;
first [
eassumption |
left;
reflexivity] |
vauto]);
specialize (
IHq1 NB1));
intros B;
apply error_expr_Binop_inv in B;
destruct B as [(
v &
w &
V &
W &
B) | [
B | (
v &
V &
B)] ];
auto;
try (
specialize (
H1 _ V);
destruct H1 as (
pe1' &
PE1 &
EV1));
try (
specialize (
H2 _ W);
destruct H2 as (
pe2' &
PE2 &
EV2));
try (
assert ( ∀
pe,
In pe (
pe2::
lp2) → ¬
error_pexpr ge m ρ
e pe)
as NB2
by (
intros pe PE B';
eapply NB; [
apply in_map2;
first [
eassumption |
left;
reflexivity] |
vauto]);
specialize (
IHq2 NB2)
);
auto;
try (
(
eapply NB; [
apply in_map2;
eauto |
vauto])
).
-
rename m0 into κ.
simpl.
unfold bind.
simpl.
apply am_bind_case.
intros;
exact I.
intros ((
tp1,
nm1),
lp)
LP.
specialize (
IHq _ TN).
generalize (
convert_correct q _ TN).
rewrite LP.
intros H1.
rewrite LP in IHq.
simpl in IHq.
generalize (
convert_wf q (
tp,
nm)
TN);
rewrite LP.
intros (
MONO1 &
WF).
apply am_bind_case.
intros;
exact I.
intros ((
tp2,
nm2), κ')
K.
assert (
Hκ:
tp2 =
tp1 /\
nm2 =
nm1 /\ ∃
Hκ, κ' =
Some (
exist _ κ
Hκ))
by (
destruct κ;
eq_some_inv;
eauto).
destruct Hκ
as (-> & -> & [
Hκ ->]).
clear K.
apply am_bind_case.
intros;
exact I.
intros (
nm3, [|
cells]).
intros;
exact I.
unfold lift,
fmap.
apply am_bind_case.
discriminate.
intros x Hcells Q.
simpl in Q.
eq_some_inv;
subs.
generalize (
deref_pexpr_inv nm1 (
exist _ κ
Hκ)
lp).
rewrite Hcells.
clear Hcells.
intros Q.
simpl.
assert (ρ ∈ γ (
tp1,
nm1))
as Hρ1.
apply (
tnum_m_stronger MONO1);
auto.
unfold realize.
generalize (@
optimistic_realization_sound cells (
tp1,
nm1)).
destruct (
optimistic_realization _ _)
as [ | (
tp',
nm') ];
simpl;
intros Hreal;
elim (
Hreal ρ
Hpun Hρ1).
intros TP'
NM'.
destruct (
proj2 (
tnum_m_stronger MONO1 (
conj Hpun TN)))
as (ρ
n &
Nc &
NM).
with_am_map'.
simpl.
intros (
X &
Y)
NB.
assert ( ∀
pe,
In pe lp → ¬
error_pexpr ge m ρ
e pe)
as NB'.
{
intros pe PE B.
specialize (
Q _ PE).
destruct Q as (
Q &
me &
ME &
CI &
CS).
generalize (
me_of_pe_correct nm1 ρ
n NM pe).
rewrite ME.
intros (
NC &
MEB).
apply (λ
P,
N.nconvert_def ge m _ _ _ _ Hstk _ _ (λ
x,
x)
_ _ NumDom sz SZ'
_ ρ ρ
n Nc (@
invariant_block_of_ablock_inj _ _ INV)
NM _ PT _ P me NC MEB B).
intuition.
}
specialize (
IHq NB').
intros B.
apply error_expr_Load_inv in B.
destruct B as [(
v' &
V' &
B) |
B]. 2:
easy.
specialize (
H1 _ V').
destruct H1 as (
pe &
PE &
EV).
specialize (
Q pe PE).
destruct Q as (
TY &
me &
ME &
CA &
CI &
CS).
destruct CS as (
ptr &
Hptr &
OFS).
generalize (
pt_eval_pexpr_correct Hstk PT EV).
rewrite Hptr;
clear Hptr.
intros PTR.
generalize (
me_of_pe_correct _ _ NM pe).
rewrite ME.
clear ME.
intros (
ME &
MEB).
generalize (λ
P,
error_pexpr_def (
N.nconvert_def ge m _ _ _ _ Hstk _ _ (λ
x,
x)
_ _ NumDom sz SZ'
_ ρ ρ
n Nc (@
invariant_block_of_ablock_inj _ _ INV)
NM _ PT _ P me ME MEB)
EV).
intros Z.
specialize (
Z (
WF _ PE)).
generalize (
pexpr_get_ty_ok EV Z).
rewrite TY.
destruct v';
destruct 1.
clear TY.
clear Z.
destruct (
N.nconvert_correct _ _ _ _ _ _ Hstk _ _ _ _ _ _ _ _ _ _ Nc (@
invariant_block_of_ablock_inj _ _ INV)
_ _ EV _ PT _ ME)
as (
n &
Z &
EV' & ?).
discriminate.
simpl in Z.
subst n.
destruct PTR as (
bs &
BS &
Hb).
assert (∃
v,
Mem.load κ
m b (
Int.unsigned i) =
Some v ∧
v ≠
Vundef)
as (
v &
V &
DEF).
{
set (
c :=
cell_from bs (
Int.unsigned i,
exist _ κ
Hκ)).
destruct (
Y c)
as (
pe' &
PE' &
IN).
rewrite <-
CellSet.elements_spec.
subst c.
eapply OFS;
auto.
eapply concretize_int_correct;
eauto.
generalize (
TP'
c).
destruct (
ACTreeDom.get _ _)
as [|
ty].
discriminate.
inversion PE'.
subst pe'.
clear PE'.
unfold ρ.
simpl.
destruct bs as [
f r |
ab ];
simpl in *;
eq_some_inv.
*
destruct (
get_stk _ _)
as [ (? &
e') | ]. 2:
eq_some_inv.
simpl in *.
destruct (
e' !
r)
as [(?,?)|];
eq_some_inv.
simpl in *.
subst b.
destruct (
Mem.load)
as [
v|].
intros V.
exists v.
split.
reflexivity.
intros ->.
destruct ty;
destruct V.
destruct ty;
destruct 1.
*
destruct Genv.invert_symbol;
eq_some_inv.
subst c ab.
destruct (
Mem.load)
as [
v|].
intros V.
exists v.
split.
reflexivity.
intros ->.
destruct ty;
destruct V.
destruct ty;
destruct 1.
}
inversion B.
auto.
congruence.
congruence.
Qed.
Lemma deref_expr_correct (
tn:
tnum) (
TN: ρ ∈ γ
tn) κ
q :
match am_get (
deref_expr κ
q tn)
with
|
Some (
tn',
cells) =>
tnum_mono tn tn' ∧
¬
error_expr ge e tmp m q ∧
∀
v,
eval_expr ge e tmp m q v →
∃
ab b i,
v =
Vptr b i ∧
In (
cell_from ab (
Int.unsigned i, κ))
cells ∧
block_of_ablock ge ((
tmp,
e) ::
stk)
ab =
Some b ∧
(
align_chunk (
proj1_sig κ) |
Int.unsigned i)
|
None =>
True
end.
Proof.
Lemma nconvert_sound (
tn:
tnum) (
TN: ρ ∈ γ
tn) (
q:
expr) :
match am_get (
nconvert q tn)
with
|
Some (
tn',
_) =>
tnum_mono tn tn' ∧
¬
error_expr ge e tmp m q
|
None =>
True
end.
Proof.
Lemma nconvert_ex (
tn:
tnum) (
TN: ρ ∈ γ(
tn)) (
q:
expr) :
match am_get (
nconvert q tn)
with
|
Some ((
tp',
nm'),
lme) =>
tnum_mono tn (
tp',
nm') ∧
∃
lpe,
am_get (
convert q tn) =
Some ((
tp',
nm'),
lpe) ∧
∀
v,
eval_expr ge e tmp m q v →
v ≠
Vundef →
∀ (
TP: ρ ∈ γ
tp') (ρ
n:
cell →
mach_num) (
Nc:
compat ρ ρ
n) (
NM: ρ
n ∈ γ
nm'),
∃
pe me n,
In pe lpe ∧
eval_pexpr ge m ρ
e pe v ∧
N.nconvert ge μ
_ _ (λ
x,
x)
_ _ NumDom sz nm'
pt pe =
inl me ∧
In me lme ∧
N.ncompat v n ∧
N.wtype_num n (
pexpr_get_ty pe) ∧
eval_mexpr ρ
n me n
|
None =>
True
end.
Proof.
Lemma convert_to_me (
tn:
tnum) (
TN: ρ ∈ γ(
tn)) (
q:
expr) :
match am_get (
convert q tn)
with
|
Some ((
tp',
nm'),
lpe) =>
match am_get (
me_of_pe_list nm'
lpe)
with
|
Some lme =>
tnum_mono tn (
tp',
nm') ∧
∃
v,
eval_expr ge e tmp m q v ∧
v ≠
Vundef
∧ ∀ (
TP: ρ ∈ γ
tp') (ρ
n:
cell →
mach_num) (
Nc:
compat ρ ρ
n) (
NM: ρ
n ∈ γ
nm'),
∃
pe me n,
In pe lpe ∧
eval_pexpr ge m ρ
e pe v ∧
N.nconvert ge μ
_ _ (λ
x,
x)
_ _ NumDom sz nm'
pt pe =
inl me ∧
In me lme ∧
N.ncompat v n ∧
N.wtype_num n (
pexpr_get_ty pe) ∧
eval_mexpr ρ
n me n
|
None =>
True
end
|
None =>
True
end.
Proof.
generalize (
nconvert_sound _ TN q).
generalize (
nconvert_ex _ TN q).
unfold nconvert,
bind.
simpl.
destruct (
convert q _)
as (((
tp',
nm'),
lpe) & [|]). 2:
intros;
exact I.
simpl.
destruct (
me_of_pe_list _ lpe)
as (
lme & [|]). 2:
intros;
exact I.
simpl.
intros (
MONO &
lpe' &
Hlpe' &
H) (
_ &
NB);
eq_some_inv;
subst.
destruct (
noerror_eval_expr_def NB)
as (
v &
Def &
V).
specialize (
H v V Def).
split.
exact MONO.
exists v.
split.
exact V.
split.
exact Def.
intros TP ρ
n Nc NM.
specialize (
H TP _ Nc NM).
destruct H as (
pe &
me &
n &
Hn &
Hpn &
Hvn &
Htn &
Vn).
exists pe,
me,
n.
intuition.
Qed.
End CONVERT_CORRECT.
End CONVERT.
Definition t :
Type := (
stack+⊤ * (
sizes * (
points_to *
tnum)))%
type.
Definition iter_t :
Type := (
stack+⊤ * (
sizes * (
points_to * (
types *
num_iter))))%
type.
Definition AbMem stk sz pt tp nm :
t := (
stk, (
sz, (
pt, (
tp,
nm)))).
Definition ab_stk (
ab:
t) :
stack+⊤ :=
fst ab.
Definition ab_sz (
ab:
t) :
sizes :=
fst (
snd ab).
Definition ab_pt (
ab:
t) :
points_to :=
fst (
snd (
snd ab)).
Definition ab_nm (
ab:
t) :
tnum :=
snd (
snd (
snd ab)).
Definition ab_tp (
ab:
t) :
types :=
fst (
snd (
snd (
snd ab))).
Definition ab_num (
ab:
t) :
num :=
snd (
snd (
snd (
snd ab))).
Arguments ab_stk ab /.
Arguments ab_sz ab /.
Arguments ab_pt ab /.
Arguments ab_nm ab /.
Arguments ab_tp ab /.
Arguments ab_num ab /.
Definition ab_stk_iter (
ab:
iter_t) :
stack+⊤ :=
fst ab.
Definition ab_sz_iter (
ab:
iter_t) :
sizes :=
fst (
snd ab).
Definition ab_pt_iter (
ab:
iter_t) :
points_to :=
fst (
snd (
snd ab)).
Definition ab_nm_iter (
ab:
iter_t) :
tnum_iter :=
snd (
snd (
snd ab)).
Definition ab_tp_iter (
ab:
iter_t) :
types :=
fst (
snd (
snd (
snd ab))).
Definition ab_num_iter (
ab:
iter_t) :
num_iter :=
snd (
snd (
snd (
snd ab))).
Definition with_stk (
f:
stack+⊤ →
stack+⊤) (
ab:
t) :
t :=
AbMem (
f (
ab_stk ab)) (
ab_sz ab) (
ab_pt ab) (
ab_tp ab) (
ab_num ab).
Definition with_sz (
f:
sizes →
sizes) (
ab:
t) :
t :=
AbMem (
ab_stk ab) (
f (
ab_sz ab)) (
ab_pt ab) (
ab_tp ab) (
ab_num ab).
Definition with_pt (
f:
points_to →
points_to) (
ab:
t) :
t :=
AbMem (
ab_stk ab) (
ab_sz ab) (
f (
ab_pt ab)) (
ab_tp ab) (
ab_num ab).
Definition with_tp (
f:
types →
types) (
ab:
t) :
t :=
AbMem (
ab_stk ab) (
ab_sz ab) (
ab_pt ab) (
f (
ab_tp ab)) (
ab_num ab).
Definition with_num (
f:
num →
num) (
ab:
t) :
t :=
AbMem (
ab_stk ab) (
ab_sz ab) (
ab_pt ab) (
ab_tp ab) (
f (
ab_num ab)).
Definition with_tnum (
f:
tnum →
tnum) (
ab:
t) :
t :=
(
ab_stk ab, (
ab_sz ab, (
ab_pt ab,
f (
ab_nm ab)))).
Definition dom {
A} (
x:
positive) (
m:
PTree.t A) :
bool :=
match PTree.get x m with
|
Some _ =>
true
|
None =>
false
end.
Remark dom_set {
A}
x m y (
a:
A) :
dom x (
PTree.set y a m) =
peq x y ||
dom x m.
Proof.
Instance stack_elt_gamma :
gamma_op (
lvarset *
tvarset) (
temp_env *
env) :=
λ
ltv te_e,
∀
x,
PSet.mem x (
fst ltv) =
dom x (
snd te_e).
Instance join_stack_elt_correct :
join_op_correct (
lvarset*
tvarset) ((
lvarset *
tvarset)+⊤) (
temp_env *
env).
Proof.
Instance leb_stack_elt_correct :
leb_op_correct (
lvarset *
tvarset) (
temp_env *
env).
Proof.
Record gamma (
ab:
t) (
cs:
concrete_state) :
Prop :=
{
_ :
fst cs ∈ γ(
ab_stk ab)
;
_ :
ab_stk ab ≠
All →
invariant cs
;
_ :
snd cs ∈
sizes_gamma ge (
fst cs) (
ab_sz ab)
;
_ :
mem_as_fun ge cs ∈ (
points_to_gamma ge (
fst cs) (
ab_pt ab) ∩ γ(
ab_nm ab))
}.
Instance t_gamma :
gamma_op t concrete_state :=
gamma.
Record iter_gamma (
ab:
iter_t) (
cs:
concrete_state) :
Prop :=
{
_ :
fst cs ∈ γ(
ab_stk_iter ab)
;
_ :
ab_stk_iter ab ≠
All →
invariant cs
;
_ :
snd cs ∈
sizes_gamma ge (
fst cs) (
ab_sz_iter ab)
;
_ :
mem_as_fun ge cs ∈ (
points_to_gamma ge (
fst cs) (
ab_pt_iter ab) ∩ γ(
ab_nm_iter ab))
}.
Instance iter_t_gamma :
gamma_op iter_t concrete_state :=
iter_gamma.
Definition split_t (
ab:
t) :
option (
ident *
lvarset *
tvarset *
stack *
sizes *
points_to *
tnum) :=
match ab_stk ab with
|
All |
Just nil =>
None
|
Just ((ε, τ) :: σ) =>
let '(
sz, (
pt,
tn)) := (
snd ab)
in
Some (
plength σ, ε, τ, σ,
sz,
pt,
tn)
end.
Definition noerror (
exp:
expr) (
ab:
t) :
alarm_mon unit :=
match split_t ab with
|
Some (μ, ε, τ, σ,
sz,
pt,
tn) =>
do _ <-
nconvert μ ε
sz pt exp tn;
ret tt
|
None =>
do _ <-
alarm_am "
anomaly (
noerror)";
ret tt
end.
Definition ab_eval_expr (
ab:
t) (
a:
expr)
:
alarm_mon ((
tnum *
PTSet *
AbTy.t+⊤ *
list (
mexpr cell)) +⊥) :=
match split_t ab with
|
Some (μ, ε, τ, σ,
sz,
pt,
tn) =>
do (
tn',
lp) <-
convert μ ε
sz pt a tn;
let '(
tp',
nm') :=
tn'
in
do ln <-
me_of_pe_list μ
sz pt nm'
lp;
match lp with nil =>
ret Bot |
_ =>
let '(
a',
ty) :=
union_list_map (λ
e, (
pt_eval_pexpr ge μ
pt e,
Just (
pexpr_get_ty e))) (
All,
All)
lp in
ret (
NotBot (
tn',
a',
ty,
ln))
end
|
None =>
do _ <-
alarm_am "
ab_eval_expr failed";
ret Bot
end.
Fixpoint ab_eval_exprlist (
ab:
t) (
e:
list expr) :
alarm_mon ((
t *
list (
PTSet *
AbTy.t+⊤ *
list (
mexpr cell)))+⊥) :=
match e with
|
nil =>
ret (
NotBot (
ab,
nil))
|
e ::
e' =>
do r <-
ab_eval_expr ab e;
match r with
|
Bot =>
ret Bot
|
NotBot (
tn,
pt,
ty,
me) =>
do m <-
ab_eval_exprlist (
with_tnum (λ
_,
tn)
ab)
e';
match m with
|
Bot =>
ret Bot
|
NotBot (
ab,
y) =>
ret (
NotBot (
ab, (
pt,
ty,
me) ::
y))
end
end
end.
Definition nm_forget_all :=
fold_left (λ
m c,
bind m (
AbMachineEnv.forget c)).
Definition nm_upd (
nm:
num) (
c:
cell) (
e:(
mexpr cell)) :
num+⊥ :=
let nm' :=
AbMachineEnv.assign c e nm in
nm_forget_all (
overlap c)
nm'.
Definition nm_upd_cells (
nm:
num) (
l:
list cell) (
e:(
mexpr cell)) :
num+⊥ :=
union_list_map (λ
c,
nm_upd nm c e) (
NotBot nm)
l.
Definition ct_forget_all {
A:
Type} :=
fold_left (λ (
m:
ACTreeDom.t A)
c,
ACTreeDom.set m c All).
Definition ct_upd {
A} (
m:
ACTreeDom.t A) (
c:
cell) (
a:
A+⊤) :
ACTreeDom.t A :=
ACTreeDom.set (
ct_forget_all (
overlap c)
m)
c a.
Definition pt_upd (
pt:
points_to) (
l:
list cell) (
s:
BlockSet.t+⊤) :
points_to :=
union_list_map (λ
c,
ct_upd pt c s)
pt l.
Definition tp_upd_cells (
tp:
types) (
l:
list cell) (
tt:
AbTy.t+⊤) :
types :=
union_list_map (λ
c,
ct_upd tp c tt)
tp l.
Definition chunk_type (κ:
typed_memory_chunk) (
ty:
AbTy.t+⊤) :
bool :=
match ty with
|
All =>
false
|
Just ty' =>
match κ,
ty'
with
|
exist (
Mint8signed |
Mint8unsigned |
Mint16signed |
Mint16unsigned)
_,
VI
|
exist Mint32 _, (
VI |
VP |
VIP)
|
exist Mint64 _,
VL
|
exist Mfloat64 _,
VF
|
exist Mfloat32 _,
VS
=>
true
|
_,
_ =>
false
end
end.
Definition assign_cells (κ:
option typed_memory_chunk) (
c:
list cell) (
a:
expr) (
ab:
t) :
alarm_mon (
t+⊥) :=
do res <-
ab_eval_expr ab a;
match res with
|
NotBot ((
tp,
nm),
ptr,
ty,
ln) =>
do _ <-
am_assert match κ
with Some κ =>
chunk_type κ
ty |
None =>
true end
("
bad type: " ++
to_string ty);
ret (
do nm' <-
union_list_map (
nm_upd_cells nm c) (
NotBot nm)
ln;
let tp' :=
tp_upd_cells tp c ty in
ret (
AbMem (
ab_stk ab) (
ab_sz ab) (
pt_upd (
ab_pt ab)
c ptr)
tp'
nm')
)
|
Bot =>
ret Bot
end.
Definition assign_in (μ:
fname) (
x:
ident) (
a:
expr) (
ab:
t) :
alarm_mon (
t+⊥) :=
(
assign_cells None (
ACtemp μ
x ::
nil)
a ab).
Definition assign (
x:
ident) (
a:
expr) (
ab:
t) :
alarm_mon (
t+⊥) :=
match ab_stk ab with
|
Just (
_::σ) =>
assign_in (
plength σ)
x a ab
|
_ =>
do _ <-
alarm_am "
assign failed";
ret Bot
end.
Definition assign_any (
x:
ident) (
ty:
AbTy.t) (
ab:
t) :
alarm_mon (
t+⊥) :=
match split_t ab with
|
Some (μ, ε, τ, σ,
sz,
pt,
tn) =>
let '(
tp,
nm) :=
tn in
let c :=
ACtemp μ
x in
do nm' <-
match ty with
|
VI |
VL |
VF |
VS =>
ret (
AbMachineEnv.forget c nm)
|
_ =>
do _ <-
alarm_am ("
assign_any:
bad type " ++
to_string ty);
ret Bot
end;
ret (
do nm' <-
nm';
ret (
with_num (λ
_,
nm')
(
with_pt (λ
pt,
ACTreeDom.set pt c (
Just BlockSet.empty))
(
with_tp (λ
tp,
ACTreeDom.set tp c (
Just ty))
ab))))
|
None =>
do _ <-
alarm_am "
assign_any failed";
ret Bot
end.
Definition permission_can_write (
p:
permission) :
bool :=
match p with
| (
Freeable |
Writable) =>
true
| (
Readable |
Nonempty) =>
false
end.
Definition cell_in_bounds (κ:
typed_memory_chunk) (
ab:
t) (
c:
cell) :
alarm_mon unit :=
let b :=
ablock_of_cell c in
let '(
ofs,
_) :=
range_of_cell c in
match ABTreeDom.get b (
ab_sz ab)
with
|
All =>
do _ <-
alarm_am ("
block of unknown size: " ++
to_string b);
ret tt
|
Just (
hi, (
perm,
vol)) =>
if permission_can_write perm then
if zle 0
ofs &&
zle (
ofs +
size_chunk (
proj1_sig κ))
hi
then ret tt
else do _ <-
alarm_am ("
cell out of range("++
to_string hi ++"): " ++
to_string c);
ret tt
else do _ <-
alarm_am ("
read-
only cell: " ++
to_string c);
ret tt
end.
Definition expr_has_cast_for_chunk (
e:
expr) (κ:
typed_memory_chunk) :
bool :=
match κ,
e with
|
exist Mint8signed _,
Eunop Ocast8signed _
|
exist Mint8unsigned _,
Eunop Ocast8unsigned _
|
exist Mint16signed _,
Eunop Ocast16signed _
|
exist Mint16unsigned _,
Eunop Ocast16unsigned _
|
exist Mint32 _,
_
|
exist Mint64 _,
_
|
exist Mfloat32 _,
_
|
exist Mfloat64 _,
_
=>
true
|
_,
_ =>
false
end.
Definition store (κ:
memory_chunk) (
a e:
expr) (
ab:
t) :
alarm_mon (
t+⊥) :=
let κ :
option typed_memory_chunk :=
match κ
with
|
Many32 |
Many64 =>
None
| κ =>
Some (
exist _ κ
I)
end
in
match κ
with
|
None =>
do _ <-
alarm_am "
invalid store memory chunk";
ret Bot
|
Some κ =>
match split_t ab with
|
Some (μ, ε, τ, σ,
sz,
pt,
tn) =>
do _ <-
am_assert (
expr_has_cast_for_chunk e κ)
("
Uncasted expr for " ++
to_string (
proj1_sig κ) ++ ": " ++
to_string e);
do (
tn',
cells) <-
deref_expr μ ε
sz pt κ
a tn;
let ab :=
with_tnum (λ
_,
tn')
ab in
match cells with nil =>
ret Bot |
_ =>
do _ <-
am_rev_map (
cell_in_bounds κ
ab)
cells;
assign_cells (
Some κ)
cells e ab
end
|
None =>
do _ <-
alarm_am "
store failed";
ret Bot
end
end.
Definition nassume b nm (
F:
mexpr cell →
mexpr cell)
e :
num+⊥ :=
union_list_map (λ
me,
AbMachineEnv.assume (
F me)
b nm) (
NotBot nm)
e.
Definition bool_expr (
e:
expr) :
expr :=
match e with
|
Ebinop (
Ocmp _|
Ocmpu _|
Ocmpf _|
Ocmpfs _|
Ocmpl _|
Ocmplu _)
_ _ =>
e
|
_ =>
Ebinop (
Ocmp Cne)
e (
Econst (
Csharpminor.Ointconst Int.zero))
end.
Definition assume (
b:
expr) (
ab:
t) :
alarm_mon (
t+⊥ *
t+⊥) :=
match split_t ab with
|
Some (μ, ε, τ, σ,
sz,
pt,
tn) =>
let b :=
bool_expr b in
do (
tn',
b') <-
nconvert μ ε
sz pt b tn;
let '(
tp,
nm) :=
tn'
in
ret
(
do nz <-
nassume true nm id b';
ret (
AbMem (
Just ((ε,τ)::σ))
sz pt tp nz),
do z <-
nassume false nm id b';
ret (
AbMem (
Just ((ε,τ)::σ))
sz pt tp z))
|
None =>
do _ <-
alarm_am "
assume failed";
ret (
Bot,
Bot)
end.
Definition deref_fun (
e:
expr) (
ab:
t) :
alarm_mon (
list (
ident *
fundef)) :=
match split_t ab with
|
Some (μ, ε, τ, σ,
sz,
pt,
tn) =>
do (
tn,
cells) <-
deref_expr μ ε
sz pt (
exist _ Mint32 I)
e tn;
am_map' (λ
c,
match c with
|
ACglobal b 0 (
exist Mint32 _) =>
match Genv.find_funct_ptr ge b with
|
Some f =>
match Genv.invert_symbol ge b with
|
Some i =>
Result (
i,
f)
|
None =>
Error None "
unknown function"
end
|
None =>
Error None ("
bad function pointer " ++
to_string b)
end
|
_ =>
Error None ("
bad function pointer (2)")
end)
cells
|
None =>
do _ <-
alarm_am "
anomaly:
deref_fun";
ret nil
end.
Definition ab_bind_parameters (μ:
ident)
(
formals:
list ident) (
args:
list (
PTSet *
AbTy.t+⊤ *
list (
mexpr cell)))
:
alarm_mon (
t+⊥) →
alarm_mon (
t+⊥) :=
fold_left2
(λ
acc id v,
do ab' <-
acc;
ret (
do ab' <-
ab';
let c :=
ACtemp μ
id in
let '(
ptr,
ty,
ln) :=
v in
do nm' <-
union_list_map (λ
me,
AbMachineEnv.assign c me (
ab_num ab')) (
NotBot (
ab_num ab'))
ln;
ret (
AbMem (
ab_stk ab') (
ab_sz ab')
(
ct_upd (
ab_pt ab')
c ptr) (
ct_upd (
ab_tp ab')
c ty)
nm'))
)
(λ
_ _,
do _ <-
alarm_am "
ab_bind_parameters:
too many formals";
ret Bot)
(λ
_ _,
do _ <-
alarm_am "
ab_bind_parameters:
too many arguments";
ret Bot)
formals args.
Definition set_local_sizes μ
vars :
sizes →
sizes :=
fold_left (λ
sz x_hi,
ABTreeDom.set sz (
ABlocal μ (
fst x_hi)) (
Just (
snd x_hi, (
Freeable,
false))))
vars.
Definition push_frame (μ
_def:
function) (
args:
list expr) (
ab:
t) :
alarm_mon (
t+⊥) :=
do σ' <-
match ab_stk ab with
|
All =>
do _ <-
alarm_am "
no stack";
ret nil
|
Just σ' =>
ret σ'
end;
let μ :=
plength σ'
in
do res <-
ab_eval_exprlist ab args;
match res with
|
Bot =>
ret Bot
|
NotBot (
ab,
eargs) =>
let ε :=
PSetOp.build (
rev_map fst μ
_def.(
fn_vars))
in
let τ :=
PSetOp.build (μ
_def.(
fn_temps) ++ μ
_def.(
fn_params))
in
let σ := (ε, τ) :: σ'
in
let ab' :=
with_stk (λ
_,
Just σ) (
with_sz (
set_local_sizes μ μ
_def.(
fn_vars))
ab)
in
ab_bind_parameters μ μ
_def.(
fn_params)
eargs (
ret (
NotBot ab'))
end.
Invalidate cells local to μ.
Definition is_local_cell (μ:
fname) (
c:
cell) :
bool :=
match c with
|
AClocal μ'
_ _ _
|
ACtemp μ'
_ =>
eq_dec μ μ'
|
ACglobal _ _ _ =>
false
end.
Definition is_local_block (μ:
fname) (
ab:
ablock) :
bool :=
match ab with
|
ABlocal μ'
_ =>
eq_dec μ μ'
|
ABglobal _ =>
false
end.
Definition pop_local_tp (μ:
fname) :
types →
types :=
ACTreeDom.SP.filter (λ
c _,
negb (
is_local_cell μ
c)).
Invalidate pointers to cells local to μ.
Definition pop_local_pt (μ:
fname) :
points_to →
points_to :=
ACTreeDom.SP.filter (λ
c bs,
negb (
is_local_cell μ
c) &&
negb (
BSO.existsb (
is_local_block μ)
bs)).
Definition clear_local_sizes μ ε :
sizes →
sizes :=
PSet.fold (λ
x,
ABTree.remove (
ABlocal μ
x)) ε.
Definition all_local_cells (μ:
ident) (ε:
lvarset) (
sz:
sizes) :
list cell :=
PSet.fold (λ
x,
let z :=
match ABTree.get (
ABlocal μ
x)
sz with Some (
z,
_) =>
z |
None =>
Z0 end in
memory_chunk_fold (λ
acc κ,
let k :=
align_chunk (
proj1_sig κ)
in
N.peano_rect _
acc
(λ
n,
cons (
AClocal μ
x (
Z.of_N n *
k) κ))
(
Z.to_N (
z /
k))
)
) ε
nil.
Definition pop_local_num (μ:
ident) (ε:
lvarset) (τ:
tvarset) (
sz:
sizes) :
num+⊥ →
num+⊥ :=
(
nm_forget_all (
all_local_cells μ ε
sz)) ∘ (
nm_forget_all (
List.map (
ACtemp μ) (
PSet.elements τ))).
Definition pop_frame (
res:
option (
expr)) (
temp :
option (
ident)) (
ab:
t) :
alarm_mon (
t+⊥) :=
match ab_stk ab,
res,
temp with
|
Just ((ε₀, τ₀)::(ε,τ)::σ),
Some r,
Some x =>
let μ :=
plength σ
in
let μ₀ :=
Pos.succ μ
in
(
do ab' <-
assign_in μ
x r ab;
match ab'
with
|
NotBot ab'' =>
ret (
do nm' <-
pop_local_num μ₀ ε₀ τ₀ (
ab_sz ab'') (
NotBot (
ab_num ab''));
ret (
with_sz (
clear_local_sizes μ₀ ε₀)
(
with_tp (
pop_local_tp μ₀)
(
with_pt (
pop_local_pt μ₀)
(
with_stk (λ
_,
Just ((ε,τ)::σ))
(
with_num (λ
_,
nm')
ab''))))))
|
Bot =>
ret Bot
end
)
|
Just ((ε,τ)::
nil),
Some r,
_ =>
let μ :=
xH in
do ret' <-
ab_eval_expr ab r;
match ret'
with
|
Bot =>
ret Bot
|
NotBot (
_,
ty,
_) =>
match ty with
|
Just VI =>
ret (
NotBot (
with_sz (
clear_local_sizes μ ε)
(
with_tp (
pop_local_tp μ)
(
with_pt (
pop_local_pt μ)
(
with_stk (λ
_,
Just nil)
ab)))))
|
_ =>
do _ <-
alarm_am "
main ret not an int";
ret Bot
end
end
|
Just (
_::
nil),
_,
_ =>
do _ <-
alarm_am "
pop_frame failed at main";
ret Bot
|
Just ((ε,τ)::σ),
None,
None =>
let μ :=
plength σ
in
ret (
do nm' <-
pop_local_num μ ε τ (
ab_sz ab) (
NotBot (
ab_num ab));
ret (
with_sz (
clear_local_sizes μ ε)
(
with_tp (
pop_local_tp μ)
(
with_pt (
pop_local_pt μ)
(
with_stk (λ
_,
Just σ)
(
with_num (λ
_,
nm')
ab))))))
|
Just ((ε,τ)::σ),
Some r,
None =>
let μ :=
plength σ
in
do _ <-
noerror r ab;
ret (
do nm' <-
pop_local_num μ ε τ (
ab_sz ab) (
NotBot (
ab_num ab));
ret (
with_sz (
clear_local_sizes μ ε)
(
with_tp (
pop_local_tp μ)
(
with_pt (
pop_local_pt μ)
(
with_stk (λ
_,
Just σ)
(
with_num (λ
_,
nm')
ab))))))
|
_,
_,
_ =>
do _ <-
alarm_am ("
pop_frame failed: " ++
to_string temp ++ " := " ++
to_string res );
ret Bot
end.
Let bad_align {
T} (
r:
T) :=
do _ <-
alarm_am "
misaligned init data";
ret r.
Instance InitDataToString :
ToString init_data :=
λ
id,
match id with
|
Init_int8 i => "
int8: " ++
to_string i
|
Init_int16 i => "
int16: " ++
to_string i
|
Init_int32 i => "
int32: " ++
to_string i
|
Init_int64 i => "
int64: " ++
to_string i
|
Init_float32 f => "
float32: " ++
to_string f
|
Init_float64 f => "
float64: " ++
to_string f
|
Init_space n => "
space: " ++
to_string n
|
Init_addrof i o => "&" ++
to_string i ++ " + " ++
to_string o
end.
Definition type_of_chunk (κ:
typed_memory_chunk) :
AbTy.t :=
match κ
with
|
exist (
Mint8signed |
Mint8unsigned |
Mint16signed |
Mint16unsigned |
Mint32)
_
=>
VI
|
exist Mint64 _ =>
VL
|
exist Mfloat64 _ =>
VF
|
exist Mfloat32 _ =>
VS
|
exist _ H =>
match H with end
end.
Definition permission_can_read (
p:
permission) : {
perm_order p Readable } + {
p =
Nonempty } :=
match p with
|
Freeable =>
left (
perm_F_any Readable)
|
Writable =>
left perm_W_R
|
Readable =>
left (
perm_refl Readable)
|
Nonempty =>
right eq_refl
end.
Definition zero_all_cells (
b:
block) (
base:
Z) (
sz:
Z) (
ab:
t):
t+⊥ :=
N.peano_rect
(λ
_,
t+⊥)
(
NotBot ab)
(λ
ofs ab,
memory_chunk_fold
(λ
ab κ,
let ofs' :=
base +
Z.of_N ofs in
if Zdivide_dec (
align_chunk (
proj1_sig κ))
ofs' (
align_chunk_pos (
proj1_sig κ))
&&
zle (
Z.of_N ofs +
size_chunk (
proj1_sig κ))
sz then
do ab <-
ab;
let c :=
ACglobal b ofs' κ
in
do nm <-
AbMachineEnv.assign c
(
match κ
with
|
exist (
Mint8signed |
Mint8unsigned |
Mint16signed |
Mint16unsigned |
Mint32)
_
=>
me_const_i _ Int.zero
|
exist Mint64 _ =>
me_const_l _ Int64.zero
|
exist (
Mfloat32)
_ =>
me_const_s _ Float32.zero
|
exist (
Mfloat64)
_ =>
me_const_f _ Float.zero
|
exist _ H =>
match H with end
end)
(
ab_num ab);
ret
(
with_tp (
ACTree.set c (
type_of_chunk κ))
(
with_pt (
ACTree.set c BlockSet.empty)
(
with_num (λ
_,
nm)
ab)))
else ab
)
ab)
(
Z.to_N sz).
Definition ab_alloc_global perm vol b (
gv:
list init_data)
ab :
alarm_mon (
t+⊥) :=
do sz_ab' <-
am_fold
(λ (
acc:
_*(
_+⊥))
id,
let '(
ofs,
ab) :=
acc in
let ofs' :=
ofs +
Genv.init_data_size id in
let c κ
H :=
ACglobal b ofs (
exist _ κ
H)
in
if match id with
|
Init_space _
|
Init_int8 _ =>
true
|
Init_int16 _ =>
Zdivide_dec (
align_chunk Mint16signed)
ofs eq_refl
|
Init_int32 _
|
Init_addrof _ _ =>
Zdivide_dec (
align_chunk Mint32)
ofs eq_refl
|
Init_int64 _ =>
Zdivide_dec (
align_chunk Mint64)
ofs eq_refl
|
Init_float32 _ =>
Zdivide_dec (
align_chunk Mfloat32)
ofs eq_refl
|
Init_float64 _ =>
Zdivide_dec (
align_chunk Mfloat64)
ofs eq_refl
end then
match id return alarm_mon (
Z*
t+⊥)
with
|
Init_int32 n =>
ret (
ofs',
if permission_can_read perm
then
do ab' <-
ab;
do nm <-
AbMachineEnv.assign (
c Mint32 I) (
me_const_i _ n) (
ab_num ab');
ret (
with_tp (
ACTree.set (
c Mint32 I)
VI)
(
with_pt (
ACTree.set (
c Mint32 I)
BlockSet.empty)
(
with_num (λ
_,
nm)
ab')))
else ab)
|
Init_int64 n =>
ret (
ofs',
if permission_can_read perm
then
do ab' <-
ab;
do nm <-
AbMachineEnv.assign (
c Mint64 I) (
me_const_l _ n) (
ab_num ab');
ret (
with_tp (
ACTree.set (
c Mint64 I)
VL)
(
with_pt (
ACTree.set (
c Mint64 I)
BlockSet.empty)
(
with_num (λ
_,
nm)
ab')))
else ab)
|
Init_addrof s o =>
match Genv.find_symbol ge s with
|
Some b' =>
ret (
ofs',
if permission_can_read perm
then
do ab' <-
ab;
do nm <-
AbMachineEnv.assign (
c Mint32 I) (
me_const_i _ o) (
ab_num ab');
ret (
with_tp (
ACTree.set (
c Mint32 I)
VP)
(
with_pt (
ACTree.set (
c Mint32 I) (
BSO.singleton (
ABglobal b')))
(
with_num (λ
_,
nm)
ab')))
else ab)
|
None =>
do _ <-
alarm_am ("
ab_alloc_globals:
not a symbol ("
++
to_string s ++ ")");
ret (
ofs',
ab)
end
|
Init_space s =>
ret (
ofs',
if negb (
permission_can_read perm)
then ab else do ab' <-
ab;
zero_all_cells b ofs s ab')
|
Init_float64 f =>
ret (
ofs',
if negb (
permission_can_read perm)
then ab
else
do ab' <-
ab;
do nm <-
AbMachineEnv.assign (
c Mfloat64 I) (
MEconst _ (
MNfloat f)) (
ab_num ab');
ret (
with_tp (
ACTree.set (
c Mfloat64 I)
VF)
(
with_pt (
ACTree.set (
c Mfloat64 I)
BlockSet.empty)
(
with_num (λ
_,
nm)
ab'))))
|
Init_float32 f =>
ret (
ofs',
if negb (
permission_can_read perm)
then ab
else
do ab' <-
ab;
do nm <-
AbMachineEnv.assign (
c Mfloat32 I) (
MEconst _ (
MNsingle f)) (
ab_num ab');
ret (
with_tp (
ACTree.set (
c Mfloat32 I)
VS)
(
with_pt (
ACTree.set (
c Mfloat32 I)
BlockSet.empty)
(
with_num (λ
_,
nm)
ab'))))
|
Init_int8 i =>
ret (
ofs',
if permission_can_read perm
then
do ab' <-
ab;
do nm <-
AbMachineEnv.assign (
c Mint8unsigned I) (
MEunop Ocast8unsigned (
me_const_i _ i)) (
ab_num ab');
ret (
with_tp (
ACTree.set (
c Mint8unsigned I)
VI)
(
with_pt (
ACTree.set (
c Mint8unsigned I)
BlockSet.empty)
(
with_num (λ
_,
nm)
ab')))
else ab)
|
Init_int16 i =>
ret (
ofs',
if permission_can_read perm
then
do ab' <-
ab;
do nm <-
AbMachineEnv.assign (
c Mint16unsigned I) (
MEunop Ocast16unsigned (
me_const_i _ i)) (
ab_num ab');
ret (
with_tp (
ACTree.set (
c Mint16unsigned I)
VI)
(
with_pt (
ACTree.set (
c Mint16unsigned I)
BlockSet.empty)
(
with_num (λ
_,
nm)
ab')))
else ab)
end
else bad_align acc)
gv
(0,
ab);
let '(
sz,
ab') :=
sz_ab'
in
ret (
do ab'' <-
ab';
ret (
with_sz (
ABTree.set (
ABglobal b) (
sz, (
perm,
vol)))
ab'')).
Definition ab_alloc_globals (
gl:
list (
ident *
globdef fundef unit)) :
alarm_mon (
block *
t+⊥) :=
(
am_fold
(λ
acc ig,
let '(
b,
ab) :=
acc in
let b' :=
Pos.succ b in
match ig with
| (
_,
Gfun _) =>
ret (
b',
fmap (
with_sz (
ABTree.set (
ABglobal b) (1, (
Nonempty,
false))))
ab)
| (
_,
Gvar gv) =>
do ab' <-
ab_alloc_global (
Genv.perm_globvar gv) (
gvar_volatile gv)
b gv.(
gvar_init)
ab;
ret (
b',
ab')
end)
gl
(
xH,
do t <- ⊤;
ret (
Just nil,
t))).
Definition init_mem (
defs:
list (
ident *
globdef fundef unit)) :
alarm_mon (
t+⊥) :=
do _ <-
am_assert (
norepet_map fst defs) ("
duplicate name in globals");
do ab <-
ab_alloc_globals defs;
ret (
snd ab).
Definition validate_volatile_ptr (
sz:
sizes) (
ptr:
BlockSet.t) (
lne:
list (
mexpr cell)) :
bool →
bool :=
BlockSet.fold
(λ
blk (
acc:
bool),
if acc
then
match blk with
|
ABlocal _ _ =>
false
|
ABglobal b =>
match Genv.invert_symbol ge b with
|
None =>
false
|
Some g =>
match ABTreeDom.get blk sz with
|
Just (
hi, (
perm,
vol)) =>
vol
|
All =>
false
end
end
end
else acc)
ptr.
Definition check_volatile (
tgt: (
ident *
int) +
expr) (κ:
memory_chunk) (
ab:
t) :
alarm_mon ident :=
do _ <-
match tgt with
|
inl (
g,
ofs) =>
match Genv.find_symbol ge g with
|
None =>
alarm_am "
check_volatile:
bad global"
|
Some b =>
let b :=
ABglobal b in
match ABTreeDom.get b (
ab_sz ab)
with
|
Just (
hi, (
perm,
vol)) =>
am_assert vol ("
check_volatile:
not volatile")
|
All =>
alarm_am "
check_volatile:
unknown size"
end
end
|
inr addr =>
do z <-
ab_eval_expr ab addr;
match z with
|
NotBot (
tn,
Just ptr,
Just VP,
ne) =>
am_assert (
validate_volatile_ptr (
ab_sz ab)
ptr ne true) ("
check_volatile:
bad pointer")
|
_ =>
alarm_am "
check_volatile:
unresolved expression"
end
end;
match ab_stk ab with
|
Just (
_ :: σ ) =>
ret (
plength σ)
|
_ =>
do _ <-
alarm_am "
check_volatile:
no stack";
ret xH
end.
Definition forget_cell (
ab:
t) (
c:
cell) :
t+⊥ :=
do nm' <-
AbMachineEnv.forget c (
ab_num ab);
NotBot (
with_pt (λ
pt,
ACTreeDom.set pt c All)
(
with_tp (λ
tp,
ACTreeDom.set tp c (⊤))
(
with_num (λ
_,
nm')
ab))).
Definition vload (
rettemp:
option ident) (
g_ofs:
option (
ident *
int)) (κ:
memory_chunk) (
args:
list expr) (
ab:
t) :
alarm_mon (
t+⊥) :=
do _ <-
am_assert match κ
with Mint64 |
Mint32 |
Mfloat32 |
Mfloat64 =>
true |
_ =>
false end "
vload:
bad chunk";
match
match g_ofs,
args with
|
Some q,
nil =>
Some (
inl q)
|
None,
addr ::
nil =>
Some (
inr addr)
|
_,
_ =>
None
end
with
|
None =>
do _ <-
alarm_am "
vload:
bad arguments";
ret Bot
|
Some tgt =>
do μ <-
check_volatile tgt κ
ab;
match rettemp with
|
None =>
ret (
NotBot ab)
|
Some r =>
match κ
with
|
Mint64 =>
assign_any r VL ab
|
Mfloat64 =>
assign_any r VF ab
|
Mfloat32 =>
assign_any r VS ab
|
_ =>
ret (
forget_cell ab (
ACtemp μ
r))
end
end
end.
Definition only_global_pointer (
aptr:
BlockSet.t+⊤) :
bool :=
match aptr with
|
All =>
false
|
Just ptr =>
negb (
BSO.existsb (λ
p,
match p with
|
ABglobal b =>
match Genv.invert_symbol ge b with Some g =>
negb (
Senv.public_symbol ge g) |
None =>
true end
|
ABlocal _ _ =>
true
end)
ptr)
end.
Definition vstore (
rettemp:
option ident) (
g_ofs:
option (
ident *
int)) (κ:
memory_chunk) (
args:
list expr) (
ab:
t) :
alarm_mon (
t+⊥) :=
match
match g_ofs,
args with
|
Some q,
arg ::
nil =>
Some (
inl q,
arg)
|
None,
addr ::
arg ::
nil =>
Some (
inr addr,
arg)
|
_,
_ =>
None
end
with
|
None =>
do _ <-
alarm_am "
vstore:
bad arguments";
ret Bot
|
Some (
tgt,
arg) =>
do μ <-
check_volatile tgt κ
ab;
do v <-
ab_eval_expr ab arg;
match v with
|
Bot =>
ret Bot
|
NotBot (
tn,
ptr,
oty,
lne) =>
do _ <-
am_assert
match oty with
|
Just ty =>
match ty, κ
with
|
VL,
Mint64
|
VS,
Mfloat32
|
VF,
Mfloat64
|
VI, (
Mint32 |
Mint8signed |
Mint8unsigned |
Mint16signed |
Mint16unsigned )
=>
true
| (
VIP|
VP),
Mint32 =>
only_global_pointer ptr
|
_,
_ =>
false
end
|
All =>
false
end
("
vstore:
cannot prove that the argument " ++
to_string arg ++ "
is well-
typed " ++
to_string oty);
let ab :=
with_tnum (λ
_,
tn)
ab in
match rettemp with
|
None =>
ret (
NotBot ab)
|
Some r =>
ret (
forget_cell ab (
ACtemp μ
r))
end
end
end.
Instance widen_mem :
widen_op (
iter_t+⊥) (
t+⊥) :=
{|
widen A B :=
let '(
NUM_it_ret,
NUM_ret) :=
match A with
|
Bot =>
init_iter Bot
|
NotBot (
_, (
_, (
_, (
_,
NUM)))) =>
NUM
end ▽
match B with
|
Bot =>
Bot
|
NotBot (
_, (
_, (
_, (
_,
NUM)))) =>
NotBot NUM
end
in
match B with
|
Bot =>
match A with
|
Bot => (
Bot,
Bot)
|
NotBot (
STK, (
SZ, (
PT, (
TP,
_)))) =>
(
NotBot (
STK, (
SZ, (
PT, (
TP,
NUM_it_ret)))),
do NUM_ret <-
NUM_ret;
ret (
STK, (
SZ, (
PT, (
TP,
NUM_ret)))))
end
|
NotBot (
STK', (
SZ', (
PT', (
TP',
_)))) =>
match A with
|
Bot =>
(
NotBot (
STK', (
SZ', (
PT', (
TP',
NUM_it_ret)))),
do NUM_ret <-
NUM_ret;
ret (
STK', (
SZ', (
PT', (
TP',
NUM_ret)))))
|
NotBot (
STK, (
SZ, (
PT, (
TP,
NUM)))) =>
let STK_ret :=
match STK,
STK'
with
|
Just STK,
Just STK' =>
list_widen join STK STK'
|
_,
_ =>
All
end
in
let SZ_ret :=
sizes_widen SZ SZ'
in
let PT_ret :=
points_to_widen PT PT'
in
let TP_ret :=
types_widen TP TP'
in
(
NotBot (
STK_ret, (
SZ_ret, (
PT_ret, (
TP_ret,
NUM_it_ret)))),
do NUM_ret <-
NUM_ret;
ret (
STK_ret, (
SZ_ret, (
PT_ret, (
TP_ret,
NUM_ret)))))
end
end;
init_iter x :=
do x <-
x;
ret (
ab_stk x, (
ab_sz x, (
ab_pt x, (
ab_tp x,
init_iter (
NotBot (
ab_num x))))))
|}.
Instance widen_mem_correct:
widen_op_correct (
iter_t +⊥) (
t +⊥)
concrete_state.
Proof.
split.
-
intros.
eapply botbind_spec,
H.
intros.
destruct H0;
constructor;
auto.
destruct H3.
split.
auto.
red in H4.
destruct a0 as (? & ? & ? & ? & ?).
destruct H4.
split.
apply H4.
destruct H5 as (ρ' &
A &
B).
eexists.
split.
eauto.
apply init_iter_correct.
auto.
-
unfold widen_mem.
intros x y cs Hcs.
destruct x as [|(
STK &
SZ &
PT &
TP &
NUM)].
contradiction.
destruct Hcs.
destruct H2 as [? [? [ρ' []]]].
simpl.
match goal with
| |-
context [?
A ▽ ?
B] =>
pose proof (
widen_incr A B _ H5);
destruct (
A ▽
B)
end.
unfold ACTree.elt in *.
destruct y as [|(
STK' &
SZ' &
PT' &
TP' &
NUM')].
+
split.
constructor;
auto.
split.
auto.
split.
auto.
eexists.
split.
eauto.
apply H6.
eapply botbind_spec. 2:
apply H6.
constructor;
auto.
split.
auto.
split.
auto.
eexists.
split.
eauto.
apply H7.
+
match goal with
| |-
context [(
match STK with All =>
All |
Just STK0 => @?
A STK0 end)] =>
remember (
match STK with All =>
All |
Just STK0 =>
A STK0 end)
as STK''
end.
cbv beta in HeqSTK''.
unfold top_op in STK''.
assert (γ
STK'' (
fst cs)).
{
destruct STK.
subst.
constructor.
destruct STK'.
subst.
constructor.
subst.
apply list_widen_incr,
H.
intros x y f Hf.
apply join_correct.
auto. }
assert (
STK'' ≠
All →
invariant cs).
{
intros.
apply H0.
destruct STK.
congruence.
discriminate. }
assert (
sizes_gamma ge (
fst cs) (
sizes_widen SZ SZ') (
snd cs)).
{
unfold sizes_widen.
apply sizes_join_correct.
auto. }
assert (
points_to_gamma ge (
fst cs) (
points_to_widen PT PT') (
mem_as_fun ge cs)).
{
apply ACTreeDom.join_tree_correct.
refine _.
auto. }
assert (γ (
types_widen TP TP') (
mem_as_fun ge cs)).
{
apply join_correct.
auto. }
split.
*
constructor.
auto.
auto.
auto.
split.
auto.
split.
auto.
eexists.
split.
eauto.
apply H6.
*
eapply botbind_spec.
constructor.
auto.
auto.
auto.
split.
auto.
split.
auto.
eexists.
split.
eauto.
eauto.
apply H6.
Qed.
Instance mem_cshm_dom :
mem_dom t (
iter_t+⊥) :=
{|
assign :=
assign
;
assign_any :=
assign_any
;
store :=
store
;
assume :=
assume
;
noerror :=
noerror
;
deref_fun :=
deref_fun
;
ab_vload :=
vload
;
ab_vstore :=
vstore
;
push_frame :=
push_frame
;
pop_frame :=
pop_frame
;
ab_malloc sz dst ab :=
do _ <-
alarm_am "
malloc";
ret (⊤)
;
ab_free e ab :=
do _ <-
alarm_am "
free";
ret (⊤)
;
ab_memcpy sz al dst src ab :=
do _ <-
alarm_am ("
memcpy(" ++
to_string sz ++ ", " ++
to_string al ++ ", " ++
to_string dst ++ ", " ++
to_string src ++ ")");
ret (⊤)
;
init_mem :=
init_mem
|}.
Lemma list_gamma_len {
t B} {
G:
gamma_op t B} {
x y} :
list_gamma G x y →
plength x =
plength y.
Proof.
Instance t_join_correct :
join_op_correct t (
t+⊥)
concrete_state.
Proof.
Instance t_leb_correct :
leb_op_correct t concrete_state.
Proof.
intros (
stk &
sz &
pt &
tpnm) (
stk' &
sz' &
pt' &
tpnm')
LE (σ &
m) [
STK INV SZ (
PT &
NUM) ].
unfold WProd.leb_prod,
leb in LE.
simpl in *.
unfold leb in LE.
simpl in *.
unfold leb in LE.
simpl in *.
repeat rewrite andb_true_iff in LE.
destruct LE as (
LEstk &
LEsz &
LEpt &
LEnm).
constructor.
simpl.
eapply leb_correct;
eauto.
simpl.
destruct stk'
as [|
stk'].
intuition.
intros _.
apply INV.
destruct stk.
simpl in LEstk.
eq_some_inv.
discriminate.
simpl.
eapply leb_correct;
eauto.
split.
simpl.
eapply leb_correct;
eauto.
eapply leb_correct;
eauto.
Qed.
Instance TToString :
ToString t :=
(λ
x,
"
Mem { " ++ "
stack : " ++
to_string (
ab_stk x) ++
new_line
++ "
blocks: " ++
to_string (
ab_sz x) ++
new_line
++ "
points: " ++
to_string (
ab_pt x) ++
new_line
++ "
types : " ++
to_string (
ab_tp x) ++
new_line
++ "
num : " ++
to_string (
ab_num x) ++
new_line
++ "}" ++
new_line ).
Instance IterTToString :
ToString iter_t :=
(λ
x,
"
Mem { " ++ "
stack : " ++
to_string (
ab_stk_iter x) ++
new_line
++ "
blocks: " ++
to_string (
ab_sz_iter x) ++
new_line
++ "
points: " ++
to_string (
ab_pt_iter x) ++
new_line
++ "
types : " ++
to_string (
ab_tp_iter x) ++
new_line
++ "
num : " ++
to_string (
ab_num_iter x) ++
new_line
++ "}" ++
new_line ).
End num.