stor-layout.c (start_record_layout): Initialize remaining_in_alignment.

2006-06-04 Eric Christopher <echristo@apple.com>

        * stor-layout.c (start_record_layout): Initialize remaining_in_alignment.
        (debug_rli): Output value for remaining_in_alignment.
        (update_alignment_for_field): Unconditionalize
        ms_bitfield_layout_p code. Handle non-bitfield fields. Remove
        extra alignment code.
        (place_field): Don't realign if ms_bitfield_layout_p. Unconditionalize
        ms_bitfield_layout_p code. Rewrite handling of structure fields.
        * tree.h (record_layout_info_s): Remove prev_packed.
        * doc/extend.texi (ms_struct): Add documentation of format.

2006-06-04 Eric Christopher <echristo@apple.com>

        * gcc.dg/attr-ms_struct-1.c: New.

From-SVN: r114364
This commit is contained in:
Eric Christopher 2006-06-04 19:50:48 +00:00
parent a0c04f8e49
commit 0ac11108c4
6 changed files with 426 additions and 201 deletions

View File

@ -1,3 +1,15 @@
2006-06-04 Eric Christopher <echristo@apple.com>
* stor-layout.c (start_record_layout): Initialize remaining_in_alignment.
(debug_rli): Output value for remaining_in_alignment.
(update_alignment_for_field): Unconditionalize
ms_bitfield_layout_p code. Handle non-bitfield fields. Remove
extra alignment code.
(place_field): Don't realign if ms_bitfield_layout_p. Unconditionalize
ms_bitfield_layout_p code. Rewrite handling of structure fields.
* tree.h (record_layout_info_s): Remove prev_packed.
* doc/extend.texi (ms_struct): Add documentation of format.
2006-06-04 Mark Shinwell <shinwell@codesourcery.com>
* tree.h: Declare folding_initializer.

View File

@ -3246,6 +3246,117 @@ either format.
Currently @option{-m[no-]ms-bitfields} is provided for the Microsoft Windows X86
compilers to match the native Microsoft compiler.
The Microsoft structure layout algorithm is fairly simple with the exception
of the bitfield packing:
The padding and alignment of members of structures and whether a bit field
can straddle a storage-unit boundary
@enumerate
@item Structure members are stored sequentially in the order in which they are
declared: the first member has the lowest memory address and the last member
the highest.
@item Every data object has an alignment-requirement. The alignment-requirement
for all data except structures, unions, and arrays is either the size of the
object or the current packing size (specified with either the aligned attribute
or the pack pragma), whichever is less. For structures, unions, and arrays,
the alignment-requirement is the largest alignment-requirement of its members.
Every object is allocated an offset so that:
offset % alignment-requirement == 0
@item Adjacent bit fields are packed into the same 1-, 2-, or 4-byte allocation
unit if the integral types are the same size and if the next bit field fits
into the current allocation unit without crossing the boundary imposed by the
common alignment requirements of the bit fields.
@end enumerate
Handling of zero-length bitfields:
MSVC interprets zero-length bitfields in the following ways:
@enumerate
@item If a zero-length bitfield is inserted between two bitfields that would
normally be coalesced, the bitfields will not be coalesced.
For example:
@smallexample
struct
@{
unsigned long bf_1 : 12;
unsigned long : 0;
unsigned long bf_2 : 12;
@} t1;
@end smallexample
The size of @code{t1} would be 8 bytes with the zero-length bitfield. If the
zero-length bitfield were removed, @code{t1}'s size would be 4 bytes.
@item If a zero-length bitfield is inserted after a bitfield, @code{foo}, and the
alignment of the zero-length bitfield is greater than the member that follows it,
@code{bar}, @code{bar} will be aligned as the type of the zero-length bitfield.
For example:
@smallexample
struct
@{
char foo : 4;
short : 0;
char bar;
@} t2;
struct
@{
char foo : 4;
short : 0;
double bar;
@} t3;
@end smallexample
For @code{t2}, @code{bar} will be placed at offset 2, rather than offset 1.
Accordingly, the size of @code{t2} will be 4. For @code{t3}, the zero-length
bitfield will not affect the alignment of @code{bar} or, as a result, the size
of the structure.
Taking this into account, it is important to note the following:
@enumerate
@item If a zero-length bitfield follows a normal bitfield, the type of the
zero-length bitfield may affect the alignment of the structure as whole. For
example, @code{t2} has a size of 4 bytes, since the zero-length bitfield follows a
normal bitfield, and is of type short.
@item Even if a zero-length bitfield is not followed by a normal bitfield, it may
still affect the alignment of the structure:
@smallexample
struct
@{
char foo : 6;
long : 0;
@} t4;
@end smallexample
Here, @code{t4} will take up 4 bytes.
@end enumerate
@item Zero-length bitfields following non-bitfield members are ignored:
@smallexample
struct
@{
char foo;
long : 0;
char bar;
@} t5;
@end smallexample
Here, @code{t5} will take up 2 bytes.
@end enumerate
@end table
@subsection Xstormy16 Variable Attributes

