CCCPP.v: Copyright 2010 Tahina Ramananandro
Require Import LibLists.
Require Import Cplusconcepts.
Require Import Coqlib.
Require Import Tactics.
Require Import CplusWf.
Require Import LibMaps.
Require Import LayoutConstraints.
Require Import LibPos.
Require Import CPP.
Require Import Dynamic.
Require Import DynamicWf.
Load Param.
The proof of correctness of a layout algorithm optimized for empty base tail padding (POPL 2011, Section 6.2)
Section Compcert.
Variable (
A :
ATOM.t).
Empty classes
A class is empty if, and only if, all the following conditions hold:
-
it has no scalar fields
-
all its structure fields are of an empty class type
-
it has no virtual methods
-
it has no virtual bases
-
all its direct non-virtual bases are empty
Section Is_empty.
Variable hierarchy :
PTree.t (
Class.t A).
Inductive is_empty :
ident ->
Prop :=
|
is_empty_intro :
forall ci c
(
H_ci_c :
hierarchy !
ci =
Some c)
(
H_fields_struct :
forall f,
In f (
Class.fields c) ->
exists e,
exists he,
FieldSignature.type f =
FieldSignature.Struct e he)
(
H_fields_struct_empty :
forall f,
In f (
Class.fields c) ->
forall e he,
FieldSignature.type f =
FieldSignature.Struct e he ->
is_empty e)
(
H_no_virtual_methods :
forall m,
In m (
Class.methods c) ->
Method.virtual m =
true ->
False)
(
H_no_virtual_bases :
forall b,
In (
Class.Inheritance.Shared,
b) (
Class.super c) ->
False)
(
H_bases_empty :
forall b,
In (
Class.Inheritance.Repeated,
b) (
Class.super c) ->
is_empty b),
is_empty ci
.
This definition meets the constraints for empty classes stated in 4.3
Lemma is_empty_prop :
Is_empty.prop hierarchy is_empty.
Proof.
constructor.
inversion 1; congruence.
inversion 1. intros until 1. replace c0 with c in * by congruence. assumption.
inversion 1. intros until 1. replace c0 with c in * by congruence. assumption.
inversion 1; intros; subst. replace c0 with c in * by congruence.
destruct h.
eauto.
destruct (H_no_virtual_bases b).
assumption.
Qed.
Lemma dynamic_nonempty :
forall i,
is_dynamic hierarchy i ->
is_empty i ->
False.
Proof.
induction 1 ; inversion 1 ; subst ; replace c0 with c in * by congruence.
destruct H_methods.
destruct H0.
eauto.
eauto.
destruct h ; eauto.
Qed.
Hypothesis hierarchy_wf :
Well_formed_hierarchy.prop hierarchy.
Lemma no_virtual_bases :
forall ci,
is_empty ci ->
forall vb,
is_virtual_base_of hierarchy vb ci ->
False.
Proof.
intros.
revert H.
induction H0.
inversion 1;
subst.
replace c0 with c in *
by congruence.
eauto.
intros.
apply IHis_virtual_base_of.
inversion H2.
subst.
replace c0 with c in *
by congruence.
destruct h'.
eauto.
apply False_rect.
eauto.
Qed.
Definition is_empty_dec :
forall i, {
is_empty i} + {~
is_empty i}.
Proof.
End Is_empty.
Definition Optim :=
CPP.Optim (
CppOptim is_empty_prop dynamic_nonempty).
Variable (
PF :
PLATFORM A).
Section LD.
Overview of the layout algorithm
Computed values
Apart from the values expected in 4.1 and computed in offsets, this algorithm computes the ebo and nvebo sets of empty base offsets and non-virtual empty base offsets, incrementally as in 4.5.5. cilimit is the identifier of the class being laid out.
Record LD :
Type :=
Ld {
offsets :
PTree.t (
LayoutConstraints.t A);
cilimit :
ident;
ebo :
PTree.t (
list (
ident *
Z));
nvebo :
PTree.t (
list (
ident *
Z))
}.
Section prop.
Variable hierarchy :
PTree.t (
Class.t A).
Variable o :
LD.
Invariant
Record prop :
Prop :=
intro {
Guard
offsets_guard :
forall ci, (
offsets o) !
ci <>
None ->
hierarchy !
ci <>
None;
Section 4
offsets_intro :
forall ci of, (
offsets o) !
ci =
Some of ->
class_level_prop Optim PF (
offsets o)
hierarchy ci of
;
Guard
offsets_guard2 :
forall ci, (
offsets o) !
ci <>
None ->
Plt ci (
cilimit o);
offsets_exist :
forall ci,
Plt ci (
cilimit o) ->
hierarchy !
ci <>
None -> (
offsets o) !
ci <>
None
;
4.5.5 for empty bases
disjoint_ebo :
forall ci o', (
offsets o) !
ci =
Some o' ->
disjoint_empty_base_offsets Optim (
offsets o)
hierarchy ci o'
;
Specification and guard conditions for ebo, nvebo the sets of (non-virtual) empty base offsets
ebo_prop :
forall ci e, (
ebo o) !
ci =
Some e ->
forall b o', (
In (
b,
o')
e <->
empty_base_offset Optim (
offsets o)
hierarchy ci b o')
;
ebo_exist :
forall ci,
Plt ci (
cilimit o) -> (
ebo o) !
ci <>
None
;
ebo_guard :
forall ci, (
ebo o) !
ci <>
None ->
Plt ci (
cilimit o)
;
nvebo_prop :
forall ci e, (
nvebo o) !
ci =
Some e ->
forall b o', (
In (
b,
o')
e <->
non_virtual_empty_base_offset Optim (
offsets o)
hierarchy ci b o')
;
nvebo_exist :
forall ci,
Plt ci (
cilimit o) -> (
nvebo o) !
ci <>
None;
nvebo_guard :
forall ci, (
nvebo o) !
ci <>
None ->
Plt ci (
cilimit o)
}.
End prop.
End LD.
Hint Resolve offsets_guard offsets_intro offsets_exist disjoint_ebo ebo_prop ebo_exist nvebo_prop nvebo_exist.
Section Layout.
Variable hierarchy :
PTree.t (
Class.t A).
Hypothesis hierarchy_wf :
Well_formed_hierarchy.prop hierarchy.
Let virtual_bases :=
let (
t,
_) :=
Well_formed_hierarchy.virtual_bases hierarchy_wf in t.
Let virtual_bases_prop : (
forall cn,
hierarchy !
cn <>
None ->
virtual_bases !
cn <>
None) /\
forall cn l,
virtual_bases !
cn =
Some l ->
forall i, (
In i l <->
is_virtual_base_of hierarchy i cn)
.
Proof.
Incremental layout
The identifier of the class being laid out is LD.cilimit ld. All classes with an identifier less that LD.cilimit ld are assumed to be already laid out.
Section Step.
Variable ld :
LD.
Hypothesis Hld :
prop hierarchy ld.
Section Def.
Variable h :
Class.t A.
Hypothesis Hh :
hierarchy ! (
cilimit ld) =
Some h.
Layout of non-virtual direct bases
Section Non_virtual_direct_base_layout.
-
nvl_todo: the list of non-virtual direct bases to which an offset has not yet been assigned
-
nvl_offsets: the mapping between non-virtual direct bases and offsets
-
nvl_nvebo: the set of non-virtual empty base offsets reachable through a direct non-virtual base that has already been assigned an offset
-
nvl_nvds: the non-virtual data size so far. This is also the field boundary so far (because fields will be laid out no sooner than after the last non-virtual direct base).
-
nvl_nvsize: the non-virtual size so far.
-
nvl_pbase: the primary base, if any
-
nvl_align: the non-virtual alignment so far
Record nvl :
Set :=
make_nvl {
nvl_todo :
list ident;
nvl_offsets :
PTree.t Z;
nvl_nvebo :
list (
ident *
Z);
nvl_nvds :
Z;
nvl_nvsize :
Z;
nvl_pbase :
option ident;
nvl_align :
Z
}.
Section prop.
Variable nvldata :
nvl.
Record nvl_prop :
Prop :=
nvl_intro {
Guard
nvl_exist :
forall ci, (
In (
Class.Inheritance.Repeated,
ci) (
Class.super h) <-> ((
nvl_offsets nvldata) !
ci <>
None \/
In ci (
nvl_todo nvldata)));
C21
nvl_primary_base :
forall ci,
nvl_pbase nvldata =
Some ci -> (
nvl_offsets nvldata) !
ci =
Some 0;
4.3
nvl_primary_base_dynamic :
forall ci,
nvl_pbase nvldata =
Some ci ->
is_dynamic hierarchy ci;
Guard
nvl_data_low_bound : 0 <=
nvl_nvds nvldata;
C19
nvl_data_dynamic_low_bound :
is_dynamic hierarchy (
cilimit ld) ->
dynamic_type_data_size PF <=
nvl_nvds nvldata;
C5
nvl_size_pos : 0 <
nvl_nvsize nvldata;
Guard
nvl_low_bound :
forall ci of, (
nvl_offsets nvldata) !
ci =
Some of -> 0 <=
of;
C20
nvl_dynamic_no_primary_low_bound :
is_dynamic hierarchy (
cilimit ld) ->
nvl_pbase nvldata =
None ->
forall ci, (
is_empty hierarchy ci ->
False) ->
forall of, (
nvl_offsets nvldata) !
ci =
Some of ->
dynamic_type_data_size PF <=
of;
C6
nvl_nonempty_non_overlap :
forall ci1 o1, (
nvl_offsets nvldata) !
ci1 =
Some o1 -> (
is_empty hierarchy ci1 ->
False) ->
forall ci2 o2, (
nvl_offsets nvldata) !
ci2 =
Some o2 -> (
is_empty hierarchy ci2 ->
False) ->
ci1 <>
ci2 ->
forall of1, (
offsets ld) !
ci1 =
Some of1 ->
forall of2, (
offsets ld) !
ci2 =
Some of2 ->
o1 +
non_virtual_data_size of1 <=
o2 \/
o2 +
non_virtual_data_size of2 <=
o1;
C23
nvl_disjoint_empty_bases :
forall ci1 o1, (
nvl_offsets nvldata) !
ci1 =
Some o1 ->
forall ci2 o2, (
nvl_offsets nvldata) !
ci2 =
Some o2 ->
ci1 <>
ci2 ->
forall b bo1,
non_virtual_empty_base_offset Optim (
offsets ld)
hierarchy ci1 b bo1 ->
forall bo2,
non_virtual_empty_base_offset Optim (
offsets ld)
hierarchy ci2 b bo2 ->
o1 +
bo1 <>
o2 +
bo2;
C7
nvl_nonempty_high_bound :
forall ci, (
is_empty hierarchy ci ->
False) ->
forall of, (
nvl_offsets nvldata) !
ci =
Some of ->
forall o', (
offsets ld) !
ci =
Some o' ->
of +
non_virtual_data_size o' <=
nvl_nvds nvldata;
C1
nvl_high_bound :
forall ci,
forall of, (
nvl_offsets nvldata) !
ci =
Some of ->
forall o', (
offsets ld) !
ci =
Some o' ->
of +
non_virtual_size o' <=
nvl_nvsize nvldata;
Guard
nvl_align_pos : 0 <
nvl_align nvldata;
C16
nvl_align_dynamic :
is_dynamic hierarchy (
cilimit ld) -> (
dynamic_type_data_align PF |
nvl_align nvldata);
C15
nvl_align_prop :
forall ci, (
nvl_offsets nvldata) !
ci <>
None ->
forall of, (
offsets ld) !
ci =
Some of -> (
non_virtual_align of |
nvl_align nvldata);
nvl_offset_align :
forall ci of, (
nvl_offsets nvldata) !
ci =
Some of ->
forall co, (
offsets ld) !
ci =
Some co -> (
non_virtual_align co |
of);
Specification of nvl_nvebo non-virtual empty base offsets
nvl_nvebo_prop :
forall b o, (
In (
b,
o) (
nvl_nvebo nvldata) <->
exists ci,
exists of, (
nvl_offsets nvldata) !
ci =
Some of /\
non_virtual_empty_base_offset Optim (
offsets ld)
hierarchy ci b (
o -
of))
}.
End prop.
Section Step.
Variable nvldata :
nvl.
Hypothesis prop :
nvl_prop nvldata.
Trying to assign an offset to the non-virtual direct base a of cilimit ld
Variable a :
ident.
Variable q :
list ident.
Hypothesis Htodo :
nvl_todo nvldata =
a ::
q.
Hypothesis undef: (
nvl_offsets nvldata) !
a =
None.
Let son :
In (
Class.Inheritance.Repeated,
a) (
Class.super h).
Proof.
destruct (
nvl_exist prop a).
apply H0.
rewrite Htodo.
auto.
Qed.
Let Hlt : (
Plt a (
cilimit ld)).
Proof.
Let orig_offset : {
o' | (
offsets ld) !
a =
Some o'}.
Proof.
Let o' :=
let (
o',
_) :=
orig_offset in o'.
Let Ho' : (
offsets ld) !
a =
Some o'.
Proof.
unfold o'.
destruct orig_offset.
assumption.
Qed.
Let e0 : {
e | (
nvebo ld) !
a =
Some e}.
Proof.
generalize (
nvebo_exist (
Hld)
Hlt).
case_eq ((
nvebo ld) !
a);
try congruence.
intros.
repeat esplit.
Qed.
Let e :=
let (
e,
_) :=
e0 in e.
Let He : (
nvebo ld) !
a =
Some e.
Proof.
unfold e.
destruct e0.
assumption.
Qed.
The offset
nv_offset assigned to
a is computed as follows:
-
starting from 0 if a is empty, from nvl_nvds nvldata (the non-virtual data size so far) otherwise
-
find the least offset o multiple of the non-virtual alignment of a, and such that the set e of non-virtual empty base offsets reachable from a is disjoint from nvl_nvebo the offsets of non-virtual empty base offsets so far, knowing that there will be no conflict if o >= nvl_nvsize nvldata
See LibPos for a definition of bounded_offset.
Let em :=
is_empty_dec hierarchy_wf a.
Let f z (
x :
_ *
_) :=
let (
b,
o) :=
x in
if In_dec (
prod_eq_dec peq Z_eq_dec) (
b,
z +
o) (
nvl_nvebo nvldata)
then true else false.
Let align_pos : 0 <
non_virtual_align o'.
Proof.
Let f'
z :=
match List.filter (
f z)
e with
|
nil =>
true
|
_ =>
false
end.
Definition nv_offset :=
let (
z,
_) :=
bounded_offset align_pos (
if em then 0
else nvl_nvds nvldata) (
nvl_nvsize nvldata)
f'
in z.
Lemma nv_offsets_non_overlap :
forall ci co, (
nvl_offsets nvldata) !
ci =
Some co ->
forall b bo,
non_virtual_empty_base_offset Optim (
offsets ld)
hierarchy ci b bo ->
forall bo',
non_virtual_empty_base_offset Optim (
offsets ld)
hierarchy a b bo' ->
co +
bo <>
nv_offset +
bo'.
Proof.
Lemma nv_offset_low_bound : 0 <=
nv_offset.
Proof.
Lemma nv_offset_align : (
non_virtual_align o' |
nv_offset).
Proof.
Lemma nv_offset_nonempty_low_bound : (
is_empty hierarchy a ->
False) ->
nvl_nvds nvldata <=
nv_offset.
Proof.
unfold nv_offset.
destruct (
bounded_offset align_pos (
if em then 0
else nvl_nvds nvldata) (
nvl_nvsize nvldata)
f').
revert a0.
case em.
contradiction.
tauto.
Qed.
Let g :=
map_snd (
key :=
ident) (
fun o =>
nv_offset +
o).
Update the data to assign nv_offset to the non-virtual base.
Definition non_virtual_direct_base_layout_step : {
nvldata' |
nvl_prop nvldata' /\
nvl_todo nvldata' =
q
}.
exists (
make_nvl
remove a from nvl_todo = a :: q
q
assign nv_offset to a
(
PTree.set a nv_offset (
nvl_offsets nvldata))
add non-virtual empty base offsets of a to nvl_nvebo
(
List.map g e ++
nvl_nvebo nvldata)
update data size if a is not empty
(
if em then nvl_nvds nvldata else (
nv_offset +
non_virtual_data_size o'))
update size to the max
(
if Z_le_dec (
nv_offset +
non_virtual_size o') (
nvl_nvsize nvldata)
then (
nvl_nvsize nvldata)
else (
nv_offset +
non_virtual_size o'))
keep the same primary base
(
nvl_pbase nvldata)
update alignment to the least common multiple
(
lcm (
nvl_align nvldata) (
non_virtual_align o'))
).
Proof.
End Step.
Finalization: if at some point, some direct non-virtual bases have already been assigned an offset, then the following lemma tells how to deal with all the remaining direct non-virtual bases
Definition non_virtual_direct_base_layout_end :
forall nvldata,
nvl_prop nvldata -> {
nvldata' |
nvl_prop nvldata' /\
nvl_todo nvldata' =
nil
}.
Proof.
intro.
var (
nvl_todo nvldata).
revert v nvldata H.
induction v.
intros.
exists nvldata.
split.
assumption.
assumption.
intros.
case_eq ((
nvl_offsets nvldata) !
a).
intros.
apply (
IHv (
make_nvl
v
(
nvl_offsets nvldata)
(
nvl_nvebo nvldata)
(
nvl_nvds nvldata)
(
nvl_nvsize nvldata)
(
nvl_pbase nvldata)
(
nvl_align nvldata)
)).
reflexivity.
inversion x.
constructor;
simpl;
try trivial.
intros.
rewrite H in nvl_exist0.
simpl in nvl_exist0.
destruct (
nvl_exist0 ci).
split.
destruct (
peq a ci).
subst.
intros.
left.
congruence.
tauto.
tauto.
intros.
destruct (
non_virtual_direct_base_layout_step x H).
assumption.
destruct a0.
eauto.
Qed.
Initialization.
Section Init.
Let f (
x :
_ *
ident) :=
match x with
| (
Class.Inheritance.Repeated,
b) =>
b ::
nil
|
_ =>
nil
end.
Let nvbases :=
flatten (
map f (
Class.super h)).
Let g b :=
if is_dynamic_dec hierarchy_wf b then true else false
.
Let dynbases :=
filter g nvbases.
There is a direct non-virtual primary base a of cilimit ld: choose it as the primary base
Section Primary_base.
Variable a :
ident.
Variable q :
list ident.
Hypothesis some_dynbase :
dynbases =
a ::
q.
Lemma nveb_inh :
In (
Class.Inheritance.Repeated,
a) (
Class.super h).
Proof.
destruct (
filter_In g a nvbases).
unfold dynbases in some_dynbase.
rewrite some_dynbase in H.
destruct (
H (
or_introl _ (
refl_equal _))).
destruct (
member_flatten_elim H1).
destruct H3.
destruct (
list_in_map_inv _ _ _ H3).
destruct H5.
destruct x0.
subst.
destruct t;
simpl in H4;
try contradiction.
inversion H4;
try contradiction.
subst.
assumption.
Qed.
Let inh :=
nveb_inh.
Lemma nveb_dyn :
is_dynamic hierarchy a.
Proof.
destruct (
filter_In g a nvbases).
unfold dynbases in some_dynbase.
rewrite some_dynbase in H.
destruct (
H (
or_introl _ (
refl_equal _))).
unfold g in H2.
destruct (
is_dynamic_dec hierarchy_wf a).
assumption.
discriminate.
Qed.
Let dyn :=
nveb_dyn.
Let Hlt :
Plt a (
cilimit ld).
Proof.
Let of'0 : {
of' | (
offsets ld) !
a =
Some of'}.
Proof.
Let of' :=
let (
of',
_) :=
of'0
in of'.
Let Hof' : (
offsets ld) !
a =
Some of'.
Proof.
unfold of'.
destruct of'0.
assumption.
Qed.
Let e0 : {
e | (
nvebo ld) !
a =
Some e}.
Proof.
generalize (
nvebo_exist (
Hld)
Hlt).
case_eq ((
nvebo ld) !
a);
try congruence.
intros.
repeat esplit.
Qed.
Let e :=
let (
e,
_) :=
e0 in e.
Let He : (
nvebo ld) !
a =
Some e.
Proof.
unfold e.
destruct e0.
assumption.
Qed.
Let ne :
is_empty hierarchy a ->
False.
Proof.
Definition nvl_init_some_primary_base : {
nv |
nvl_prop nv
}.
exists (
make_nvl
nvbases
(
PTree.set a 0 (
PTree.empty _))
e
(
non_virtual_data_size of')
(
non_virtual_size of')
(
Some a)
(
non_virtual_align of')
).
Proof.
End Primary_base.
The class is dynamic, but has no primary base
Section No_primary_base.
Section Dynamic.
Hypothesis dyn :
is_dynamic hierarchy (
cilimit ld).
Definition nvl_init_dynamic_no_primary_base : {
nv |
nvl_prop nv
}.
exists (
make_nvl
nvbases
(
PTree.empty _)
nil
(
dynamic_type_data_size PF)
(
dynamic_type_data_size PF)
None
(
dynamic_type_data_align PF)
).
Proof.
End Dynamic.
The class is not dynamic
Section Non_dynamic.
Hypothesis dyn :
is_dynamic hierarchy (
cilimit ld) ->
False.
Definition nvl_init_non_dynamic : {
nv |
nvl_prop nv
}.
exists (
make_nvl
nvbases
(
PTree.empty _)
nil
0
1
None
1
).
Proof.
End Non_dynamic.
End No_primary_base.
Finally, pack all together
Definition non_virtual_direct_base_layout : {
nvldata |
nvl_prop nvldata /\
nvl_todo nvldata =
nil
}.
Proof.
End Init.
End Non_virtual_direct_base_layout.
Let nvldata be the layout of direct non-virtual bases. Then, nvl_nvdsize nvldata, the data size so far before laying out fields, is the field boundary.
Let nvldata :=
let (
k,
_) :=
non_virtual_direct_base_layout in k.
Let H_nvldata :
nvl_prop nvldata.
Proof.
Let H_nvldata_2 :
nvl_todo nvldata =
nil.
Proof.
Layout of fields
Section Field_layout.
-
fl_todo: the list of fields to which an offset has not yet been assigned
-
fl_offsets: the mapping between fields and offsets
-
fl_ebo: the set of empty base offsets reachable through a field that has already been assigned an offset
-
fl_nvds: the non-virtual data size so far.
-
fl_nvsize: the non-virtual size so far.
-
fl_align: the non-virtual alignment so far.
Record fl :
Type :=
make_fl {
fl_todo :
list (
FieldSignature.t A);
fl_offsets :
list (
FieldSignature.t A *
Z);
fl_ebo :
list (
ident *
Z);
fl_nvds :
Z;
fl_nvsize :
Z;
fl_align :
Z
}.
Section prop.
Variable fldata :
fl.
Record fl_prop :
Prop :=
fl_intro {
Guard
fl_exist :
forall fs, (
In fs (
Class.fields h) <-> (
assoc (
FieldSignature.eq_dec (
A :=
A))
fs (
fl_offsets fldata) <>
None \/
In fs (
fl_todo fldata)));
C11
fl_data_low_bound :
nvl_nvds nvldata <=
fl_nvds fldata;
Helper for C1
fl_size_low_bound :
nvl_nvsize nvldata <=
fl_nvsize fldata;
Guard
fl_low_bound :
forall fs of,
assoc (
FieldSignature.eq_dec (
A :=
A))
fs (
fl_offsets fldata) =
Some of -> 0 <=
of;
C8
fl_nonempty_low_bound :
forall fs of,
assoc (
FieldSignature.eq_dec (
A :=
A))
fs (
fl_offsets fldata) =
Some of -> (
forall ty n,
FieldSignature.type fs =
FieldSignature.Struct ty n ->
is_empty hierarchy ty ->
False) ->
nvl_nvds nvldata <=
of;
C9
fl_non_overlap :
forall fs1 o1,
assoc (
FieldSignature.eq_dec (
A :=
A))
fs1 (
fl_offsets fldata) =
Some o1 -> (
forall ty n,
FieldSignature.type fs1 =
FieldSignature.Struct ty n ->
is_empty hierarchy ty ->
False) ->
forall fs2 o2,
assoc (
FieldSignature.eq_dec (
A :=
A))
fs2 (
fl_offsets fldata) =
Some o2 ->
fs1 <>
fs2 -> (
forall ty n,
FieldSignature.type fs2 =
FieldSignature.Struct ty n ->
is_empty hierarchy ty ->
False) ->
forall s1,
field_data_size PF (
offsets ld)
fs1 =
Some s1 ->
forall s2,
field_data_size PF (
offsets ld)
fs2 =
Some s2 ->
o1 +
s1 <=
o2 \/
o2 +
s2 <=
o1;
C24
fl_disjoint_empty_bases :
forall fs1 o1,
assoc (
FieldSignature.eq_dec (
A :=
A))
fs1 (
fl_offsets fldata) =
Some o1 ->
forall ci1 p1,
FieldSignature.type fs1 =
FieldSignature.Struct ci1 p1 ->
forall z1, 0 <=
z1 ->
z1 <
Zpos p1 ->
forall so1, (
offsets ld) !
ci1 =
Some so1 ->
forall b bo1,
empty_base_offset Optim (
offsets ld)
hierarchy ci1 b bo1 ->
forall ci2 o2, (
nvl_offsets nvldata) !
ci2 =
Some o2 ->
forall bo2,
non_virtual_empty_base_offset Optim (
offsets ld)
hierarchy ci2 b bo2 ->
o1 +
z1 *
size so1 +
bo1 <>
o2 +
bo2;
C25
fl_disjoint_empty_bases_fields :
forall fs1 o1,
assoc (
FieldSignature.eq_dec (
A :=
A))
fs1 (
fl_offsets fldata) =
Some o1 ->
forall ci1 p1,
FieldSignature.type fs1 =
FieldSignature.Struct ci1 p1 ->
forall z1, 0 <=
z1 ->
z1 <
Zpos p1 ->
forall so1, (
offsets ld) !
ci1 =
Some so1 ->
forall b bo1,
empty_base_offset Optim (
offsets ld)
hierarchy ci1 b bo1 ->
forall fs2 o2,
assoc (
FieldSignature.eq_dec (
A :=
A))
fs2 (
fl_offsets fldata) =
Some o2 ->
forall ci2 p2,
FieldSignature.type fs2 =
FieldSignature.Struct ci2 p2 ->
forall z2, 0 <=
z2 ->
z2 <
Zpos p2 ->
forall so2, (
offsets ld) !
ci2 =
Some so2 ->
forall bo2,
empty_base_offset Optim (
offsets ld)
hierarchy ci2 b bo2 ->
fs1 <>
fs2 ->
o1 +
z1 *
size so1 +
bo1 <>
o2 +
z2 *
size so2 +
bo2;
C10
fl_nonempty_high_bound :
forall fs of,
assoc (
FieldSignature.eq_dec (
A :=
A))
fs (
fl_offsets fldata) =
Some of -> (
forall ty n,
FieldSignature.type fs =
FieldSignature.Struct ty n ->
is_empty hierarchy ty ->
False) ->
forall s,
field_data_size PF (
offsets ld)
fs =
Some s ->
of +
s <=
fl_nvds fldata;
C2
fl_high_bound :
forall fs of,
assoc (
FieldSignature.eq_dec (
A :=
A))
fs (
fl_offsets fldata) =
Some of ->
forall s,
field_size PF (
offsets ld)
fs =
Some s ->
of +
s <=
fl_nvsize fldata;
Guard
fl_align_pos : 0 <
fl_align fldata;
Helper for C15 and C16
fl_align_nvl : (
nvl_align nvldata |
fl_align fldata);
C14
fl_align_prop :
forall fs,
assoc (
FieldSignature.eq_dec (
A :=
A))
fs (
fl_offsets fldata) <>
None ->
forall al,
field_align PF (
offsets ld)
fs =
Some al -> (
al |
fl_align fldata);
fl_offset_align :
forall fs fo,
assoc (
FieldSignature.eq_dec (
A :=
A))
fs (
fl_offsets fldata) =
Some fo ->
forall al,
field_align PF (
offsets ld)
fs =
Some al -> (
al |
fo);
Specification of fl_ebo, the set of the empty base offsets reachable through a field of cilimit ld
fl_ebo_prop :
forall b o, (
In (
b,
o) (
fl_ebo fldata) <->
exists fs,
exists of,
assoc (
FieldSignature.eq_dec (
A :=
A))
fs (
fl_offsets fldata) =
Some of /\
exists ci,
exists n,
FieldSignature.type fs =
FieldSignature.Struct ci n /\
exists i, 0 <=
i /\
i <
Zpos n /\
exists oo, (
offsets ld) !
ci =
Some oo /\
empty_base_offset Optim (
offsets ld)
hierarchy ci b (
o -
of -
i *
size oo))
}.
End prop.
Section Step.
Variable fldata :
fl.
Hypothesis prop :
fl_prop fldata.
Trying to assign an offset to the field fs0 of cilimit ld
Variable fs0 :
FieldSignature.t A.
Variable q :
list (
FieldSignature.t A).
Hypothesis Htodo :
fl_todo fldata =
fs0 ::
q.
Hypothesis undef:
assoc (
FieldSignature.eq_dec (
A :=
A))
fs0 (
fl_offsets fldata) =
None.
Let son :
In fs0 (
Class.fields h).
Proof.
destruct (
fl_exist prop fs0).
apply H0.
rewrite Htodo.
auto.
Qed.
fs0 is a structure array field of type a
Section Struct.
Variable a :
ident.
Variable na :
positive.
Hypothesis Hstruct :
FieldSignature.type fs0 =
FieldSignature.Struct a na.
Let Hlt : (
Plt a (
cilimit ld)).
Proof.
Definition fstruct_orig_offset : {
o' | (
offsets ld) !
a =
Some o'}.
Proof.
Let o' :=
let (
o',
_) :=
fstruct_orig_offset in o'.
Let Ho' : (
offsets ld) !
a =
Some o'.
Proof.
Definition fstruct_e0 : {
e | (
ebo ld) !
a =
Some e}.
Proof.
generalize (
ebo_exist (
Hld)
Hlt).
case_eq ((
ebo ld) !
a);
try congruence.
intros.
repeat esplit.
Qed.
Let e :=
let (
e,
_) :=
fstruct_e0 in e.
Let He : (
ebo ld) !
a =
Some e.
Proof.
fstruct_e'0_aux constructs the union of all << j * sizeof(a) + ebo(a) >> for each j such that 0 <= j < n
Definition fstruct_e'0
_aux :
forall k, 0 <=
k -> 0 <=
k <=
Zpos na ->
forall l, (
forall b o,
In (
b,
o)
l <->
exists j, 0 <=
j /\
j <
Zpos na -
k /\
In (
b,
o -
j *
size o')
e) ->
{
l |
forall b o,
In (
b,
o)
l <->
exists j, 0 <=
j /\
j <
Zpos na /\
In (
b,
o -
j *
size o')
e}.
Proof.
intros until 1.
pattern k.
eapply Z_lt_rec;
try eassumption.
intros.
clear k H.
destruct (
Z_eq_dec x 0).
subst.
replace (
Zpos na - 0)
with (
Zpos na)
in H2 by omega.
exists l;
assumption.
assert (0 <=
x - 1 <=
Zpos na)
by omega.
assert (0 <=
x - 1 <
x)
by omega.
apply (
H0 _ H3 H (
map (
map_snd (
fun o =>
o + (
Zpos na -
x) *
size o'))
e ++
l)).
intros.
assert (
forall A B C :
Prop, (
A <->
B) -> (
B <->
C) -> (
A <->
C))
by tauto.
refine (
H4 _ _ _ (
in_app (
b,
o)
_ _)
_).
split.
destruct 1.
destruct (
list_in_map_inv _ _ _ H5).
destruct H6.
destruct x0.
Opaque Zmult Zplus Zminus.
simpl in H6.
injection H6;
intros;
subst.
exists (
Zpos na -
x).
split.
Transparent Zminus.
omega.
split.
omega.
replace (
z + (
Zpos na -
x) *
size o' - (
Zpos na -
x) *
size o')
with z by omega.
assumption.
destruct (
H2 b o).
destruct (
H6 H5).
destruct H8.
destruct H9.
exists x0.
split.
omega.
split.
omega.
assumption.
destruct 1.
destruct H5.
destruct H6.
pattern (
b,
o)
at 1.
replace (
b,
o)
with (
map_snd (
fun o0 =>
o0 + (
Zpos na -
x) *
size o') (
b,
o - (
Zpos na -
x) *
size o')).
destruct (
Z_eq_dec x0 (
Zpos na -
x)).
subst.
left.
apply in_map.
assumption.
right.
destruct (
H2 b o).
apply H9.
exists x0.
split.
omega.
split.
omega.
assumption.
Opaque Zminus.
simpl.
f_equal.
Transparent Zminus.
omega.
Qed.
Definition fstruct_e'0 :
{
l |
forall b o,
In (
b,
o)
l <->
exists j, 0 <=
j /\
j <
Zpos na /\
In (
b,
o -
j *
size o')
e}.
Proof.
Let e' :=
let (
e',
_) :=
fstruct_e'0
in e'.
Let He' :
forall b o,
In (
b,
o)
e' <->
exists j, 0 <=
j /\
j <
Zpos na /\
In (
b,
o -
j *
size o')
e.
Proof.
unfold e'.
destruct fstruct_e'0.
assumption.
Qed.
The offset
fl_offset assigned to
fs0 is computed as follows:
-
starting from 0 if fs0 is empty, from fl_nvds fldata (the non-virtual data size so far) otherwise
-
find the least offset o multiple of the alignment of a, and such that the set e' of empty base offsets reachable from any cell of the array of a is disjoint from nvl_nvebo the offsets of non-virtual empty base offsets so far, and from fl_ebo the empty base offsets reachable from other fields so far, knowing that there will be no conflict if o >= fl_nvsize fldata
See LibPos for a definition of bounded_offset.
Let em :=
is_empty_dec hierarchy_wf a.
Let f z (
x :
_ *
_) :=
let (
b,
o) :=
x in
if In_dec (
prod_eq_dec peq Z_eq_dec) (
b,
z +
o) (
nvl_nvebo nvldata)
then true else
if In_dec (
prod_eq_dec peq Z_eq_dec) (
b,
z +
o) (
fl_ebo fldata)
then true else
false.
Definition fstruct_off0 : {
z | (
if em then 0
else fl_nvds fldata) <=
z /\ (
align o' |
z) /\ (
fl_nvsize fldata <=
z \/
List.filter (
f z)
e' =
nil)}.
Proof.
Definition fl_offset :=
let (
z,
_) :=
fstruct_off0 in z.
Lemma fl_offset_prop : (
if em then 0
else fl_nvds fldata) <=
fl_offset /\ (
align o' |
fl_offset) /\ (
fl_nvsize fldata <=
fl_offset \/
List.filter (
f fl_offset)
e' =
nil).
Proof.
Lemma fl_offsets_non_overlap :
forall ci co, (
nvl_offsets nvldata) !
ci =
Some co ->
forall b bo,
non_virtual_empty_base_offset Optim (
offsets ld)
hierarchy ci b bo ->
forall i, 0 <=
i ->
i <
Zpos na ->
forall bo',
empty_base_offset Optim (
offsets ld)
hierarchy a b bo' ->
co +
bo <>
fl_offset +
i *
size o' +
bo'.
Proof.
Lemma fl_disjoint_field_empty_bases :
forall z1, 0 <=
z1 ->
z1 <
Zpos na ->
forall b bo1,
empty_base_offset Optim (
offsets ld)
hierarchy a b bo1 ->
forall fs2 o2,
assoc (
FieldSignature.eq_dec (
A :=
A))
fs2 (
fl_offsets fldata) =
Some o2 ->
forall ci2 p2,
FieldSignature.type fs2 =
FieldSignature.Struct ci2 p2 ->
forall z2, 0 <=
z2 ->
z2 <
Zpos p2 ->
forall so2, (
offsets ld) !
ci2 =
Some so2 ->
forall bo2,
empty_base_offset Optim (
offsets ld)
hierarchy ci2 b bo2 ->
fl_offset +
z1 *
size o' +
bo1 <>
o2 +
z2 *
size so2 +
bo2.
Proof.
Let g :=
map_snd (
key :=
ident) (
fun o =>
fl_offset +
o).
Definition field_layout_step_struct : {
fldata' |
fl_prop fldata' /\
fl_todo fldata' =
q
}.
exists (
make_fl
remove fs0 from fl_todo fldata = fs0 :: q
q
assign fl_offset to fs0
((
fs0,
fl_offset) :: (
fl_offsets fldata))
add the empty base offsets reachable from fs0
(
List.map g e' ++
fl_ebo fldata)
update the data size if a is not empty
(
if em then fl_nvds fldata else fl_offset + (
Zpos na - 1) *
size o' +
data_size o')
update the size to the max
(
if Z_le_dec (
fl_offset +
Zpos na *
size o') (
fl_nvsize fldata)
then (
fl_nvsize fldata)
else (
fl_offset +
Zpos na *
size o'))
update the alignment to the least common multiple
(
lcm (
fl_align fldata) (
align o'))
).
Proof.
End Struct.
General case
Definition field_layout_step : {
fldata' |
fl_prop fldata' /\
fl_todo fldata' =
q
}.
case struct: use the results of section Struct above.
case_eq (
FieldSignature.type fs0);
eauto using field_layout_step_struct.
only case scalar is left
intros.
destruct (
incr_align (
typ_align_positive PF t) (
fl_nvds fldata)).
destruct a.
exists (
make_fl
q
((
fs0,
x) ::
fl_offsets fldata)
(
fl_ebo fldata)
(
x +
typ_size PF (
t))
(
if Z_le_dec (
x +
typ_size PF (
t)) (
fl_nvsize fldata)
then (
fl_nvsize fldata)
else (
x +
typ_size PF (
t)))
(
lcm (
typ_align PF t) (
fl_align fldata))
).
Proof.
End Step.
Definition field_layout : {
fldata' |
fl_prop fldata' /\
fl_todo fldata' =
nil
}.
Proof.
End Field_layout.
Let fldata := (
let (
f,
_) :=
field_layout in f).
Let H_fldata :
fl_prop fldata.
Proof.
Let H_fldata_2 :
fl_todo fldata =
nil.
Proof.
At this point, all non-virtual layout is done. The field boundary is nvl_nvdsize nvldata, whereas all other non-virtual values are defined in fldata.
nvebo0 is the set of all non-virtual empty base offsets, except the offset of cilimit ld itself.
Let nvebo0 :=
nvl_nvebo nvldata ++
fl_ebo fldata.
Lemma nvebo0_incl :
forall b o,
In (
b,
o)
nvebo0 -> 0 <=
o <
fl_nvsize fldata.
Proof.
nvebo is the set of all non-virtual empty base offsets, including the offset of cilimit ld itself if it is empty.
Let Nvebo := (
if is_empty_dec hierarchy_wf (
cilimit ld)
then (
cons (
cilimit ld, 0)
nil)
else nil) ++
nvebo0.
Virtual base layout
In this algorithm, we do not consider generalized virtual bases, but only virtual bases. Indeed, the non-virtual parts of the virtual bases of cilimit ld make the conditions of 4.5 hold, which is not yet known for cilimit ld itself. So we have to treat the non-virtual part of the class differently from the non-virtual parts of its virtual bases.
Section Virtual_base_layout.
-
vl_todo: the list of virtual bases to which an offset has not yet been assigned
-
vl_offsets: the mapping between virtual bases and offsets
-
vl_nvebo: the set of non-virtual empty base offsets reachable through a virtual base that has already been assigned an offset
-
vl_ds: the data size so far.
-
vl_size: the size so far.
-
vl_align: the alignment so far.
Record vl :
Set :=
make_vl {
vl_todo :
list ident;
vl_offsets :
PTree.t Z;
vl_nvebo :
list (
ident *
Z);
vl_ds :
Z;
vl_size :
Z;
vl_align :
Z
}.
Section prop.
Variable vldata :
vl.
Record vl_prop :
Prop :=
vl_intro {
Guard
vl_exist :
forall ci, (
is_virtual_base_of hierarchy ci (
cilimit ld) <-> ((
vl_offsets vldata) !
ci <>
None \/
In ci (
vl_todo vldata)));
C13 for the class itself
vl_data_low_bound :
fl_nvds fldata <=
vl_ds vldata;
C3 for the class itself
vl_size_low_bound :
fl_nvsize fldata <=
vl_size vldata;
Guard
vl_low_bound :
forall ci of, (
vl_offsets vldata) !
ci =
Some of -> 0 <=
of;
C12 between the class itself and one of its virtual bases
vl_nonempty_low_bound :
forall ci, (
is_empty hierarchy ci ->
False) ->
forall of, (
vl_offsets vldata) !
ci =
Some of ->
fl_nvds fldata <=
of;
C12 between two virtual bases
vl_nonempty_non_overlap :
forall ci1 o1, (
vl_offsets vldata) !
ci1 =
Some o1 -> (
is_empty hierarchy ci1 ->
False) ->
forall ci2 o2, (
vl_offsets vldata) !
ci2 =
Some o2 -> (
is_empty hierarchy ci2 ->
False) ->
ci1 <>
ci2 ->
forall of1, (
offsets ld) !
ci1 =
Some of1 ->
forall of2, (
offsets ld) !
ci2 =
Some of2 ->
o1 +
non_virtual_data_size of1 <=
o2 \/
o2 +
non_virtual_data_size of2 <=
o1;
C26 between two virtual bases
vl_disjoint_empty_bases :
forall ci1 o1, (
vl_offsets vldata) !
ci1 =
Some o1 ->
forall ci2 o2, (
vl_offsets vldata) !
ci2 =
Some o2 ->
ci1 <>
ci2 ->
forall b bo1,
non_virtual_empty_base_offset Optim (
offsets ld)
hierarchy ci1 b bo1 ->
forall bo2,
non_virtual_empty_base_offset Optim (
offsets ld)
hierarchy ci2 b bo2 ->
o1 +
bo1 <>
o2 +
bo2;
C26 between the class itself and one of its virtual bases
vl_disjoint_empty_bases_main :
forall ci o, (
vl_offsets vldata) !
ci =
Some o ->
forall b bo,
non_virtual_empty_base_offset Optim (
offsets ld)
hierarchy ci b bo ->
In (
b,
o +
bo)
Nvebo ->
False;
C13 for a virtual base
vl_nonempty_high_bound :
forall ci, (
is_empty hierarchy ci ->
False) ->
forall of, (
vl_offsets vldata) !
ci =
Some of ->
forall o', (
offsets ld) !
ci =
Some o' ->
of +
non_virtual_data_size o' <=
vl_ds vldata;
C3 for a virtual base
vl_high_bound :
forall ci,
forall of, (
vl_offsets vldata) !
ci =
Some of ->
forall o', (
offsets ld) !
ci =
Some o' ->
of +
non_virtual_size o' <=
vl_size vldata;
Guard
vl_align_pos : 0 <
vl_align vldata;
C17 for the class itself
vl_align_field : (
fl_align fldata |
vl_align vldata);
C17 for a virtual base
vl_align_prop :
forall ci, (
vl_offsets vldata) !
ci <>
None ->
forall of, (
offsets ld) !
ci =
Some of -> (
non_virtual_align of |
vl_align vldata);
vl_offset_align :
forall ci of, (
vl_offsets vldata) !
ci =
Some of ->
forall co, (
offsets ld) !
ci =
Some co -> (
non_virtual_align co |
of);
Specification of the set vl_nvebo of non-virtual empty base offsets accessible from some virtual base.
vl_nvebo_prop :
forall b o, (
In (
b,
o) (
vl_nvebo vldata) <->
exists ci,
exists of, (
vl_offsets vldata) !
ci =
Some of /\
non_virtual_empty_base_offset Optim (
offsets ld)
hierarchy ci b (
o -
of))
}.
End prop.
Section Step.
Variable vldata :
vl.
Hypothesis prop :
vl_prop vldata.
Trying to assign an offset to the virtual base a of cilimit ld
Variable a :
ident.
Variable q :
list ident.
Hypothesis Htodo :
vl_todo vldata =
a ::
q.
Hypothesis undef: (
vl_offsets vldata) !
a =
None.
Let son :
is_virtual_base_of hierarchy a (
cilimit ld).
Proof.
destruct (
vl_exist prop a).
apply H0.
rewrite Htodo.
auto.
Qed.
Let Hlt : (
Plt a (
cilimit ld)).
Proof.
Definition v_orig_offset : {
o' | (
offsets ld) !
a =
Some o'}.
Proof.
Let o' :=
let (
o',
_) :=
v_orig_offset in o'.
Let Ho' : (
offsets ld) !
a =
Some o'.
Proof.
Let e0 : {
e | (
nvebo ld) !
a =
Some e}.
Proof.
generalize (
nvebo_exist (
Hld)
Hlt).
case_eq ((
nvebo ld) !
a);
try congruence.
intros.
repeat esplit.
Qed.
Let e :=
let (
e,
_) :=
e0 in e.
Let He : (
nvebo ld) !
a =
Some e.
Proof.
unfold e.
destruct e0.
assumption.
Qed.
Let cilimit_nonempty :
is_empty hierarchy (
cilimit ld) ->
False.
Proof.
Corollary nvebo_eq_nvebo0 :
Nvebo =
nvebo0.
Proof.
unfold Nvebo.
case (
is_empty_dec hierarchy_wf (
cilimit ld));
try contradiction;
reflexivity.
Qed.
Let em :=
is_empty_dec hierarchy_wf a.
The offset
v_offset assigned to
a is computed as follows:
-
starting from 0 if a is empty, from vl_ds fldata (the data size so far) otherwise
-
find the least offset o multiple of the non-virtual alignment of a, and such that the set e of non-virtual empty base offsets reachable from a is disjoint from nvl_nvebo the offsets of non-virtual empty base offsets so far, and from fl_ebo the empty base offsets reachable from other fields so far, and from vl_nvebo the offsets of non-virtual empty base offsets reachable through virtual bases so far, knowing that there will be no conflict if o >= vl_size fldata
See LibPos for a definition of bounded_offset.
Let f z (
x :
_ *
_) :=
let (
b,
o) :=
x in
if In_dec (
prod_eq_dec peq Z_eq_dec) (
b,
z +
o) (
nvebo0)
then true
else if In_dec (
prod_eq_dec peq Z_eq_dec) (
b,
z +
o) (
vl_nvebo vldata)
then true
else false.
Let f'
z :=
match List.filter (
f z)
e with
|
nil =>
true
|
_ =>
false
end.
Let align_pos : 0 <
non_virtual_align o'.
Proof.
Definition v_offset :=
let (
z,
_) :=
bounded_offset align_pos (
if em then 0
else vl_ds vldata) (
vl_size vldata)
f'
in z.
Lemma v_offsets_non_overlap :
forall ci co, (
vl_offsets vldata) !
ci =
Some co ->
forall b bo,
non_virtual_empty_base_offset Optim (
offsets ld)
hierarchy ci b bo ->
forall bo',
non_virtual_empty_base_offset Optim (
offsets ld)
hierarchy a b bo' ->
co +
bo <>
v_offset +
bo'.
Proof.
Lemma v_offsets_non_overlap_main :
forall b bo',
non_virtual_empty_base_offset Optim (
offsets ld)
hierarchy a b bo' ->
In (
b,
v_offset +
bo')
Nvebo ->
False.
Proof.
Lemma v_offset_low_bound : 0 <=
v_offset.
Proof.
Lemma v_offset_align : (
non_virtual_align o' |
v_offset).
Proof.
Lemma v_offset_nonempty_low_bound : (
is_empty hierarchy a ->
False) ->
vl_ds vldata <=
v_offset.
Proof.
unfold v_offset.
destruct (
bounded_offset align_pos (
if em then 0
else vl_ds vldata) (
vl_size vldata)
f').
destruct em;
tauto.
Qed.
Let g :=
map_snd (
key :=
ident) (
fun o =>
v_offset +
o).
Definition virtual_base_layout_step : {
vldata' |
vl_prop vldata' /\
vl_todo vldata' =
q
}.
exists (
make_vl
remove a from vl_todo vldata = a :: q
q
assign v_offset to a
(
PTree.set a v_offset (
vl_offsets vldata))
add the non-virtual empty base offsets of a to the empty base offsets of cilimit ld
(
List.map g e ++
vl_nvebo vldata)
update the data size if a is not empty
(
if em then vl_ds vldata else (
v_offset +
non_virtual_data_size o'))
update the size to the max
(
if Z_le_dec (
v_offset +
non_virtual_size o') (
vl_size vldata)
then (
vl_size vldata)
else (
v_offset +
non_virtual_size o'))
update the alignment to the least common multiple
(
lcm (
vl_align vldata) (
non_virtual_align o'))
).
Proof.
End Step.
Finally, lay out all the virtual bases
Definition vbases_aux : {
l |
forall x,
In x l <->
is_virtual_base_of hierarchy x (
cilimit ld)}.
Proof.
case_eq (
virtual_bases ! (
cilimit ld)).
intros.
exists l.
destruct (
virtual_bases_prop).
eauto.
intros.
apply False_rect.
destruct (
virtual_bases_prop).
eapply H0.
2 :
eassumption.
congruence.
Qed.
Let vbases :=
let (
v,
_) :=
vbases_aux in v.
Let H_vbases :
forall x,
In x vbases <->
is_virtual_base_of hierarchy x (
cilimit ld).
Proof.
unfold vbases.
destruct vbases_aux.
assumption.
Qed.
Definition virtual_base_layout : {
vldata |
vl_prop vldata /\
vl_todo vldata =
nil
}.
Proof.
End Virtual_base_layout.
Let vldata :=
let (
v,
_) :=
virtual_base_layout in v.
Let H_vldata :
vl_prop vldata.
Proof.
Let H_vldata_2 :
vl_todo vldata =
nil.
Proof.
Finalization and proof of correctness
Now, round the size up to max(size, dsize), then up to the nearest multiple of the alignment.
Let size0 :=
incr_align (
vl_align_pos H_vldata) (
if Z_le_dec (
vl_size vldata) (
vl_ds vldata)
then vl_ds vldata else vl_size vldata).
Let size :=
let (
s,
_) :=
size0 in s.
Let H_size :
vl_size vldata <=
size.
Proof.
Let H_data_size :
vl_ds vldata <=
size.
Proof.
Let H_size_2 : (
vl_align vldata |
size).
Proof.
unfold size.
destruct size0.
tauto.
Qed.
Construction of the layout data as expected in 4.2
Let o' := (
LayoutConstraints.make
(
nvl_pbase nvldata)
(
nvl_offsets nvldata)
(
nvl_nvds nvldata)
(
fl_offsets fldata)
(
fl_nvds fldata)
(
fl_nvsize fldata)
(
fl_align fldata)
(
PTree.set (
cilimit ld) 0 (
vl_offsets vldata))
(
vl_ds vldata)
size
(
vl_align vldata)
).
Definition offsets' :=
PTree.set (
cilimit ld)
o' (
offsets ld).
Lemma offsets'
_eq :
forall ci',
Plt ci' (
cilimit ld) ->
offsets' !
ci' = (
offsets ld) !
ci'.
Proof.
unfold offsets'.
intros.
rewrite PTree.gso.
trivial.
intro;
subst.
eapply Plt_irrefl;
eauto.
Qed.
Lemma offsets_preserve_old :
forall ci,
Plt ci (
cilimit ld) ->
forall o,
offsets' !
ci =
Some o ->
class_level_prop Optim PF offsets'
hierarchy ci o.
Proof.
Lemma offsets'
_defined :
offsets' ! (
cilimit ld) =
Some o'.
Proof.
unfold offsets'.
rewrite PTree.gss.
trivial.
Qed.
Lemma nvl_offsets_lt :
forall bi of,
(
nvl_offsets nvldata) !
bi =
Some of ->
Plt bi (
cilimit ld).
Proof.
Lemma nvl_offsets_offsets' :
forall bi of,
(
nvl_offsets nvldata) !
bi =
Some of ->
offsets' !
bi = (
offsets ld) !
bi.
Proof.
Lemma fl_offsets_offsets' :
forall f of,
assoc (
FieldSignature.eq_dec (
A :=
A))
f (
fl_offsets fldata) =
Some of ->
forall ci n,
FieldSignature.type f =
FieldSignature.Struct ci n ->
offsets' !
ci = (
offsets ld) !
ci.
Proof.
Lemma vl_offsets_offsets' :
forall bi of,
(
vl_offsets vldata) !
bi =
Some of ->
offsets' !
bi = (
offsets ld) !
bi.
Proof.
The proof that the new offsets computed for the current class satisfy the soundness conditions
Lemma offsets'
_preserve :
class_level_prop Optim PF offsets'
hierarchy (
cilimit ld)
o'.
Proof.
constructor;
unfold o';
simpl.
intros.
eapply nvl_primary_base_dynamic.
eauto.
assumption.
intros.
generalize (
nvl_primary_base H_nvldata H).
intros.
assert ((
nvl_offsets nvldata) !
b <>
None)
by congruence.
destruct (
nvl_exist H_nvldata b).
generalize (
H3 (
or_introl _ H1)).
intros.
assert (
Plt b (
cilimit ld))
by eauto using Well_formed_hierarchy.well_founded.
rewrite (
offsets'
_eq H5).
eauto using Well_formed_hierarchy.complete,
offsets_exist.
intros.
case_eq (
nvl_pbase nvldata);
try congruence.
intros.
generalize (
nvl_primary_base_dynamic H_nvldata H0).
intros.
generalize (
nvl_primary_base H_nvldata H0).
intros.
assert ((
nvl_offsets nvldata) !
i <>
None)
by congruence.
destruct (
nvl_exist H_nvldata i).
generalize (
H5 (
or_introl _ H3)).
intros.
eapply is_dynamic_base.
eassumption.
eassumption.
assumption.
intros until 1.
intro.
replace c with h by congruence.
generalize (
nvl_exist H_nvldata bi).
rewrite H_nvldata_2.
simpl .
tauto.
intros.
replace c with h by congruence.
revert H.
generalize (
nvl_exist H_nvldata bi).
rewrite H_nvldata_2.
simpl.
tauto.
intros;
eauto using nvl_primary_base.
intros;
eauto using nvl_low_bound.
intros;
eauto using nvl_dynamic_no_primary_low_bound.
intros;
eauto using nvl_align_dynamic,
fl_align_nvl,
Zdivide_trans.
intros until 1.
rewrite (
nvl_offsets_offsets'
H).
intros;
eauto using nvl_offset_align.
intros until 4.
rewrite (
nvl_offsets_offsets'
H).
rewrite (
nvl_offsets_offsets'
H1).
intros.
eauto using nvl_nonempty_non_overlap.
intros until 2.
rewrite (
nvl_offsets_offsets'
H0).
intros.
eauto using nvl_nonempty_high_bound.
eauto using nvl_data_low_bound.
eauto using nvl_data_dynamic_low_bound.
intros.
replace c with h in *
by congruence.
generalize (
fl_exist H_fldata f).
rewrite H_fldata_2.
simpl.
tauto.
intros.
replace c with h in *
by congruence.
generalize (
fl_exist H_fldata f).
rewrite H_fldata_2.
simpl.
tauto.
intros.
eauto using fl_low_bound.
intros;
eauto using fl_nonempty_low_bound.
intros until 1.
generalize (
fl_offset_align H_fldata H).
unfold field_align.
case_eq (
FieldSignature.type f).
tauto.
intros until 1.
rewrite (
fl_offsets_offsets'
H H0).
tauto.
intros until 5.
generalize (
fl_non_overlap H_fldata H H1 H0 H3 H2).
unfold field_data_size.
case_eq (
FieldSignature.type f1).
case_eq (
FieldSignature.type f2).
tauto.
intros until 1.
rewrite (
fl_offsets_offsets'
H0 H4).
tauto.
intros until 1.
rewrite (
fl_offsets_offsets'
H H4).
case_eq (
FieldSignature.type f2).
tauto.
intros until 1.
rewrite (
fl_offsets_offsets'
H0 H5).
tauto.
intros.
destruct (
is_dynamic_dec hierarchy_wf (
cilimit ld)).
generalize (
nvl_data_dynamic_low_bound H_nvldata i).
generalize (
fl_data_low_bound H_fldata).
generalize (
dynamic_type_data_size_low_bound PF).
omega.
pose (
G :=
fun f :
_ A =>
match FieldSignature.type f with
|
FieldSignature.Scalar _ =>
true
|
FieldSignature.Struct ci _ =>
if is_empty_dec hierarchy_wf ci then false else true
end).
case_eq (
filter G (
Class.fields h)).
intros.
pose (
F :=
fun cl =>
match cl with
| (
Class.Inheritance.Repeated,
ci) =>
if is_empty_dec hierarchy_wf ci then false else true
|
_ =>
false
end).
case_eq (
filter F (
Class.super h)).
intros.
destruct H.
econstructor.
eassumption.
intros.
generalize (
filter_In G f (
Class.fields h)).
rewrite H0.
simpl.
unfold G.
destruct (
FieldSignature.type f).
tauto.
intros;
repeat esplit.
intros.
generalize (
filter_In G f (
Class.fields h)).
rewrite H0.
simpl.
unfold G.
rewrite H2.
destruct (
is_empty_dec hierarchy_wf e);
tauto.
intros.
destruct n.
eapply is_dynamic_virtual_methods.
eassumption.
eauto.
intros.
destruct n.
eapply is_dynamic_virtual_base.
eleft.
eassumption.
eassumption.
intros.
generalize (
filter_In F (
Class.Inheritance.Repeated,
b) (
Class.super h)).
rewrite H1.
simpl.
destruct 1.
destruct (
is_empty_dec hierarchy_wf b).
assumption.
destruct H3.
auto.
intros.
generalize (
filter_In F p (
Class.super h)).
destruct p.
rewrite H1.
simpl.
destruct 1.
destruct (
H2 (
or_introl _ (
refl_equal _))).
destruct t;
try discriminate.
destruct (
is_empty_dec hierarchy_wf i);
try discriminate.
assert ((
offsets ld) !
i <>
None)
by eauto using Well_formed_hierarchy.well_founded,
Well_formed_hierarchy.complete,
offsets_exist.
case_eq ((
offsets ld) !
i);
try congruence.
intros.
generalize (
nonempty_non_virtual_data_size_positive (
offsets_intro (
Hld)
H7)
n0).
intros.
destruct (
nvl_exist H_nvldata i).
generalize (
H9 H4).
rewrite H_nvldata_2.
simpl.
destruct 1;
try contradiction.
case_eq ((
nvl_offsets nvldata) !
i);
try congruence.
intros.
generalize (
nvl_low_bound H_nvldata H12).
generalize (
nvl_nonempty_high_bound H_nvldata n0 H12 H7).
generalize (
fl_data_low_bound H_fldata).
omega.
intros.
generalize (
filter_In G t (
Class.fields h)).
rewrite H0.
destruct 1.
destruct (
H1 (
or_introl _ (
refl_equal _))).
generalize (
fl_exist H_fldata t).
rewrite H_fldata_2.
simpl.
destruct 1.
destruct (
H5 H3);
try contradiction.
case_eq (
assoc (
FieldSignature.eq_dec (
A :=
A))
t (
fl_offsets fldata));
try congruence.
intros.
generalize (
fl_low_bound H_fldata H8).
generalize (
fl_nonempty_high_bound H_fldata H8).
unfold field_data_size.
revert H4.
unfold G.
case_eq (
FieldSignature.type t).
intros.
assert ( (
forall (
ty :
ident) (
n :
positive),
FieldSignature.Scalar t0 =
FieldSignature.Struct ty n ->
is_empty hierarchy ty ->
False)
)
by (
intros;
discriminate).
generalize (
H10 H12 _ (
refl_equal _)).
generalize (
typ_size_positive PF t0).
omega.
intros until 1.
destruct (
is_empty_dec hierarchy_wf struct);
try congruence.
intros until 1.
case_eq ((
offsets ld) !
struct);
try congruence.
intros.
assert (
(
forall (
ty :
ident) (
n :
positive),
FieldSignature.Struct (
A :=
A)
struct arraysize =
FieldSignature.Struct ty n ->
is_empty hierarchy ty ->
False)
)
by (
congruence).
generalize (
H11 H13 _ (
refl_equal _)).
generalize (
size_positive (
offsets_intro (
Hld))
H10).
intros.
generalize (
Zpos_positive arraysize).
intros.
Transparent Zminus.
assert (0 <=
Zpos arraysize - 1)
by omega.
assert (0 <=
LayoutConstraints.size t0)
by omega.
generalize (
Zmult_ge H17 H18).
intros.
generalize (
virtual_base_offsets_data_size (
offsets_intro Hld H10) (
virtual_base_offsets_self (
offsets_intro Hld H10))
n0 H10).
generalize (
nonempty_non_virtual_data_size_positive (
offsets_intro Hld H10)
n0).
omega.
intros.
assert ((
offsets ld) !
struct <>
None)
by eauto using Well_formed_hierarchy.well_founded_struct,
Well_formed_hierarchy.complete_struct,
offsets_exist.
contradiction.
intros.
eapply fl_nonempty_high_bound.
eauto.
eassumption.
assumption.
revert H1.
unfold field_data_size.
case_eq (
FieldSignature.type f).
tauto.
intros until 1.
rewrite (
fl_offsets_offsets'
H H1).
tauto.
intros until 1.
generalize (
fl_high_bound H_fldata H).
unfold field_size.
case_eq (
FieldSignature.type f).
tauto.
intros until 1.
rewrite (
fl_offsets_offsets'
H H0).
tauto.
eauto using fl_data_low_bound.
intros until 1.
rewrite (
nvl_offsets_offsets'
H).
intros;
eauto using nvl_high_bound,
fl_size_low_bound,
Zle_trans.
intros until 1.
case_eq ((
nvl_offsets nvldata) !
bi);
try congruence.
intros until 1.
rewrite (
nvl_offsets_offsets'
H0).
intros;
eauto using nvl_align_prop,
Zdivide_trans,
fl_align_nvl.
intros until 1.
case_eq (
assoc (
FieldSignature.eq_dec (
A :=
A))
f (
fl_offsets fldata));
try congruence.
intros until 1.
generalize (
fl_align_prop H_fldata H).
unfold field_align.
case_eq (
FieldSignature.type f).
tauto.
intros until 1.
rewrite (
fl_offsets_offsets'
H0 H1).
tauto.
intros.
rewrite PTree.gso.
destruct (
vl_exist H_vldata b).
generalize (
H0 H).
rewrite H_vldata_2.
simpl.
tauto.
intro;
subst b.
generalize (
Well_formed_hierarchy.is_virtual_base_of_lt hierarchy_wf H).
apply Plt_irrefl.
intro.
destruct (
peq b (
cilimit ld)).
tauto.
rewrite PTree.gso.
destruct (
vl_exist H_vldata b).
rewrite H_vldata_2 in H0.
simpl in H0.
tauto.
assumption.
apply PTree.gss.
intro.
destruct (
peq b (
cilimit ld)).
subst.
rewrite PTree.gss.
injection 1;
intros;
subst.
exists 0;
omega.
rewrite PTree.gso.
intros until 1.
rewrite (
vl_offsets_offsets'
H).
eauto using vl_offset_align.
assumption.
intros ? ?.
destruct (
peq b (
cilimit ld)).
subst.
rewrite PTree.gss.
injection 1;
intros;
subst.
omega.
rewrite PTree.gso.
eauto using vl_low_bound.
assumption.
intros ? ?.
destruct (
peq b1 (
cilimit ld)).
subst.
rewrite PTree.gss.
injection 1;
intro;
subst.
simpl.
intros.
rewrite PTree.gso in H1.
unfold offsets'
in H0.
rewrite PTree.gss in H0.
rewrite (
vl_offsets_offsets'
H1)
in H2.
left.
injection H0;
intro;
subst bo1.
simpl.
eauto using vl_nonempty_low_bound.
congruence.
rewrite PTree.gso.
intro.
rewrite (
vl_offsets_offsets'
H).
intros until 1.
intros ? ?.
destruct (
peq b2 (
cilimit ld)).
subst.
rewrite PTree.gss.
injection 1;
intro;
subst.
unfold offsets'.
rewrite PTree.gss.
injection 1;
intro;
subst bo2.
simpl.
intros.
right.
eauto using vl_nonempty_low_bound.
rewrite PTree.gso.
intro.
rewrite (
vl_offsets_offsets'
H1).
intros.
eauto using vl_nonempty_non_overlap.
assumption.
assumption.
intros ? ?.
destruct (
peq bi (
cilimit ld)).
subst.
rewrite PTree.gss.
injection 1;
intro;
subst.
unfold offsets'.
rewrite PTree.gss.
injection 2;
intro;
subst bo.
simpl.
eauto using vl_data_low_bound.
rewrite PTree.gso.
unfold offsets'.
rewrite PTree.gso.
intros.
eauto using vl_nonempty_high_bound.
assumption.
assumption.
assumption.
unfold offsets'.
intro.
destruct (
peq bi (
cilimit ld)).
subst.
rewrite PTree.gss.
rewrite PTree.gss.
injection 1;
intro;
subst.
injection 1;
intro;
subst bo.
simpl.
eauto using Zle_trans,
vl_size_low_bound.
rewrite PTree.gso.
rewrite PTree.gso.
intros.
eauto using Zle_trans,
vl_high_bound.
assumption.
assumption.
unfold offsets'.
intro.
destruct (
peq b (
cilimit ld)).
subst.
rewrite PTree.gss.
rewrite PTree.gss.
injection 2;
intro;
subst bo.
simpl.
eauto using vl_align_field.
rewrite PTree.gso.
rewrite PTree.gso.
eauto using vl_align_prop.
assumption.
assumption.
assumption.
eauto using vl_align_pos.
eauto using fl_align_pos.
generalize (
nvl_size_pos H_nvldata).
generalize (
fl_size_low_bound H_fldata).
omega.
Qed.
Lemma non_virtual_empty_base_offset_old :
forall ci,
Plt ci (
cilimit ld) ->
forall b o,
non_virtual_empty_base_offset Optim (
offsets ld)
hierarchy ci b o ->
non_virtual_empty_base_offset Optim offsets'
hierarchy ci b o.
Proof.
Lemma empty_base_offset_old :
forall ci,
Plt ci (
cilimit ld) ->
forall b o,
empty_base_offset Optim (
offsets ld)
hierarchy ci b o ->
empty_base_offset Optim offsets'
hierarchy ci b o.
Proof.
Lemma disjoint_empty_base_offsets_old :
forall ci,
Plt ci (
cilimit ld) ->
forall of,
offsets' !
ci =
Some of ->
disjoint_empty_base_offsets Optim offsets'
hierarchy ci of.
Proof.
Lemma non_virtual_empty_base_offset_new :
forall ci,
Plt ci (
cilimit ld) ->
forall b o,
non_virtual_empty_base_offset Optim offsets'
hierarchy ci b o ->
non_virtual_empty_base_offset Optim (
offsets ld)
hierarchy ci b o.
Proof.
Lemma empty_base_offset_new :
forall ci,
Plt ci (
cilimit ld) ->
forall b o,
empty_base_offset Optim offsets'
hierarchy ci b o ->
empty_base_offset Optim (
offsets ld)
hierarchy ci b o.
Proof.
Lemma Nvebo_prop :
forall b o,
In (
b,
o)
Nvebo <->
non_virtual_empty_base_offset Optim offsets'
hierarchy (
cilimit ld)
b o.
Proof.
Lemma disjoint_empty_base_offsets_new :
disjoint_empty_base_offsets Optim offsets'
hierarchy (
cilimit ld)
o'.
Proof.
Let ld' :=
Ld
offsets'
(
Psucc (
cilimit ld))
(
PTree.set (
cilimit ld) (
Nvebo ++
vl_nvebo vldata) (
ebo ld))
(
PTree.set (
cilimit ld)
Nvebo (
nvebo ld))
.
The proof of the global invariant of the algorithm (guard conditions and specifications for nvebo and ebo
Lemma step' :
prop hierarchy ld'.
Proof.
Definition layout_step_defined : {
ld'0 |
prop hierarchy ld'0 /\
cilimit ld'0 =
Psucc (
cilimit ld)
}.
exists ld'.
Proof.
split.
apply step'.
reflexivity.
Qed.
End Def.
What to do if cilimit ld is not an identifier of a defined class
Section Undef.
Hypothesis undef :
hierarchy ! (
cilimit ld) =
None.
Definition layout_step_undefined : {
ld'0 |
prop hierarchy ld'0 /\
cilimit ld'0 =
Psucc (
cilimit ld)
}.
exists (
Ld
(
offsets ld)
(
Psucc (
cilimit ld))
(
PTree.set (
cilimit ld)
nil (
ebo ld))
(
PTree.set (
cilimit ld)
nil (
nvebo ld))
);
simpl.
Proof.
End Undef.
Definition layout_step : {
ld'0 |
prop hierarchy ld'0 /\
cilimit ld'0 =
Psucc (
cilimit ld)
}.
Proof.
End Step.
Packing all together
Definition empty_layout : {
ld'0 |
prop hierarchy ld'0 /\
cilimit ld'0 =
xH
}.
exists (
Ld
(
PTree.empty _)
xH
(
PTree.empty _)
(
PTree.empty _)
);
simpl.
Proof.
split;
try trivial.
constructor;
simpl;
try (
intros;
rewrite PTree.gempty in *;
simpl in *);
try congruence.
destruct ci;
simpl in *;
discriminate.
destruct ci;
simpl in *;
discriminate.
destruct ci;
simpl in *;
discriminate.
Qed.
Let max0 :=
max_index hierarchy.
Let max :=
let (
m,
_) :=
max0 in m.
Let H_max :
forall j,
hierarchy !
j <>
None ->
Plt j max.
Proof.
unfold max.
destruct max0.
assumption.
Qed.
Definition layout_end : {
ld'0 |
prop hierarchy ld'0 /\
cilimit ld'0 =
max
}.
Proof.
Definition layout : {
offsets |
(
forall ci,
hierarchy !
ci <>
None <->
offsets !
ci <>
None) /\
forall ci of,
offsets !
ci =
Some of -> (
class_level_prop Optim PF (
offsets )
hierarchy ci of /\
disjoint_empty_base_offsets Optim (
offsets)
hierarchy ci of
)
}.
Proof.
destruct (
layout_end).
destruct a.
inversion H.
exists (
offsets x).
split.
split.
intros.
eapply offsets_exist.
eassumption.
rewrite H0.
eauto.
assumption.
auto.
split;
eauto.
Qed.
End Layout.
End Compcert.