aboutsummaryrefslogtreecommitdiffstats
path: root/cfrontend/Ctypes.v
diff options
context:
space:
mode:
Diffstat (limited to 'cfrontend/Ctypes.v')
-rw-r--r--cfrontend/Ctypes.v680
1 files changed, 538 insertions, 142 deletions
diff --git a/cfrontend/Ctypes.v b/cfrontend/Ctypes.v
index 664a60c5..e3356510 100644
--- a/cfrontend/Ctypes.v
+++ b/cfrontend/Ctypes.v
@@ -6,10 +6,11 @@
(* *)
(* Copyright Institut National de Recherche en Informatique et en *)
(* Automatique. All rights reserved. This file is distributed *)
-(* under the terms of the GNU General Public License as published by *)
-(* the Free Software Foundation, either version 2 of the License, or *)
-(* (at your option) any later version. This file is also distributed *)
-(* under the terms of the INRIA Non-Commercial License Agreement. *)
+(* under the terms of the GNU Lesser General Public License as *)
+(* published by the Free Software Foundation, either version 2.1 of *)
+(* the License, or (at your option) any later version. *)
+(* This file is also distributed under the terms of the *)
+(* INRIA Non-Commercial License Agreement. *)
(* *)
(* *********************************************************************)
@@ -19,6 +20,10 @@ Require Import Axioms Coqlib Maps Errors.
Require Import AST Linking.
Require Archi.
+Set Asymmetric Patterns.
+
+Local Open Scope error_monad_scope.
+
(** * Syntax of types *)
(** Compcert C types are similar to those of C. They include numeric types,
@@ -83,20 +88,28 @@ Proof.
decide equality.
Defined.
+Lemma signedness_eq: forall (s1 s2: signedness), {s1=s2} + {s1<>s2}.
+Proof.
+ decide equality.
+Defined.
+
+Lemma attr_eq: forall (a1 a2: attr), {a1=a2} + {a1<>a2}.
+Proof.
+ decide equality. decide equality. apply N.eq_dec. apply bool_dec.
+Defined.
+
Lemma type_eq: forall (ty1 ty2: type), {ty1=ty2} + {ty1<>ty2}
with typelist_eq: forall (tyl1 tyl2: typelist), {tyl1=tyl2} + {tyl1<>tyl2}.
Proof.
- assert (forall (x y: signedness), {x=y} + {x<>y}) by decide equality.
assert (forall (x y: floatsize), {x=y} + {x<>y}) by decide equality.
- assert (forall (x y: attr), {x=y} + {x<>y}).
- { decide equality. decide equality. apply N.eq_dec. apply bool_dec. }
- generalize ident_eq zeq bool_dec ident_eq intsize_eq; intros.
+ generalize ident_eq zeq bool_dec ident_eq intsize_eq signedness_eq attr_eq; intros.
+ decide equality.
decide equality.
decide equality.
decide equality.
Defined.
-Opaque type_eq typelist_eq.
+Global Opaque intsize_eq signedness_eq attr_eq type_eq typelist_eq.
(** Extract the attributes of a type. *)
@@ -148,17 +161,53 @@ Definition attr_union (a1 a2: attr) : attr :=
Definition merge_attributes (ty: type) (a: attr) : type :=
change_attributes (attr_union a) ty.
+(** Maximal size in bits of a bitfield of type [sz]. *)
+
+Definition bitsize_intsize (sz: intsize) : Z :=
+ match sz with
+ | I8 => 8
+ | I16 => 16
+ | I32 => 32
+ | IBool => 1
+ end.
+
(** Syntax for [struct] and [union] definitions. [struct] and [union]
are collectively called "composites". Each compilation unit
comes with a list of top-level definitions of composites. *)
Inductive struct_or_union : Type := Struct | Union.
-Definition members : Type := list (ident * type).
+Inductive member : Type :=
+ | Member_plain (id: ident) (t: type)
+ | Member_bitfield (id: ident) (sz: intsize) (sg: signedness) (a: attr)
+ (width: Z) (padding: bool).
+
+Definition members : Type := list member.
Inductive composite_definition : Type :=
Composite (id: ident) (su: struct_or_union) (m: members) (a: attr).
+Definition name_member (m: member) : ident :=
+ match m with
+ | Member_plain id _ => id
+ | Member_bitfield id _ _ _ _ _ => id
+ end.
+
+Definition type_member (m: member) : type :=
+ match m with
+ | Member_plain _ t => t
+ | Member_bitfield _ sz sg a w _ =>
+ (* An unsigned bitfield of width < size of type reads with a signed type *)
+ let sg' := if zlt w (bitsize_intsize sz) then Signed else sg in
+ Tint sz sg' a
+ end.
+
+Definition member_is_padding (m: member) : bool :=
+ match m with
+ | Member_plain _ _ => false
+ | Member_bitfield _ _ _ _ _ p => p
+ end.
+
Definition name_composite_def (c: composite_definition) : ident :=
match c with Composite id su m a => id end.
@@ -166,7 +215,9 @@ Definition composite_def_eq (x y: composite_definition): {x=y} + {x<>y}.
Proof.
decide equality.
- decide equality. decide equality. apply N.eq_dec. apply bool_dec.
-- apply list_eq_dec. decide equality. apply type_eq. apply ident_eq.
+- apply list_eq_dec. decide equality.
+ apply type_eq. apply ident_eq.
+ apply bool_dec. apply zeq. apply attr_eq. apply signedness_eq. apply intsize_eq. apply ident_eq.
- decide equality.
- apply ident_eq.
Defined.
@@ -192,6 +243,13 @@ Record composite : Type := {
Definition composite_env : Type := PTree.t composite.
+(** Access modes for members of structs or unions: either a plain field
+ or a bitfield *)
+
+Inductive bitfield : Type :=
+ | Full
+ | Bits (sz: intsize) (sg: signedness) (pos: Z) (width: Z).
+
(** * Operations over types *)
(** ** Conversions *)
@@ -349,13 +407,16 @@ Fixpoint sizeof (env: composite_env) (t: type) : Z :=
Lemma sizeof_pos:
forall env t, sizeof env t >= 0.
Proof.
- induction t; simpl; try omega.
- destruct i; omega.
- destruct f; omega.
- destruct Archi.ptr64; omega.
- change 0 with (0 * Z.max 0 z) at 2. apply Zmult_ge_compat_r. auto. xomega.
- destruct (env!i). apply co_sizeof_pos. omega.
- destruct (env!i). apply co_sizeof_pos. omega.
+ induction t; simpl.
+- lia.
+- destruct i; lia.
+- lia.
+- destruct f; lia.
+- destruct Archi.ptr64; lia.
+- change 0 with (0 * Z.max 0 z) at 2. apply Zmult_ge_compat_r. auto. lia.
+- lia.
+- destruct (env!i). apply co_sizeof_pos. lia.
+- destruct (env!i). apply co_sizeof_pos. lia.
Qed.
(** The size of a type is an integral multiple of its alignment,
@@ -384,41 +445,205 @@ Proof.
- destruct (env!i). apply co_sizeof_alignof. apply Z.divide_0_r.
Qed.
+(** ** Layout of struct fields *)
+
+Section LAYOUT.
+
+Variable env: composite_env.
+
+Definition bitalignof (t: type) := alignof env t * 8.
+
+Definition bitsizeof (t: type) := sizeof env t * 8.
+
+Definition bitalignof_intsize (sz: intsize) : Z :=
+ match sz with
+ | I8 | IBool => 8
+ | I16 => 16
+ | I32 => 32
+ end.
+
+Definition next_field (pos: Z) (m: member) : Z :=
+ match m with
+ | Member_plain _ t =>
+ align pos (bitalignof t) + bitsizeof t
+ | Member_bitfield _ sz _ _ w _ =>
+ let s := bitalignof_intsize sz in
+ if zle w 0 then
+ align pos s
+ else
+ let curr := floor pos s in
+ let next := curr + s in
+ if zle (pos + w) next then pos + w else next + w
+ end.
+
+Definition layout_field (pos: Z) (m: member) : res (Z * bitfield) :=
+ match m with
+ | Member_plain _ t =>
+ OK (align pos (bitalignof t) / 8, Full)
+ | Member_bitfield _ sz sg _ w _ =>
+ if zle w 0 then Error (msg "accessing zero-width bitfield")
+ else if zlt (bitsize_intsize sz) w then Error (msg "bitfield too wide")
+ else
+ let s := bitalignof_intsize sz in
+ let start := floor pos s in
+ let next := start + s in
+ if zle (pos + w) next then
+ OK (start / 8, Bits sz sg (pos - start) w)
+ else
+ OK (next / 8, Bits sz sg 0 w)
+ end.
+
+(** Some properties *)
+
+Lemma bitalignof_intsize_pos:
+ forall sz, bitalignof_intsize sz > 0.
+Proof.
+ destruct sz; simpl; lia.
+Qed.
+
+Lemma next_field_incr:
+ forall pos m, pos <= next_field pos m.
+Proof.
+ intros. unfold next_field. destruct m.
+- set (al := bitalignof t).
+ assert (A: al > 0).
+ { unfold al, bitalignof. generalize (alignof_pos env t). lia. }
+ assert (pos <= align pos al) by (apply align_le; auto).
+ assert (bitsizeof t >= 0).
+ { unfold bitsizeof. generalize (sizeof_pos env t). lia. }
+ lia.
+- set (s := bitalignof_intsize sz).
+ assert (A: s > 0) by (apply bitalignof_intsize_pos).
+ destruct (zle width 0).
++ apply align_le; auto.
++ generalize (floor_interval pos s A).
+ set (start := floor pos s). intros B.
+ destruct (zle (pos + width) (start + s)); lia.
+Qed.
+
+Definition layout_start (p: Z) (bf: bitfield) :=
+ p * 8 + match bf with Full => 0 | Bits sz sg pos w => pos end.
+
+Definition layout_width (t: type) (bf: bitfield) :=
+ match bf with Full => bitsizeof t | Bits sz sg pos w => w end.
+
+Lemma layout_field_range: forall pos m ofs bf,
+ layout_field pos m = OK (ofs, bf) ->
+ pos <= layout_start ofs bf
+ /\ layout_start ofs bf + layout_width (type_member m) bf <= next_field pos m.
+Proof.
+ intros until bf; intros L. unfold layout_start, layout_width. destruct m; simpl in L.
+- inv L. simpl.
+ set (al := bitalignof t).
+ set (q := align pos al).
+ assert (A: al > 0).
+ { unfold al, bitalignof. generalize (alignof_pos env t). lia. }
+ assert (B: pos <= q) by (apply align_le; auto).
+ assert (C: (al | q)) by (apply align_divides; auto).
+ assert (D: (8 | q)).
+ { apply Z.divide_transitive with al; auto. apply Z.divide_factor_r. }
+ assert (E: q / 8 * 8 = q).
+ { destruct D as (n & E). rewrite E. rewrite Z.div_mul by lia. auto. }
+ rewrite E. lia.
+- unfold next_field.
+ destruct (zle width 0); try discriminate.
+ destruct (zlt (bitsize_intsize sz) width); try discriminate.
+ set (s := bitalignof_intsize sz) in *.
+ assert (A: s > 0) by (apply bitalignof_intsize_pos).
+ generalize (floor_interval pos s A). set (p := floor pos s) in *. intros B.
+ assert (C: (s | p)) by (apply floor_divides; auto).
+ assert (D: (8 | s)).
+ { exists (s / 8). unfold s. destruct sz; reflexivity. }
+ assert (E: (8 | p)) by (apply Z.divide_transitive with s; auto).
+ assert (F: (8 | p + s)) by (apply Z.divide_add_r; auto).
+ assert (G: p / 8 * 8 = p).
+ { destruct E as (n & EQ). rewrite EQ. rewrite Z.div_mul by lia. auto. }
+ assert (H: (p + s) / 8 * 8 = p + s).
+ { destruct F as (n & EQ). rewrite EQ. rewrite Z.div_mul by lia. auto. }
+ destruct (zle (pos + width) (p + s)); inv L; lia.
+Qed.
+
+Definition layout_alignment (t: type) (bf: bitfield) :=
+ match bf with
+ | Full => alignof env t
+ | Bits sz _ _ _ => bitalignof_intsize sz / 8
+ end.
+
+Lemma layout_field_alignment: forall pos m ofs bf,
+ layout_field pos m = OK (ofs, bf) ->
+ (layout_alignment (type_member m) bf | ofs).
+Proof.
+ intros until bf; intros L. destruct m; simpl in L.
+- inv L; simpl.
+ set (q := align pos (bitalignof t)).
+ assert (A: (bitalignof t | q)).
+ { apply align_divides. unfold bitalignof. generalize (alignof_pos env t). lia. }
+ destruct A as [n E]. exists n. rewrite E. unfold bitalignof. rewrite Z.mul_assoc, Z.div_mul by lia. auto.
+- destruct (zle width 0); try discriminate.
+ destruct (zlt (bitsize_intsize sz) width); try discriminate.
+ set (s := bitalignof_intsize sz) in *.
+ assert (A: s > 0) by (apply bitalignof_intsize_pos).
+ set (p := floor pos s) in *.
+ assert (C: (s | p)) by (apply floor_divides; auto).
+ assert (D: (8 | s)).
+ { exists (s / 8). unfold s. destruct sz; reflexivity. }
+ assert (E: forall n, (s | n) -> (s / 8 | n / 8)).
+ { intros. destruct H as [n1 E1], D as [n2 E2]. rewrite E1, E2.
+ rewrite Z.mul_assoc, ! Z.div_mul by lia. exists n1; auto. }
+ destruct (zle (pos + width) (p + s)); inv L; simpl; fold s.
+ + apply E. auto.
+ + apply E. apply Z.divide_add_r; auto using Z.divide_refl.
+Qed.
+
+End LAYOUT.
+
(** ** Size and alignment for composite definitions *)
(** The alignment for a structure or union is the max of the alignment
- of its members. *)
+ of its members. Padding bitfields are ignored. *)
-Fixpoint alignof_composite (env: composite_env) (m: members) : Z :=
- match m with
+Fixpoint alignof_composite (env: composite_env) (ms: members) : Z :=
+ match ms with
| nil => 1
- | (id, t) :: m' => Z.max (alignof env t) (alignof_composite env m')
+ | m :: ms =>
+ if member_is_padding m
+ then alignof_composite env ms
+ else Z.max (alignof env (type_member m)) (alignof_composite env ms)
end.
(** The size of a structure corresponds to its layout: fields are
laid out consecutively, and padding is inserted to align
- each field to the alignment for its type. *)
+ each field to the alignment for its type. Bitfields are packed
+ as described above. *)
-Fixpoint sizeof_struct (env: composite_env) (cur: Z) (m: members) : Z :=
- match m with
+Fixpoint bitsizeof_struct (env: composite_env) (cur: Z) (ms: members) : Z :=
+ match ms with
| nil => cur
- | (id, t) :: m' => sizeof_struct env (align cur (alignof env t) + sizeof env t) m'
+ | m :: ms => bitsizeof_struct env (next_field env cur m) ms
end.
+Definition bytes_of_bits (n: Z) := (n + 7) / 8.
+
+Definition sizeof_struct (env: composite_env) (m: members) : Z :=
+ bytes_of_bits (bitsizeof_struct env 0 m).
+
(** The size of an union is the max of the sizes of its members. *)
-Fixpoint sizeof_union (env: composite_env) (m: members) : Z :=
- match m with
+Fixpoint sizeof_union (env: composite_env) (ms: members) : Z :=
+ match ms with
| nil => 0
- | (id, t) :: m' => Z.max (sizeof env t) (sizeof_union env m')
+ | m :: ms => Z.max (sizeof env (type_member m)) (sizeof_union env ms)
end.
+(** Some properties *)
+
Lemma alignof_composite_two_p:
forall env m, exists n, alignof_composite env m = two_power_nat n.
Proof.
- induction m as [|[id t]]; simpl.
+ induction m; simpl.
- exists 0%nat; auto.
-- apply Z.max_case; auto. apply alignof_two_p.
+- destruct (member_is_padding a); auto.
+ apply Z.max_case; auto. apply alignof_two_p.
Qed.
Lemma alignof_composite_pos:
@@ -430,94 +655,113 @@ Proof.
rewrite EQ; apply two_power_nat_pos.
Qed.
-Lemma sizeof_struct_incr:
- forall env m cur, cur <= sizeof_struct env cur m.
+Lemma bitsizeof_struct_incr:
+ forall env m cur, cur <= bitsizeof_struct env cur m.
Proof.
- induction m as [|[id t]]; simpl; intros.
-- omega.
-- apply Z.le_trans with (align cur (alignof env t)).
- apply align_le. apply alignof_pos.
- apply Z.le_trans with (align cur (alignof env t) + sizeof env t).
- generalize (sizeof_pos env t); omega.
- apply IHm.
+ induction m; simpl; intros.
+- lia.
+- apply Z.le_trans with (next_field env cur a).
+ apply next_field_incr. apply IHm.
Qed.
Lemma sizeof_union_pos:
forall env m, 0 <= sizeof_union env m.
Proof.
- induction m as [|[id t]]; simpl; xomega.
+ induction m; simpl; extlia.
Qed.
-(** ** Byte offset for a field of a structure *)
-
-(** [field_offset env id fld] returns the byte offset for field [id]
- in a structure whose members are [fld]. Fields are laid out
- consecutively, and padding is inserted to align each field to the
- alignment for its type. *)
+(** ** Byte offset and bitfield designator for a field of a structure *)
-Fixpoint field_offset_rec (env: composite_env) (id: ident) (fld: members) (pos: Z)
- {struct fld} : res Z :=
- match fld with
+Fixpoint field_type (id: ident) (ms: members) {struct ms} : res type :=
+ match ms with
| nil => Error (MSG "Unknown field " :: CTX id :: nil)
- | (id', t) :: fld' =>
- if ident_eq id id'
- then OK (align pos (alignof env t))
- else field_offset_rec env id fld' (align pos (alignof env t) + sizeof env t)
+ | m :: ms => if ident_eq id (name_member m) then OK (type_member m) else field_type id ms
end.
-Definition field_offset (env: composite_env) (id: ident) (fld: members) : res Z :=
- field_offset_rec env id fld 0.
+(** [field_offset env id fld] returns the byte offset for field [id]
+ in a structure whose members are [fld]. It also returns a
+ bitfield designator, giving the location of the bits to access
+ within the storage unit for the bitfield. *)
-Fixpoint field_type (id: ident) (fld: members) {struct fld} : res type :=
- match fld with
+Fixpoint field_offset_rec (env: composite_env) (id: ident) (ms: members) (pos: Z)
+ {struct ms} : res (Z * bitfield) :=
+ match ms with
| nil => Error (MSG "Unknown field " :: CTX id :: nil)
- | (id', t) :: fld' => if ident_eq id id' then OK t else field_type id fld'
+ | m :: ms =>
+ if ident_eq id (name_member m)
+ then layout_field env pos m
+ else field_offset_rec env id ms (next_field env pos m)
end.
+Definition field_offset (env: composite_env) (id: ident) (ms: members) : res (Z * bitfield) :=
+ field_offset_rec env id ms 0.
+
(** Some sanity checks about field offsets. First, field offsets are
within the range of acceptable offsets. *)
Remark field_offset_rec_in_range:
- forall env id ofs ty fld pos,
- field_offset_rec env id fld pos = OK ofs -> field_type id fld = OK ty ->
- pos <= ofs /\ ofs + sizeof env ty <= sizeof_struct env pos fld.
+ forall env id ofs bf ty ms pos,
+ field_offset_rec env id ms pos = OK (ofs, bf) -> field_type id ms = OK ty ->
+ pos <= layout_start ofs bf
+ /\ layout_start ofs bf + layout_width env ty bf <= bitsizeof_struct env pos ms.
Proof.
- intros until ty. induction fld as [|[i t]]; simpl; intros.
+ induction ms as [ | m ms]; simpl; intros.
- discriminate.
-- destruct (ident_eq id i); intros.
- inv H. inv H0. split.
- apply align_le. apply alignof_pos. apply sizeof_struct_incr.
- exploit IHfld; eauto. intros [A B]. split; auto.
- eapply Z.le_trans; eauto. apply Z.le_trans with (align pos (alignof env t)).
- apply align_le. apply alignof_pos. generalize (sizeof_pos env t). omega.
+- destruct (ident_eq id (name_member m)).
+ + inv H0.
+ exploit layout_field_range; eauto.
+ generalize (bitsizeof_struct_incr env ms (next_field env pos m)).
+ lia.
+ + exploit IHms; eauto.
+ generalize (next_field_incr env pos m).
+ lia.
Qed.
-Lemma field_offset_in_range:
- forall env fld id ofs ty,
- field_offset env id fld = OK ofs -> field_type id fld = OK ty ->
- 0 <= ofs /\ ofs + sizeof env ty <= sizeof_struct env 0 fld.
+Lemma field_offset_in_range_gen:
+ forall env ms id ofs bf ty,
+ field_offset env id ms = OK (ofs, bf) -> field_type id ms = OK ty ->
+ 0 <= layout_start ofs bf
+ /\ layout_start ofs bf + layout_width env ty bf <= bitsizeof_struct env 0 ms.
Proof.
intros. eapply field_offset_rec_in_range; eauto.
Qed.
+Corollary field_offset_in_range:
+ forall env ms id ofs ty,
+ field_offset env id ms = OK (ofs, Full) -> field_type id ms = OK ty ->
+ 0 <= ofs /\ ofs + sizeof env ty <= sizeof_struct env ms.
+Proof.
+ intros. exploit field_offset_in_range_gen; eauto.
+ unfold layout_start, layout_width, bitsizeof, sizeof_struct. intros [A B].
+ assert (C: forall x y, x * 8 <= y -> x <= bytes_of_bits y).
+ { unfold bytes_of_bits; intros.
+ assert (P: 8 > 0) by lia.
+ generalize (Z_div_mod_eq (y + 7) 8 P) (Z_mod_lt (y + 7) 8 P).
+ lia. }
+ split. lia. apply C. lia.
+Qed.
+
(** Second, two distinct fields do not overlap *)
Lemma field_offset_no_overlap:
- forall env id1 ofs1 ty1 id2 ofs2 ty2 fld,
- field_offset env id1 fld = OK ofs1 -> field_type id1 fld = OK ty1 ->
- field_offset env id2 fld = OK ofs2 -> field_type id2 fld = OK ty2 ->
+ forall env id1 ofs1 bf1 ty1 id2 ofs2 bf2 ty2 fld,
+ field_offset env id1 fld = OK (ofs1, bf1) -> field_type id1 fld = OK ty1 ->
+ field_offset env id2 fld = OK (ofs2, bf2) -> field_type id2 fld = OK ty2 ->
id1 <> id2 ->
- ofs1 + sizeof env ty1 <= ofs2 \/ ofs2 + sizeof env ty2 <= ofs1.
+ layout_start ofs1 bf1 + layout_width env ty1 bf1 <= layout_start ofs2 bf2
+ \/ layout_start ofs2 bf2 + layout_width env ty2 bf2 <= layout_start ofs1 bf1.
Proof.
intros until fld. unfold field_offset. generalize 0 as pos.
- induction fld as [|[i t]]; simpl; intros.
+ induction fld as [|m fld]; simpl; intros.
- discriminate.
-- destruct (ident_eq id1 i); destruct (ident_eq id2 i).
+- destruct (ident_eq id1 (name_member m)); destruct (ident_eq id2 (name_member m)).
+ congruence.
-+ subst i. inv H; inv H0.
- exploit field_offset_rec_in_range. eexact H1. eauto. tauto.
-+ subst i. inv H1; inv H2.
- exploit field_offset_rec_in_range. eexact H. eauto. tauto.
++ inv H0.
+ exploit field_offset_rec_in_range; eauto.
+ exploit layout_field_range; eauto. lia.
++ inv H2.
+ exploit field_offset_rec_in_range; eauto.
+ exploit layout_field_range; eauto. lia.
+ eapply IHfld; eauto.
Qed.
@@ -525,31 +769,90 @@ Qed.
are the same. *)
Lemma field_offset_prefix:
- forall env id ofs fld2 fld1,
- field_offset env id fld1 = OK ofs ->
- field_offset env id (fld1 ++ fld2) = OK ofs.
+ forall env id ofs bf fld2 fld1,
+ field_offset env id fld1 = OK (ofs, bf) ->
+ field_offset env id (fld1 ++ fld2) = OK (ofs, bf).
Proof.
intros until fld1. unfold field_offset. generalize 0 as pos.
- induction fld1 as [|[i t]]; simpl; intros.
+ induction fld1 as [|m fld1]; simpl; intros.
- discriminate.
-- destruct (ident_eq id i); auto.
+- destruct (ident_eq id (name_member m)); auto.
Qed.
(** Fourth, the position of each field respects its alignment. *)
-Lemma field_offset_aligned:
- forall env id fld ofs ty,
- field_offset env id fld = OK ofs -> field_type id fld = OK ty ->
- (alignof env ty | ofs).
+Lemma field_offset_aligned_gen:
+ forall env id fld ofs bf ty,
+ field_offset env id fld = OK (ofs, bf) -> field_type id fld = OK ty ->
+ (layout_alignment env ty bf | ofs).
Proof.
intros until ty. unfold field_offset. generalize 0 as pos. revert fld.
- induction fld as [|[i t]]; simpl; intros.
+ induction fld as [|m fld]; simpl; intros.
- discriminate.
-- destruct (ident_eq id i).
-+ inv H; inv H0. apply align_divides. apply alignof_pos.
+- destruct (ident_eq id (name_member m)).
++ inv H0. eapply layout_field_alignment; eauto.
+ eauto.
Qed.
+Corollary field_offset_aligned:
+ forall env id fld ofs ty,
+ field_offset env id fld = OK (ofs, Full) -> field_type id fld = OK ty ->
+ (alignof env ty | ofs).
+Proof.
+ intros. exploit field_offset_aligned_gen; eauto.
+Qed.
+
+(** [union_field_offset env id ms] returns the byte offset and
+ bitfield designator for accessing a member named [id] of a union
+ whose members are [ms]. The byte offset is always 0. *)
+
+Fixpoint union_field_offset (env: composite_env) (id: ident) (ms: members)
+ {struct ms} : res (Z * bitfield) :=
+ match ms with
+ | nil => Error (MSG "Unknown field " :: CTX id :: nil)
+ | m :: ms =>
+ if ident_eq id (name_member m)
+ then layout_field env 0 m
+ else union_field_offset env id ms
+ end.
+
+(** Some sanity checks about union field offsets. First, field offsets
+ fit within the size of the union. *)
+
+Lemma union_field_offset_in_range_gen:
+ forall env id ofs bf ty ms,
+ union_field_offset env id ms = OK (ofs, bf) -> field_type id ms = OK ty ->
+ ofs = 0 /\ 0 <= layout_start ofs bf /\ layout_start ofs bf + layout_width env ty bf <= sizeof_union env ms * 8.
+Proof.
+ induction ms as [ | m ms]; simpl; intros.
+- discriminate.
+- destruct (ident_eq id (name_member m)).
+ + inv H0. set (ty := type_member m) in *.
+ destruct m; simpl in H.
+ * inv H. unfold layout_start, layout_width.
+ rewrite align_same. change (0 / 8) with 0. unfold bitsizeof. lia.
+ unfold bitalignof. generalize (alignof_pos env t). lia.
+ apply Z.divide_0_r.
+ * destruct (zle width 0); try discriminate.
+ destruct (zlt (bitsize_intsize sz) width); try discriminate.
+ assert (A: bitsize_intsize sz <= bitalignof_intsize sz <= sizeof env ty * 8).
+ { unfold ty, type_member; destruct sz; simpl; lia. }
+ rewrite zle_true in H by lia. inv H.
+ unfold layout_start, layout_width.
+ unfold floor; rewrite Z.div_0_l by lia.
+ lia.
+ + exploit IHms; eauto. lia.
+Qed.
+
+Corollary union_field_offset_in_range:
+ forall env ms id ofs ty,
+ union_field_offset env id ms = OK (ofs, Full) -> field_type id ms = OK ty ->
+ ofs = 0 /\ sizeof env ty <= sizeof_union env ms.
+Proof.
+ intros. exploit union_field_offset_in_range_gen; eauto.
+ unfold layout_start, layout_width, bitsizeof. lia.
+Qed.
+
(** ** Access modes *)
(** The [access_mode] function describes how a l-value of the given
@@ -636,7 +939,7 @@ Proof.
destruct n; auto.
right; right; right. apply Z.min_l.
rewrite two_power_nat_two_p. rewrite ! Nat2Z.inj_succ.
- change 8 with (two_p 3). apply two_p_monotone. omega.
+ change 8 with (two_p 3). apply two_p_monotone. lia.
}
induction ty; simpl.
auto.
@@ -653,7 +956,7 @@ Qed.
Lemma alignof_blockcopy_pos:
forall env ty, alignof_blockcopy env ty > 0.
Proof.
- intros. generalize (alignof_blockcopy_1248 env ty). simpl. intuition omega.
+ intros. generalize (alignof_blockcopy_1248 env ty). simpl. intuition lia.
Qed.
Lemma sizeof_alignof_blockcopy_compat:
@@ -669,8 +972,8 @@ Proof.
apply Z.min_case.
exists (two_p (Z.of_nat n)).
change 8 with (two_p 3).
- rewrite <- two_p_is_exp by omega.
- rewrite two_power_nat_two_p. rewrite !Nat2Z.inj_succ. f_equal. omega.
+ rewrite <- two_p_is_exp by lia.
+ rewrite two_power_nat_two_p. rewrite !Nat2Z.inj_succ. f_equal. lia.
apply Z.divide_refl.
}
induction ty; simpl.
@@ -707,7 +1010,8 @@ Fixpoint rank_type (ce: composite_env) (t: type) : nat :=
Fixpoint rank_members (ce: composite_env) (m: members) : nat :=
match m with
| nil => 0%nat
- | (id, t) :: m => Init.Nat.max (rank_type ce t) (rank_members ce m)
+ | Member_plain _ t :: m => Init.Nat.max (rank_type ce t) (rank_members ce m)
+ | Member_bitfield _ _ _ _ _ _ :: m => rank_members ce m
end.
(** ** C types and back-end types *)
@@ -761,7 +1065,7 @@ Definition signature_of_type (args: typelist) (res: type) (cc: calling_conventio
Definition sizeof_composite (env: composite_env) (su: struct_or_union) (m: members) : Z :=
match su with
- | Struct => sizeof_struct env 0 m
+ | Struct => sizeof_struct env m
| Union => sizeof_union env m
end.
@@ -769,21 +1073,23 @@ Lemma sizeof_composite_pos:
forall env su m, 0 <= sizeof_composite env su m.
Proof.
intros. destruct su; simpl.
- apply sizeof_struct_incr.
- apply sizeof_union_pos.
+- unfold sizeof_struct, bytes_of_bits.
+ assert (0 <= bitsizeof_struct env 0 m) by apply bitsizeof_struct_incr.
+ change 0 with (0 / 8) at 1. apply Z.div_le_mono; lia.
+- apply sizeof_union_pos.
Qed.
-Fixpoint complete_members (env: composite_env) (m: members) : bool :=
- match m with
+Fixpoint complete_members (env: composite_env) (ms: members) : bool :=
+ match ms with
| nil => true
- | (id, t) :: m' => complete_type env t && complete_members env m'
+ | m :: ms => complete_type env (type_member m) && complete_members env ms
end.
Lemma complete_member:
- forall env id t m,
- In (id, t) m -> complete_members env m = true -> complete_type env t = true.
+ forall env m ms,
+ In m ms -> complete_members env ms = true -> complete_type env (type_member m) = true.
Proof.
- induction m as [|[id1 t1] m]; simpl; intuition auto.
+ induction ms as [|m1 ms]; simpl; intuition auto.
InvBooleans; inv H1; auto.
InvBooleans; eauto.
Qed.
@@ -847,8 +1153,6 @@ Defined.
must precede all uses of this composite, unless the use is under
a pointer or function type. *)
-Local Open Scope error_monad_scope.
-
Fixpoint add_composite_definitions (env: composite_env) (defs: list composite_definition) : res composite_env :=
match defs with
| nil => OK env
@@ -911,52 +1215,88 @@ Proof.
Qed.
Lemma alignof_composite_stable:
- forall m, complete_members env m = true -> alignof_composite env' m = alignof_composite env m.
+ forall ms, complete_members env ms = true -> alignof_composite env' ms = alignof_composite env ms.
Proof.
- induction m as [|[id t]]; simpl; intros.
+ induction ms as [|m ms]; simpl; intros.
auto.
- InvBooleans. rewrite alignof_stable by auto. rewrite IHm by auto. auto.
+ InvBooleans. rewrite alignof_stable by auto. rewrite IHms by auto. auto.
Qed.
-Lemma sizeof_struct_stable:
- forall m pos, complete_members env m = true -> sizeof_struct env' pos m = sizeof_struct env pos m.
+Remark next_field_stable: forall pos m,
+ complete_type env (type_member m) = true -> next_field env' pos m = next_field env pos m.
Proof.
- induction m as [|[id t]]; simpl; intros.
+ destruct m; simpl; intros.
+- unfold bitalignof, bitsizeof. rewrite alignof_stable, sizeof_stable by auto. auto.
+- auto.
+Qed.
+
+Lemma bitsizeof_struct_stable:
+ forall ms pos, complete_members env ms = true -> bitsizeof_struct env' pos ms = bitsizeof_struct env pos ms.
+Proof.
+ induction ms as [|m ms]; simpl; intros.
auto.
- InvBooleans. rewrite alignof_stable by auto. rewrite sizeof_stable by auto.
- rewrite IHm by auto. auto.
+ InvBooleans. rewrite next_field_stable by auto. apply IHms; auto.
Qed.
Lemma sizeof_union_stable:
- forall m, complete_members env m = true -> sizeof_union env' m = sizeof_union env m.
+ forall ms, complete_members env ms = true -> sizeof_union env' ms = sizeof_union env ms.
Proof.
- induction m as [|[id t]]; simpl; intros.
+ induction ms as [|m ms]; simpl; intros.
auto.
- InvBooleans. rewrite sizeof_stable by auto. rewrite IHm by auto. auto.
+ InvBooleans. rewrite sizeof_stable by auto. rewrite IHms by auto. auto.
Qed.
Lemma sizeof_composite_stable:
- forall su m, complete_members env m = true -> sizeof_composite env' su m = sizeof_composite env su m.
+ forall su ms, complete_members env ms = true -> sizeof_composite env' su ms = sizeof_composite env su ms.
Proof.
intros. destruct su; simpl.
- apply sizeof_struct_stable; auto.
+ unfold sizeof_struct. f_equal. apply bitsizeof_struct_stable; auto.
apply sizeof_union_stable; auto.
Qed.
Lemma complete_members_stable:
- forall m, complete_members env m = true -> complete_members env' m = true.
+ forall ms, complete_members env ms = true -> complete_members env' ms = true.
Proof.
- induction m as [|[id t]]; simpl; intros.
+ induction ms as [|m ms]; simpl; intros.
auto.
- InvBooleans. rewrite complete_type_stable by auto. rewrite IHm by auto. auto.
+ InvBooleans. rewrite complete_type_stable by auto. rewrite IHms by auto. auto.
Qed.
Lemma rank_members_stable:
- forall m, complete_members env m = true -> rank_members env' m = rank_members env m.
+ forall ms, complete_members env ms = true -> rank_members env' ms = rank_members env ms.
Proof.
- induction m as [|[id t]]; simpl; intros.
+ induction ms as [|m ms]; simpl; intros.
auto.
- InvBooleans. f_equal; auto. apply rank_type_stable; auto.
+ InvBooleans. destruct m; auto. f_equal; auto. apply rank_type_stable; auto.
+Qed.
+
+Remark layout_field_stable: forall pos m,
+ complete_type env (type_member m) = true -> layout_field env' pos m = layout_field env pos m.
+Proof.
+ destruct m; simpl; intros.
+- unfold bitalignof. rewrite alignof_stable by auto. auto.
+- auto.
+Qed.
+
+Lemma field_offset_stable:
+ forall f ms, complete_members env ms = true -> field_offset env' f ms = field_offset env f ms.
+Proof.
+ intros until ms. unfold field_offset. generalize 0.
+ induction ms as [|m ms]; simpl; intros.
+- auto.
+- InvBooleans. destruct (ident_eq f (name_member m)).
+ apply layout_field_stable; auto.
+ rewrite next_field_stable by auto. apply IHms; auto.
+Qed.
+
+Lemma union_field_offset_stable:
+ forall f ms, complete_members env ms = true -> union_field_offset env' f ms = union_field_offset env f ms.
+Proof.
+ induction ms as [|m ms]; simpl; intros.
+- auto.
+- InvBooleans. destruct (ident_eq f (name_member m)).
+ apply layout_field_stable; auto.
+ apply IHms; auto.
Qed.
End STABILITY.
@@ -1086,37 +1426,41 @@ Qed.
is strictly greater than the ranks of its member types. *)
Remark rank_type_members:
- forall ce id t m, In (id, t) m -> (rank_type ce t <= rank_members ce m)%nat.
+ forall ce m ms, In m ms -> (rank_type ce (type_member m) <= rank_members ce ms)%nat.
Proof.
- induction m; simpl; intros; intuition auto.
- subst a. xomega.
- xomega.
+ induction ms; simpl; intros.
+- tauto.
+- destruct a; destruct H; subst; simpl.
+ + lia.
+ + apply IHms in H. lia.
+ + lia.
+ + apply IHms; auto.
Qed.
Lemma rank_struct_member:
- forall ce id a co id1 t1,
+ forall ce id a co m,
composite_env_consistent ce ->
ce!id = Some co ->
- In (id1, t1) (co_members co) ->
- (rank_type ce t1 < rank_type ce (Tstruct id a))%nat.
+ In m (co_members co) ->
+ (rank_type ce (type_member m) < rank_type ce (Tstruct id a))%nat.
Proof.
intros; simpl. rewrite H0.
erewrite co_consistent_rank by eauto.
exploit (rank_type_members ce); eauto.
- omega.
+ lia.
Qed.
Lemma rank_union_member:
- forall ce id a co id1 t1,
+ forall ce id a co m,
composite_env_consistent ce ->
ce!id = Some co ->
- In (id1, t1) (co_members co) ->
- (rank_type ce t1 < rank_type ce (Tunion id a))%nat.
+ In m (co_members co) ->
+ (rank_type ce (type_member m) < rank_type ce (Tunion id a))%nat.
Proof.
intros; simpl. rewrite H0.
erewrite co_consistent_rank by eauto.
exploit (rank_type_members ce); eauto.
- omega.
+ lia.
Qed.
(** * Programs and compilation units *)
@@ -1511,6 +1855,57 @@ Global Opaque Linker_program.
(** ** Commutation between linking and program transformations *)
+Section LINK_MATCH_PROGRAM_GEN.
+
+Context {F G: Type}.
+Variable match_fundef: program F -> fundef F -> fundef G -> Prop.
+
+Hypothesis link_match_fundef:
+ forall ctx1 ctx2 f1 tf1 f2 tf2 f,
+ link f1 f2 = Some f ->
+ match_fundef ctx1 f1 tf1 -> match_fundef ctx2 f2 tf2 ->
+ exists tf, link tf1 tf2 = Some tf /\ (match_fundef ctx1 f tf \/ match_fundef ctx2 f tf).
+
+Let match_program (p: program F) (tp: program G) : Prop :=
+ Linking.match_program_gen match_fundef eq p p tp
+ /\ prog_types tp = prog_types p.
+
+Theorem link_match_program_gen:
+ forall p1 p2 tp1 tp2 p,
+ link p1 p2 = Some p -> match_program p1 tp1 -> match_program p2 tp2 ->
+ exists tp, link tp1 tp2 = Some tp /\ match_program p tp.
+Proof.
+ intros until p; intros L [M1 T1] [M2 T2].
+ exploit link_linkorder; eauto. intros [LO1 LO2].
+Local Transparent Linker_program.
+ simpl in L; unfold link_program in L.
+ destruct (link (program_of_program p1) (program_of_program p2)) as [pp|] eqn:LP; try discriminate.
+ assert (A: exists tpp,
+ link (program_of_program tp1) (program_of_program tp2) = Some tpp
+ /\ Linking.match_program_gen match_fundef eq p pp tpp).
+ { eapply Linking.link_match_program; eauto.
+ - intros.
+ Local Transparent Linker_types.
+ simpl in *. destruct (type_eq v1 v2); inv H. exists v; rewrite dec_eq_true; auto.
+ }
+ destruct A as (tpp & TLP & MP).
+ simpl; unfold link_program. rewrite TLP.
+ destruct (lift_option (link (prog_types p1) (prog_types p2))) as [[typs EQ]|EQ]; try discriminate.
+ destruct (link_build_composite_env (prog_types p1) (prog_types p2) typs
+ (prog_comp_env p1) (prog_comp_env p2) (prog_comp_env_eq p1)
+ (prog_comp_env_eq p2) EQ) as (env & P & Q).
+ rewrite <- T1, <- T2 in EQ.
+ destruct (lift_option (link (prog_types tp1) (prog_types tp2))) as [[ttyps EQ']|EQ']; try congruence.
+ assert (ttyps = typs) by congruence. subst ttyps.
+ destruct (link_build_composite_env (prog_types tp1) (prog_types tp2) typs
+ (prog_comp_env tp1) (prog_comp_env tp2) (prog_comp_env_eq tp1)
+ (prog_comp_env_eq tp2) EQ') as (tenv & R & S).
+ assert (tenv = env) by congruence. subst tenv.
+ econstructor; split; eauto. inv L. split; auto.
+Qed.
+
+End LINK_MATCH_PROGRAM_GEN.
+
Section LINK_MATCH_PROGRAM.
Context {F G: Type}.
@@ -1566,3 +1961,4 @@ Local Transparent Linker_program.
Qed.
End LINK_MATCH_PROGRAM.
+