View File

@ -538,6 +538,7 @@ start_record_layout (tree t)
rli->prev_field = 0;
rli->pending_statics = 0;
rli->packed_maybe_necessary = 0;
rli->remaining_in_alignment = 0;
return rli;
}
@ -611,6 +612,11 @@ debug_rli (record_layout_info rli)
fprintf (stderr, "\naligns: rec = %u, unpack = %u, off = %u\n",
rli->record_align, rli->unpacked_align,
rli->offset_align);
/* The ms_struct code is the only that uses this. */
if (targetm.ms_bitfield_layout_p (rli->t))
fprintf (stderr, "remaning in alignment = %u\n", rli->remaining_in_alignment);
if (rli->packed_maybe_necessary)
fprintf (stderr, "packed may be necessary\n");
@ -679,7 +685,7 @@ update_alignment_for_field (record_layout_info rli, tree field,
/* Record must have at least as much alignment as any field.
Otherwise, the alignment of the field within the record is
meaningless. */
if (is_bitfield && targetm.ms_bitfield_layout_p (rli->t))
if (targetm.ms_bitfield_layout_p (rli->t))
{
/* Here, the alignment of the underlying type of a bitfield can
affect the alignment of a record; even a zero-sized field
@ -687,11 +693,12 @@ update_alignment_for_field (record_layout_info rli, tree field,
the type, except that for zero-size bitfields this only
applies if there was an immediately prior, nonzero-size
bitfield. (That's the way it is, experimentally.) */
if (! integer_zerop (DECL_SIZE (field))
? ! DECL_PACKED (field)
if (!is_bitfield
|| (!integer_zerop (DECL_SIZE (field))
? !DECL_PACKED (field)
: (rli->prev_field
&& DECL_BIT_FIELD_TYPE (rli->prev_field)
&& ! integer_zerop (DECL_SIZE (rli->prev_field))))
&& ! integer_zerop (DECL_SIZE (rli->prev_field)))))
{
unsigned int type_align = TYPE_ALIGN (type);
type_align = MAX (type_align, desired_align);
@ -699,18 +706,6 @@ update_alignment_for_field (record_layout_info rli, tree field,
type_align = MIN (type_align, maximum_field_alignment);
rli->record_align = MAX (rli->record_align, type_align);
rli->unpacked_align = MAX (rli->unpacked_align, TYPE_ALIGN (type));
/* If we start a new run, make sure we start it properly aligned. */
if ((!rli->prev_field
|| integer_zerop (DECL_SIZE (field))
|| integer_zerop (DECL_SIZE (rli->prev_field))
|| !host_integerp (DECL_SIZE (rli->prev_field), 0)
|| !host_integerp (TYPE_SIZE (type), 0)
|| !simple_cst_equal (TYPE_SIZE (type),
TYPE_SIZE (TREE_TYPE (rli->prev_field)))
|| (rli->remaining_in_alignment
< tree_low_cst (DECL_SIZE (field), 0)))
&& desired_align < type_align)
desired_align = type_align;
}
}
#ifdef PCC_BITFIELD_TYPE_MATTERS
@ -904,8 +899,10 @@ place_field (record_layout_info rli, tree field)
}
/* Does this field automatically have alignment it needs by virtue
of the fields that precede it and the record's own alignment? */
if (known_align < desired_align)
of the fields that precede it and the record's own alignment?
We already align ms_struct fields, so don't re-align them. */
if (known_align < desired_align
&& !targetm.ms_bitfield_layout_p (rli->t))
{
/* No, we need to skip space before this field.
Bump the cumulative size to multiple of field alignment. */
@ -1022,17 +1019,12 @@ place_field (record_layout_info rli, tree field)
Note: for compatibility, we use the type size, not the type alignment
to determine alignment, since that matches the documentation */
if (targetm.ms_bitfield_layout_p (rli->t)
&& ((DECL_BIT_FIELD_TYPE (field) && ! DECL_PACKED (field))
|| (rli->prev_field && ! DECL_PACKED (rli->prev_field))))
if (targetm.ms_bitfield_layout_p (rli->t))
{
/* At this point, either the prior or current are bitfields,
(possibly both), and we're dealing with MS packing. */
tree prev_saved = rli->prev_field;
/* Is the prior field a bitfield? If so, handle "runs" of same
type size fields. */
if (rli->prev_field /* necessarily a bitfield if it exists. */)
/* This is a bitfield if it exists. */
if (rli->prev_field)
{
/* If both are bitfields, nonzero, and the same size, this is
the middle of a run. Zero declared size fields are special
@ -1051,18 +1043,9 @@ place_field (record_layout_info rli, tree field)
/* We're in the middle of a run of equal type size fields; make
sure we realign if we run out of bits. (Not decl size,
type size!) */
HOST_WIDE_INT bitsize = tree_low_cst (DECL_SIZE (field), 0);
HOST_WIDE_INT bitsize = tree_low_cst (DECL_SIZE (field), 1);
if (rli->remaining_in_alignment < bitsize)
{
/* If PREV_FIELD is packed, and we haven't lumped
non-packed bitfields with it, treat this as if PREV_FIELD
was not a bitfield. This avoids anomalies where a packed
bitfield with long long base type can take up more
space than a same-size bitfield with base type short. */
if (rli->prev_packed)
rli->prev_field = prev_saved = NULL;
else
{
/* out of bits; bump up to next 'word'. */
rli->offset = DECL_FIELD_OFFSET (rli->prev_field);
@ -1071,14 +1054,11 @@ place_field (record_layout_info rli, tree field)
DECL_FIELD_BIT_OFFSET (rli->prev_field));
rli->prev_field = field;
rli->remaining_in_alignment
= tree_low_cst (TYPE_SIZE (type), 0) - bitsize;
= tree_low_cst (TYPE_SIZE (type), 1);
}
}
else
rli->remaining_in_alignment -= bitsize;
}
else if (rli->prev_packed)
rli->prev_field = prev_saved = NULL;
else
{
/* End of a run: if leaving a run of bitfields of the same type
@ -1090,18 +1070,12 @@ place_field (record_layout_info rli, tree field)
Note: since the beginning of the field was aligned then
of course the end will be too. No round needed. */
if (!integer_zerop (DECL_SIZE (rli->prev_field)))
if (!integer_zerop (DECL_SIZE (rli->prev_field))
&& rli->remaining_in_alignment)
{
tree type_size = TYPE_SIZE (TREE_TYPE (rli->prev_field));
/* If the desired alignment is greater or equal to TYPE_SIZE,
we have already adjusted rli->bitpos / rli->offset above.
*/
if ((unsigned HOST_WIDE_INT) tree_low_cst (type_size, 0)
> desired_align)
rli->bitpos
= size_binop (PLUS_EXPR, type_size,
DECL_FIELD_BIT_OFFSET (rli->prev_field));
= size_binop (PLUS_EXPR, rli->bitpos,
bitsize_int (rli->remaining_in_alignment));
}
else
/* We "use up" size zero fields; the code below should behave
@ -1115,7 +1089,6 @@ place_field (record_layout_info rli, tree field)
rli->prev_field = NULL;
}
rli->prev_packed = 0;
normalize_rli (rli);
}
@ -1148,21 +1121,11 @@ place_field (record_layout_info rli, tree field)
&& host_integerp (TYPE_SIZE (TREE_TYPE (field)), 0)
&& host_integerp (DECL_SIZE (field), 0))
rli->remaining_in_alignment
= tree_low_cst (TYPE_SIZE (TREE_TYPE(field)), 0)
- tree_low_cst (DECL_SIZE (field), 0);
= tree_low_cst (TYPE_SIZE (TREE_TYPE(field)), 1)
- tree_low_cst (DECL_SIZE (field), 1);
/* Now align (conventionally) for the new type. */
if (!DECL_PACKED(field))
type_align = MAX(TYPE_ALIGN (type), type_align);
if (prev_saved
&& DECL_BIT_FIELD_TYPE (prev_saved)
/* If the previous bit-field is zero-sized, we've already
accounted for its alignment needs (or ignored it, if
appropriate) while placing it. */
&& ! integer_zerop (DECL_SIZE (prev_saved)))
type_align = MAX (type_align,
TYPE_ALIGN (TREE_TYPE (prev_saved)));
type_align = TYPE_ALIGN (TREE_TYPE (field));
if (maximum_field_alignment != 0)
type_align = MIN (type_align, maximum_field_alignment);
@ -1202,49 +1165,8 @@ place_field (record_layout_info rli, tree field)
if (known_align != actual_align)
layout_decl (field, actual_align);
if (DECL_BIT_FIELD_TYPE (field))
{
unsigned int type_align = TYPE_ALIGN (type);
unsigned int mfa = maximum_field_alignment;
if (integer_zerop (DECL_SIZE (field)))
mfa = initial_max_fld_align * BITS_PER_UNIT;
/* Only the MS bitfields use this. We used to also put any kind of
packed bit fields into prev_field, but that makes no sense, because
an 8 bit packed bit field shouldn't impose more restriction on
following fields than a char field, and the alignment requirements
are also not fulfilled.
There is no sane value to set rli->remaining_in_alignment to when
a packed bitfield in prev_field is unaligned. */
if (mfa != 0)
type_align = MIN (type_align, mfa);
gcc_assert (rli->prev_field
|| actual_align >= type_align || DECL_PACKED (field)
|| integer_zerop (DECL_SIZE (field))
|| !targetm.ms_bitfield_layout_p (rli->t));
if (rli->prev_field == NULL && actual_align >= type_align
&& !integer_zerop (DECL_SIZE (field)))
{
if (rli->prev_field == NULL && DECL_BIT_FIELD_TYPE (field))
rli->prev_field = field;
/* rli->remaining_in_alignment has not been set if the bitfield
has size zero, or if it is a packed bitfield. */
rli->remaining_in_alignment
= (tree_low_cst (TYPE_SIZE (TREE_TYPE (field)), 0)
- tree_low_cst (DECL_SIZE (field), 0));
rli->prev_packed = DECL_PACKED (field);
}
else if (rli->prev_field && DECL_PACKED (field))
{
HOST_WIDE_INT bitsize = tree_low_cst (DECL_SIZE (field), 0);
if (rli->remaining_in_alignment < bitsize)
rli->prev_field = NULL;
else
rli->remaining_in_alignment -= bitsize;
}
}
/* Now add size of this field to the size of the record. If the size is
not constant, treat the field as being a multiple of bytes and just
@ -1268,6 +1190,21 @@ place_field (record_layout_info rli, tree field)
rli->bitpos = bitsize_zero_node;
rli->offset_align = MIN (rli->offset_align, desired_align);
}
else if (targetm.ms_bitfield_layout_p (rli->t))
{
rli->bitpos = size_binop (PLUS_EXPR, rli->bitpos, DECL_SIZE (field));
/* If we ended a bitfield before the full length of the type then
pad the struct out to the full length of the last type. */
if ((TREE_CHAIN (field) == NULL
|| TREE_CODE (TREE_CHAIN (field)) != FIELD_DECL)
&& DECL_BIT_FIELD_TYPE (field)
&& !integer_zerop (DECL_SIZE (field)))
rli->bitpos = size_binop (PLUS_EXPR, rli->bitpos,
bitsize_int (rli->remaining_in_alignment));
normalize_rli (rli);
}
else
{
rli->bitpos = size_binop (PLUS_EXPR, rli->bitpos, DECL_SIZE (field));

View File

@ -1,3 +1,7 @@
2006-06-04 Eric Christopher <echristo@apple.com>
* gcc.dg/attr-ms_struct-1.c: New.
2006-06-04 Mark Shinwell <shinwell@codesourcery.com>
* gcc.c-torture/compile/builtin_constant_p.c: New test.

View File

@ -0,0 +1,164 @@
/* Test for MS structure sizes. */
/* { dg-do run { target *-*-interix* *-*-mingw* *-*-cygwin* i?86-*-darwin* } }
/* { dg-options "-std=gnu99" } */
extern void abort ();
#define ATTR __attribute__((__ms_struct__))
#define size_struct_0 1
#define size_struct_1 4
#define size_struct_2 24
#define size_struct_3 8
#define size_struct_4 32
#define size_struct_5 12
#define size_struct_6 40
#define size_struct_7 8
#define size_struct_8 20
#define size_struct_9 32
struct _struct_0
{
char member_0;
} ATTR;
typedef struct _struct_0 struct_0;
struct _struct_1
{
char member_0;
short member_1:13;
} ATTR;
typedef struct _struct_1 struct_1;
struct _struct_2
{
double member_0;
unsigned char member_1:8;
long member_2:32;
unsigned char member_3:5;
short member_4:14;
short member_5:13;
unsigned char:0;
} ATTR;
typedef struct _struct_2 struct_2;
struct _struct_3
{
unsigned long member_0:26;
unsigned char member_1:2;
} ATTR;
typedef struct _struct_3 struct_3;
struct _struct_4
{
unsigned char member_0:7;
double member_1;
double member_2;
short member_3:5;
char member_4:2;
} ATTR;
typedef struct _struct_4 struct_4;
struct _struct_5
{
unsigned short member_0:12;
long member_1:1;
unsigned short member_2:6;
} ATTR;
typedef struct _struct_5 struct_5;
struct _struct_6
{
unsigned char member_0:7;
unsigned long member_1:25;
char member_2:1;
double member_3;
short member_4:9;
double member_5;
} ATTR;
typedef struct _struct_6 struct_6;
struct _struct_7
{
double member_0;
} ATTR;
typedef struct _struct_7 struct_7;
struct _struct_8
{
unsigned char member_0:7;
long member_1:11;
long member_2:5;
long:0;
char member_4:8;
unsigned short member_5:4;
unsigned char member_6:3;
long member_7:23;
} ATTR;
typedef struct _struct_8 struct_8;
struct _struct_9
{
double member_0;
unsigned long member_1:6;
long member_2:17;
double member_3;
unsigned long member_4:22;
} ATTR;
typedef struct _struct_9 struct_9;
struct_0 test_struct_0 = { 123 };
struct_1 test_struct_1 = { 82, 1081 };
struct_2 test_struct_2 = { 20.0, 31, 407760, 1, 14916, 6712 };
struct_3 test_struct_3 = { 64616999, 1 };
struct_4 test_struct_4 = { 61, 20.0, 20.0, 12, 0 };
struct_5 test_struct_5 = { 909, 1, 57 };
struct_6 test_struct_6 = { 12, 21355796, 0, 20.0, 467, 20.0 };
struct_7 test_struct_7 = { 20.0 };
struct_8 test_struct_8 = { 126, 1821, 22, 125, 6, 0, 2432638 };
struct_9 test_struct_9 = { 20.0, 3, 23957, 20.0, 1001631 };
int
main (void)
{
if (size_struct_0 != sizeof (struct_0))
abort ();
if (size_struct_1 != sizeof (struct_1))
abort ();
if (size_struct_2 != sizeof (struct_2))
abort ();
if (size_struct_3 != sizeof (struct_3))
abort ();
if (size_struct_4 != sizeof (struct_4))
abort ();
if (size_struct_5 != sizeof (struct_5))
abort ();
if (size_struct_6 != sizeof (struct_6))
abort ();
if (size_struct_7 != sizeof (struct_7))
abort ();
if (size_struct_8 != sizeof (struct_8))
abort ();
if (size_struct_9 != sizeof (struct_9))
abort ();
return 0;
}

View File

@ -3775,9 +3775,6 @@ typedef struct record_layout_info_s
tree pending_statics;
/* Bits remaining in the current alignment group */
int remaining_in_alignment;
/* True if prev_field was packed and we haven't found any non-packed
fields that we have put in the same alignment group. */
int prev_packed;
/* True if we've seen a packed field that didn't have normal
alignment anyway. */
int packed_maybe_necessary;