tree.h (record_layout_info_s): New structure.
* tree.h (record_layout_info_s): New structure. (record_layout_info): New type. (new_record_layout_info): New function. (layout_field): Likewise. (finish_record_layout): Likewise. * stor-layout.c (layout_record): Remove. (new_record_layout_info): New function. (layout_field): New function, broken out from layout_record. (finalize_record_size): Likewise. (compute_record_mode): Likewise. (finalize_type_size): New function, broken out from layout_type. (finish_record_layout): Likewise. (layout_type): Use them. From-SVN: r32503
This commit is contained in:
parent
05e126b360
commit
9328904cdf
@ -1,3 +1,19 @@
|
||||
2000-03-13 Mark Mitchell <mark@codesourcery.com>
|
||||
|
||||
* tree.h (record_layout_info_s): New structure.
|
||||
(record_layout_info): New type.
|
||||
(new_record_layout_info): New function.
|
||||
(layout_field): Likewise.
|
||||
(finish_record_layout): Likewise.
|
||||
* stor-layout.c (layout_record): Remove.
|
||||
(new_record_layout_info): New function.
|
||||
(layout_field): New function, broken out from layout_record.
|
||||
(finalize_record_size): Likewise.
|
||||
(compute_record_mode): Likewise.
|
||||
(finalize_type_size): New function, broken out from layout_type.
|
||||
(finish_record_layout): Likewise.
|
||||
(layout_type): Use them.
|
||||
|
||||
2000-03-12 Zack Weinberg <zack@wolery.cumb.org>
|
||||
|
||||
* cpphash.c: Don't include version.h.
|
||||
|
@ -50,8 +50,10 @@ unsigned int maximum_field_alignment;
|
||||
May be overridden by front-ends. */
|
||||
unsigned int set_alignment = 0;
|
||||
|
||||
static tree layout_record PARAMS ((tree));
|
||||
static void layout_union PARAMS ((tree));
|
||||
static void finalize_record_size PARAMS ((record_layout_info));
|
||||
static void compute_record_mode PARAMS ((tree));
|
||||
static void finalize_type_size PARAMS ((tree));
|
||||
|
||||
/* SAVE_EXPRs for sizes of types and decls, waiting to be expanded. */
|
||||
|
||||
@ -400,71 +402,74 @@ layout_decl (decl, known_align)
|
||||
}
|
||||
}
|
||||
|
||||
/* Lay out a RECORD_TYPE type (a C struct).
|
||||
This means laying out the fields, determining their positions,
|
||||
and computing the overall size and required alignment of the record.
|
||||
Note that if you set the TYPE_ALIGN before calling this
|
||||
then the struct is aligned to at least that boundary.
|
||||
/* Create a new record_layout_info for the RECORD_TYPE T. It is the
|
||||
responsibility of the caller to call `free' for the storage the
|
||||
returned. */
|
||||
|
||||
If the type has basetypes, you must call layout_basetypes
|
||||
before calling this function.
|
||||
|
||||
The return value is a list of static members of the record.
|
||||
They still need to be laid out. */
|
||||
|
||||
static tree
|
||||
layout_record (rec)
|
||||
tree rec;
|
||||
record_layout_info
|
||||
new_record_layout_info (t)
|
||||
tree t;
|
||||
{
|
||||
register tree field;
|
||||
unsigned int record_align = MAX (BITS_PER_UNIT, TYPE_ALIGN (rec));
|
||||
unsigned int unpacked_align = record_align;
|
||||
/* These must be laid out *after* the record is. */
|
||||
tree pending_statics = NULL_TREE;
|
||||
/* Record size so far is CONST_SIZE + VAR_SIZE bits,
|
||||
where CONST_SIZE is an integer
|
||||
and VAR_SIZE is a tree expression.
|
||||
If VAR_SIZE is null, the size is just CONST_SIZE.
|
||||
Naturally we try to avoid using VAR_SIZE. */
|
||||
unsigned HOST_WIDE_INT const_size = 0;
|
||||
tree var_size = 0;
|
||||
/* Once we start using VAR_SIZE, this is the maximum alignment
|
||||
that we know VAR_SIZE has. */
|
||||
unsigned int var_align = BITS_PER_UNIT;
|
||||
int packed_maybe_necessary = 0;
|
||||
record_layout_info rli
|
||||
= (record_layout_info) xcalloc (1, sizeof (struct record_layout_info_s));
|
||||
|
||||
rli->t = t;
|
||||
/* If the type has a minimum specified alignment (via an attribute
|
||||
declaration, for example) use it -- otherwise, start with a
|
||||
one-byte alignment. */
|
||||
rli->record_align = MAX (BITS_PER_UNIT, TYPE_ALIGN (t));
|
||||
rli->unpacked_align = rli->record_align;
|
||||
|
||||
#ifdef STRUCTURE_SIZE_BOUNDARY
|
||||
/* Packed structures don't need to have minimum size. */
|
||||
if (! TYPE_PACKED (rec))
|
||||
record_align = MAX (record_align, STRUCTURE_SIZE_BOUNDARY);
|
||||
rli->record_align = MAX (rli->record_align, STRUCTURE_SIZE_BOUNDARY);
|
||||
#endif
|
||||
|
||||
for (field = TYPE_FIELDS (rec); field; field = TREE_CHAIN (field))
|
||||
{
|
||||
unsigned int known_align = var_size ? var_align : const_size;
|
||||
unsigned int desired_align = 0;
|
||||
tree type = TREE_TYPE (field);
|
||||
|
||||
/* If FIELD is static, then treat it like a separate variable,
|
||||
not really like a structure field.
|
||||
If it is a FUNCTION_DECL, it's a method.
|
||||
In both cases, all we do is lay out the decl,
|
||||
and we do it *after* the record is laid out. */
|
||||
|
||||
if (TREE_CODE (field) == VAR_DECL)
|
||||
{
|
||||
pending_statics = tree_cons (NULL_TREE, field, pending_statics);
|
||||
continue;
|
||||
return rli;
|
||||
}
|
||||
|
||||
/* RLI contains information about the layout of a RECORD_TYPE. FIELD
|
||||
is a FIELD_DECL to be added after those fields already present in
|
||||
T. (FIELD is not actually added to the TYPE_FIELDS list here;
|
||||
callers that desire that behavior must manually perform that step.) */
|
||||
|
||||
void
|
||||
layout_field (rli, field)
|
||||
record_layout_info rli;
|
||||
tree field;
|
||||
{
|
||||
/* The alignment required for FIELD. */
|
||||
unsigned int desired_align;
|
||||
/* The alignment FIELD would have if we just dropped it into the
|
||||
record as it presently stands. */
|
||||
unsigned int known_align;
|
||||
/* The type of this field. */
|
||||
tree type = TREE_TYPE (field);
|
||||
/* The size of this field, in bits. */
|
||||
tree dsize;
|
||||
|
||||
/* If FIELD is static, then treat it like a separate variable, not
|
||||
really like a structure field. If it is a FUNCTION_DECL, it's a
|
||||
method. In both cases, all we do is lay out the decl, and we do
|
||||
it *after* the record is laid out. */
|
||||
if (TREE_CODE (field) == VAR_DECL)
|
||||
{
|
||||
rli->pending_statics = tree_cons (NULL_TREE, field,
|
||||
rli->pending_statics);
|
||||
return;
|
||||
}
|
||||
/* Enumerators and enum types which are local to this class need not
|
||||
be laid out. Likewise for initialized constant fields. */
|
||||
if (TREE_CODE (field) != FIELD_DECL)
|
||||
continue;
|
||||
else if (TREE_CODE (field) != FIELD_DECL)
|
||||
return;
|
||||
|
||||
/* Lay out the field so we know what alignment it needs.
|
||||
For a packed field, use the alignment as specified,
|
||||
disregarding what the type would want. */
|
||||
/* Work out the known alignment so far. */
|
||||
known_align = rli->var_size ? rli->var_align : rli->const_size;
|
||||
|
||||
/* Lay out the field so we know what alignment it needs. For a
|
||||
packed field, use the alignment as specified, disregarding what
|
||||
the type would want. */
|
||||
if (DECL_PACKED (field))
|
||||
desired_align = DECL_ALIGN (field);
|
||||
layout_decl (field, known_align);
|
||||
@ -480,9 +485,8 @@ layout_record (rec)
|
||||
#endif
|
||||
|
||||
/* Record must have at least as much alignment as any field.
|
||||
Otherwise, the alignment of the field within the record
|
||||
is meaningless. */
|
||||
|
||||
Otherwise, the alignment of the field within the record is
|
||||
meaningless. */
|
||||
#ifdef PCC_BITFIELD_TYPE_MATTERS
|
||||
if (PCC_BITFIELD_TYPE_MATTERS && type != error_mark_node
|
||||
&& DECL_BIT_FIELD_TYPE (field)
|
||||
@ -493,7 +497,7 @@ layout_record (rec)
|
||||
It does, however, affect the alignment of the next field
|
||||
within the structure. */
|
||||
if (! integer_zerop (DECL_SIZE (field)))
|
||||
record_align = MAX (record_align, desired_align);
|
||||
rli->record_align = MAX (rli->record_align, desired_align);
|
||||
else if (! DECL_PACKED (field))
|
||||
desired_align = TYPE_ALIGN (type);
|
||||
/* A named bit field of declared type `int'
|
||||
@ -507,23 +511,25 @@ layout_record (rec)
|
||||
else if (DECL_PACKED (field))
|
||||
type_align = MIN (type_align, BITS_PER_UNIT);
|
||||
|
||||
record_align = MAX (record_align, type_align);
|
||||
rli->record_align = MAX (rli->record_align, type_align);
|
||||
if (warn_packed)
|
||||
unpacked_align = MAX (unpacked_align, TYPE_ALIGN (type));
|
||||
rli->unpacked_align = MAX (rli->unpacked_align,
|
||||
TYPE_ALIGN (type));
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
record_align = MAX (record_align, desired_align);
|
||||
rli->record_align = MAX (rli->record_align, desired_align);
|
||||
if (warn_packed)
|
||||
unpacked_align = MAX (unpacked_align, TYPE_ALIGN (type));
|
||||
rli->unpacked_align = MAX (rli->unpacked_align, TYPE_ALIGN (type));
|
||||
}
|
||||
|
||||
if (warn_packed && DECL_PACKED (field))
|
||||
{
|
||||
if (const_size % TYPE_ALIGN (type) == 0
|
||||
|| (var_align % TYPE_ALIGN (type) == 0 && var_size != NULL_TREE))
|
||||
if (rli->const_size % TYPE_ALIGN (type) == 0
|
||||
|| (rli->var_align % TYPE_ALIGN (type) == 0
|
||||
&& rli->var_size != NULL_TREE))
|
||||
{
|
||||
if (TYPE_ALIGN (type) > desired_align)
|
||||
{
|
||||
@ -534,15 +540,14 @@ layout_record (rec)
|
||||
}
|
||||
}
|
||||
else
|
||||
packed_maybe_necessary = 1;
|
||||
rli->packed_maybe_necessary = 1;
|
||||
}
|
||||
|
||||
/* Does this field automatically have alignment it needs
|
||||
by virtue of the fields that precede it and the record's
|
||||
own alignment? */
|
||||
|
||||
if (const_size % desired_align != 0
|
||||
|| (var_align % desired_align != 0 && var_size != NULL_TREE))
|
||||
/* Does this field automatically have alignment it needs by virtue
|
||||
of the fields that precede it and the record's own alignment? */
|
||||
if (rli->const_size % desired_align != 0
|
||||
|| (rli->var_align % desired_align != 0
|
||||
&& rli->var_size != NULL_TREE))
|
||||
{
|
||||
/* No, we need to skip space before this field.
|
||||
Bump the cumulative size to multiple of field alignment. */
|
||||
@ -550,17 +555,17 @@ layout_record (rec)
|
||||
if (warn_padded)
|
||||
warning_with_decl (field, "padding struct to align `%s'");
|
||||
|
||||
if (var_size == NULL_TREE || var_align % desired_align == 0)
|
||||
const_size
|
||||
= CEIL (const_size, desired_align) * desired_align;
|
||||
if (rli->var_size == NULL_TREE || rli->var_align % desired_align == 0)
|
||||
rli->const_size
|
||||
= CEIL (rli->const_size, desired_align) * desired_align;
|
||||
else
|
||||
{
|
||||
if (const_size > 0)
|
||||
var_size = size_binop (PLUS_EXPR, var_size,
|
||||
bitsize_int (const_size));
|
||||
const_size = 0;
|
||||
var_size = round_up (var_size, desired_align);
|
||||
var_align = MIN (var_align, desired_align);
|
||||
if (rli->const_size > 0)
|
||||
rli->var_size = size_binop (PLUS_EXPR, rli->var_size,
|
||||
bitsize_int (rli->const_size));
|
||||
rli->const_size = 0;
|
||||
rli->var_size = round_up (rli->var_size, desired_align);
|
||||
rli->var_align = MIN (rli->var_align, desired_align);
|
||||
}
|
||||
}
|
||||
|
||||
@ -579,15 +584,15 @@ layout_record (rec)
|
||||
|
||||
/* A bit field may not span more units of alignment of its type
|
||||
than its type itself. Advance to next boundary if necessary. */
|
||||
if (((const_size + field_size + type_align - 1) / type_align
|
||||
- const_size / type_align)
|
||||
if (((rli->const_size + field_size + type_align - 1) / type_align
|
||||
- rli->const_size / type_align)
|
||||
> TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (field))) / type_align)
|
||||
const_size = CEIL (const_size, type_align) * type_align;
|
||||
rli->const_size = CEIL (rli->const_size, type_align) * type_align;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* No existing machine description uses this parameter.
|
||||
So I have made it in this aspect identical to PCC_BITFIELD_TYPE_MATTERS. */
|
||||
/* No existing machine description uses this parameter. So I have
|
||||
made it in this aspect identical to PCC_BITFIELD_TYPE_MATTERS. */
|
||||
#ifdef BITFIELD_NBYTES_LIMITED
|
||||
if (BITFIELD_NBYTES_LIMITED
|
||||
&& TREE_CODE (field) == FIELD_DECL
|
||||
@ -611,35 +616,33 @@ layout_record (rec)
|
||||
Advance to next boundary if necessary. */
|
||||
/* ??? This code should match the code above for the
|
||||
PCC_BITFIELD_TYPE_MATTERS case. */
|
||||
if (const_size / type_align
|
||||
!= (const_size + field_size - 1) / type_align)
|
||||
const_size = CEIL (const_size, type_align) * type_align;
|
||||
if (rli->const_size / type_align
|
||||
!= (rli->const_size + field_size - 1) / type_align)
|
||||
rli->const_size = CEIL (rli->const_size, type_align) * type_align;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Size so far becomes the position of this field. */
|
||||
|
||||
if (var_size && const_size)
|
||||
if (rli->var_size && rli->const_size)
|
||||
DECL_FIELD_BITPOS (field)
|
||||
= size_binop (PLUS_EXPR, var_size, bitsize_int (const_size));
|
||||
else if (var_size)
|
||||
DECL_FIELD_BITPOS (field) = var_size;
|
||||
= size_binop (PLUS_EXPR, rli->var_size, bitsize_int (rli->const_size));
|
||||
else if (rli->var_size)
|
||||
DECL_FIELD_BITPOS (field) = rli->var_size;
|
||||
else
|
||||
{
|
||||
DECL_FIELD_BITPOS (field) = bitsize_int (const_size);
|
||||
DECL_FIELD_BITPOS (field) = bitsize_int (rli->const_size);
|
||||
|
||||
/* If this field ended up more aligned than we thought it
|
||||
would be (we approximate this by seeing if its position
|
||||
changed), lay out the field again; perhaps we can use an
|
||||
integral mode for it now. */
|
||||
if (known_align != const_size)
|
||||
layout_decl (field, const_size);
|
||||
if (known_align != rli->const_size)
|
||||
layout_decl (field, rli->const_size);
|
||||
}
|
||||
|
||||
/* Now add size of this field to the size of the record. */
|
||||
|
||||
{
|
||||
register tree dsize = DECL_SIZE (field);
|
||||
dsize = DECL_SIZE (field);
|
||||
|
||||
/* This can happen when we have an invalid nested struct definition,
|
||||
such as struct j { struct j { int i; } }. The error message is
|
||||
@ -649,94 +652,103 @@ layout_record (rec)
|
||||
else if (TREE_CODE (dsize) == INTEGER_CST
|
||||
&& ! TREE_CONSTANT_OVERFLOW (dsize)
|
||||
&& TREE_INT_CST_HIGH (dsize) == 0
|
||||
&& TREE_INT_CST_LOW (dsize) + const_size >= const_size)
|
||||
&& TREE_INT_CST_LOW (dsize) + rli->const_size >= rli->const_size)
|
||||
/* Use const_size if there's no overflow. */
|
||||
const_size += TREE_INT_CST_LOW (dsize);
|
||||
rli->const_size += TREE_INT_CST_LOW (dsize);
|
||||
else
|
||||
{
|
||||
if (var_size == NULL_TREE)
|
||||
var_size = dsize;
|
||||
if (rli->var_size == NULL_TREE)
|
||||
rli->var_size = dsize;
|
||||
else
|
||||
var_size = size_binop (PLUS_EXPR, var_size, dsize);
|
||||
}
|
||||
rli->var_size = size_binop (PLUS_EXPR, rli->var_size, dsize);
|
||||
}
|
||||
}
|
||||
|
||||
/* Work out the total size and alignment of the record
|
||||
as one expression and store in the record type.
|
||||
Round it up to a multiple of the record's alignment. */
|
||||
/* Assuming that all the fields have been laid out, this function uses
|
||||
RLI to compute the final TYPE_SIZE, TYPE_ALIGN, etc. for the type
|
||||
inidicated by RLI. */
|
||||
|
||||
if (var_size == NULL_TREE)
|
||||
TYPE_SIZE (rec) = bitsize_int (const_size);
|
||||
static void
|
||||
finalize_record_size (rli)
|
||||
record_layout_info rli;
|
||||
{
|
||||
/* Work out the total size and alignment of the record as one
|
||||
expression and store in the record type. Round it up to a
|
||||
multiple of the record's alignment. */
|
||||
if (rli->var_size == NULL_TREE)
|
||||
TYPE_SIZE (rli->t) = bitsize_int (rli->const_size);
|
||||
else
|
||||
{
|
||||
if (const_size)
|
||||
var_size = size_binop (PLUS_EXPR, var_size, bitsize_int (const_size));
|
||||
|
||||
TYPE_SIZE (rec) = var_size;
|
||||
if (rli->const_size)
|
||||
rli->var_size = size_binop (PLUS_EXPR, rli->var_size,
|
||||
bitsize_int (rli->const_size));
|
||||
TYPE_SIZE (rli->t) = rli->var_size;
|
||||
}
|
||||
|
||||
/* Determine the desired alignment. */
|
||||
#ifdef ROUND_TYPE_ALIGN
|
||||
TYPE_ALIGN (rec) = ROUND_TYPE_ALIGN (rec, TYPE_ALIGN (rec), record_align);
|
||||
TYPE_ALIGN (rli->t) = ROUND_TYPE_ALIGN (rli->t, TYPE_ALIGN (rli->t),
|
||||
record_align);
|
||||
#else
|
||||
TYPE_ALIGN (rec) = MAX (TYPE_ALIGN (rec), record_align);
|
||||
TYPE_ALIGN (rli->t) = MAX (TYPE_ALIGN (rli->t), rli->record_align);
|
||||
#endif
|
||||
|
||||
/* Record the un-rounded size in the binfo node. But first we check
|
||||
the size of TYPE_BINFO to make sure that BINFO_SIZE is available. */
|
||||
if (TYPE_BINFO (rec) && TREE_VEC_LENGTH (TYPE_BINFO (rec)) > 6)
|
||||
if (TYPE_BINFO (rli->t) && TREE_VEC_LENGTH (TYPE_BINFO (rli->t)) > 6)
|
||||
{
|
||||
TYPE_BINFO_SIZE (rec) = TYPE_SIZE (rec);
|
||||
TYPE_BINFO_SIZE_UNIT (rec)
|
||||
TYPE_BINFO_SIZE (rli->t) = TYPE_SIZE (rli->t);
|
||||
TYPE_BINFO_SIZE_UNIT (rli->t)
|
||||
= convert (sizetype,
|
||||
size_binop (FLOOR_DIV_EXPR, TYPE_SIZE (rec),
|
||||
size_binop (FLOOR_DIV_EXPR, TYPE_SIZE (rli->t),
|
||||
bitsize_int (BITS_PER_UNIT)));
|
||||
}
|
||||
|
||||
{
|
||||
tree unpadded_size = TYPE_SIZE (rec);
|
||||
tree unpadded_size = TYPE_SIZE (rli->t);
|
||||
|
||||
#ifdef ROUND_TYPE_SIZE
|
||||
TYPE_SIZE (rec) = ROUND_TYPE_SIZE (rec, TYPE_SIZE (rec), TYPE_ALIGN (rec));
|
||||
TYPE_SIZE (rli->t) = ROUND_TYPE_SIZE (rli->t, TYPE_SIZE (rli->t),
|
||||
TYPE_ALIGN (rli->t));
|
||||
#else
|
||||
/* Round the size up to be a multiple of the required alignment */
|
||||
TYPE_SIZE (rec) = round_up (TYPE_SIZE (rec), TYPE_ALIGN (rec));
|
||||
TYPE_SIZE (rli->t) = round_up (TYPE_SIZE (rli->t), TYPE_ALIGN (rli->t));
|
||||
#endif
|
||||
|
||||
if (warn_padded && var_size == NULL_TREE
|
||||
&& simple_cst_equal (unpadded_size, TYPE_SIZE (rec)) == 0)
|
||||
if (warn_padded && rli->var_size == NULL_TREE
|
||||
&& simple_cst_equal (unpadded_size, TYPE_SIZE (rli->t)) == 0)
|
||||
warning ("padding struct size to alignment boundary");
|
||||
}
|
||||
|
||||
if (warn_packed && TYPE_PACKED (rec) && !packed_maybe_necessary
|
||||
&& var_size == NULL_TREE)
|
||||
if (warn_packed && TYPE_PACKED (rli->t) && !rli->packed_maybe_necessary
|
||||
&& rli->var_size == NULL_TREE)
|
||||
{
|
||||
tree unpacked_size;
|
||||
|
||||
TYPE_PACKED (rec) = 0;
|
||||
TYPE_PACKED (rli->t) = 0;
|
||||
#ifdef ROUND_TYPE_ALIGN
|
||||
unpacked_align
|
||||
= ROUND_TYPE_ALIGN (rec, TYPE_ALIGN (rec), unpacked_align);
|
||||
rli->unpacked_align
|
||||
= ROUND_TYPE_ALIGN (rli->t, TYPE_ALIGN (rli->t), rli->unpacked_align);
|
||||
#else
|
||||
unpacked_align = MAX (TYPE_ALIGN (rec), unpacked_align);
|
||||
rli->unpacked_align = MAX (TYPE_ALIGN (rli->t), rli->unpacked_align);
|
||||
#endif
|
||||
#ifdef ROUND_TYPE_SIZE
|
||||
unpacked_size = ROUND_TYPE_SIZE (rec, TYPE_SIZE (rec), unpacked_align);
|
||||
unpacked_size = ROUND_TYPE_SIZE (rli->t, TYPE_SIZE (rli->t),
|
||||
rli->unpacked_align);
|
||||
#else
|
||||
unpacked_size = round_up (TYPE_SIZE (rec), unpacked_align);
|
||||
unpacked_size = round_up (TYPE_SIZE (rli->t), rli->unpacked_align);
|
||||
#endif
|
||||
|
||||
if (simple_cst_equal (unpacked_size, TYPE_SIZE (rec)))
|
||||
if (simple_cst_equal (unpacked_size, TYPE_SIZE (rli->t)))
|
||||
{
|
||||
if (TYPE_NAME (rec))
|
||||
if (TYPE_NAME (rli->t))
|
||||
{
|
||||
char *name;
|
||||
|
||||
if (TREE_CODE (TYPE_NAME (rec)) == IDENTIFIER_NODE)
|
||||
name = IDENTIFIER_POINTER (TYPE_NAME (rec));
|
||||
if (TREE_CODE (TYPE_NAME (rli->t)) == IDENTIFIER_NODE)
|
||||
name = IDENTIFIER_POINTER (TYPE_NAME (rli->t));
|
||||
else
|
||||
name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (rec)));
|
||||
name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (rli->t)));
|
||||
if (STRICT_ALIGNMENT)
|
||||
warning ("packed attribute causes inefficient alignment for `%s'", name);
|
||||
else
|
||||
@ -750,11 +762,192 @@ layout_record (rec)
|
||||
warning ("packed attribute is unnecessary");
|
||||
}
|
||||
}
|
||||
TYPE_PACKED (rec) = 1;
|
||||
TYPE_PACKED (rli->t) = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return pending_statics;
|
||||
/* Compute the TYPE_MODE for the TYPE (which is a RECORD_TYPE). */
|
||||
|
||||
static void
|
||||
compute_record_mode (type)
|
||||
tree type;
|
||||
{
|
||||
/* Most RECORD_TYPEs have BLKmode, so we start off assuming that.
|
||||
However, if possible, we use a mode that fits in a register
|
||||
instead, in order to allow for better optimization down the
|
||||
line. */
|
||||
TYPE_MODE (type) = BLKmode;
|
||||
if (TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
|
||||
{
|
||||
tree field;
|
||||
enum machine_mode mode = VOIDmode;
|
||||
|
||||
/* A record which has any BLKmode members must itself be
|
||||
BLKmode; it can't go in a register. Unless the member is
|
||||
BLKmode only because it isn't aligned. */
|
||||
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
|
||||
{
|
||||
unsigned HOST_WIDE_INT bitpos;
|
||||
|
||||
if (TREE_CODE (field) != FIELD_DECL
|
||||
|| TREE_CODE (TREE_TYPE (field)) == ERROR_MARK)
|
||||
continue;
|
||||
|
||||
if (TYPE_MODE (TREE_TYPE (field)) == BLKmode
|
||||
&& ! TYPE_NO_FORCE_BLK (TREE_TYPE (field)))
|
||||
return;
|
||||
|
||||
if (TREE_CODE (DECL_FIELD_BITPOS (field)) != INTEGER_CST)
|
||||
return;
|
||||
|
||||
bitpos = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field));
|
||||
|
||||
/* Must be BLKmode if any field crosses a word boundary,
|
||||
since extract_bit_field can't handle that in registers. */
|
||||
if (bitpos / BITS_PER_WORD
|
||||
!= ((TREE_INT_CST_LOW (DECL_SIZE (field)) + bitpos - 1)
|
||||
/ BITS_PER_WORD)
|
||||
/* But there is no problem if the field is entire words. */
|
||||
&& TREE_INT_CST_LOW (DECL_SIZE (field)) % BITS_PER_WORD != 0)
|
||||
return;
|
||||
|
||||
/* If this field is the whole struct, remember its mode so
|
||||
that, say, we can put a double in a class into a DF
|
||||
register instead of forcing it to live in the stack. */
|
||||
if (simple_cst_equal (TYPE_SIZE (type), DECL_SIZE (field)))
|
||||
mode = DECL_MODE (field);
|
||||
|
||||
#ifdef STRUCT_FORCE_BLK
|
||||
/* With some targets, eg. c4x, it is sub-optimal
|
||||
to access an aligned BLKmode structure as a scalar. */
|
||||
if (mode == VOIDmode && STRUCT_FORCE_BLK (field))
|
||||
return;
|
||||
#endif /* STRUCT_FORCE_BLK */
|
||||
}
|
||||
|
||||
if (mode != VOIDmode)
|
||||
/* We only have one real field; use its mode. */
|
||||
TYPE_MODE (type) = mode;
|
||||
else
|
||||
TYPE_MODE (type)
|
||||
= mode_for_size_tree (TYPE_SIZE (type), MODE_INT, 1);
|
||||
|
||||
/* If structure's known alignment is less than what the scalar
|
||||
mode would need, and it matters, then stick with BLKmode. */
|
||||
if (TYPE_MODE (type) != BLKmode
|
||||
&& STRICT_ALIGNMENT
|
||||
&& ! (TYPE_ALIGN (type) >= BIGGEST_ALIGNMENT
|
||||
|| (TYPE_ALIGN (type) >=
|
||||
GET_MODE_ALIGNMENT (TYPE_MODE (type)))))
|
||||
{
|
||||
/* If this is the only reason this type is BLKmode, then
|
||||
don't force containing types to be BLKmode. */
|
||||
TYPE_NO_FORCE_BLK (type) = 1;
|
||||
TYPE_MODE (type) = BLKmode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute TYPE_SIZE and TYPE_ALIGN for TYPE, once it has been laid
|
||||
out. */
|
||||
|
||||
static void
|
||||
finalize_type_size (type)
|
||||
tree type;
|
||||
{
|
||||
/* Normally, use the alignment corresponding to the mode chosen.
|
||||
However, where strict alignment is not required, avoid
|
||||
over-aligning structures, since most compilers do not do this
|
||||
alignment. */
|
||||
|
||||
if (TYPE_MODE (type) != BLKmode && TYPE_MODE (type) != VOIDmode
|
||||
&& (STRICT_ALIGNMENT
|
||||
|| (TREE_CODE (type) != RECORD_TYPE && TREE_CODE (type) != UNION_TYPE
|
||||
&& TREE_CODE (type) != QUAL_UNION_TYPE
|
||||
&& TREE_CODE (type) != ARRAY_TYPE)))
|
||||
TYPE_ALIGN (type) = GET_MODE_ALIGNMENT (TYPE_MODE (type));
|
||||
|
||||
/* Do machine-dependent extra alignment. */
|
||||
#ifdef ROUND_TYPE_ALIGN
|
||||
TYPE_ALIGN (type)
|
||||
= ROUND_TYPE_ALIGN (type, TYPE_ALIGN (type), BITS_PER_UNIT);
|
||||
#endif
|
||||
|
||||
#ifdef ROUND_TYPE_SIZE
|
||||
if (TYPE_SIZE (type) != 0)
|
||||
TYPE_SIZE (type)
|
||||
= ROUND_TYPE_SIZE (type, TYPE_SIZE (type), TYPE_ALIGN (type));
|
||||
#endif
|
||||
|
||||
/* Evaluate nonconstant size only once, either now or as soon as safe. */
|
||||
if (TYPE_SIZE (type) != 0 && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
|
||||
TYPE_SIZE (type) = variable_size (TYPE_SIZE (type));
|
||||
|
||||
/* If we failed to find a simple way to calculate the unit size
|
||||
of the type above, find it by division. */
|
||||
if (TYPE_SIZE_UNIT (type) == 0 && TYPE_SIZE (type) != 0)
|
||||
/* TYPE_SIZE (type) is computed in bitsizetype. After the division, the
|
||||
result will fit in sizetype. We will get more efficient code using
|
||||
sizetype, so we force a conversion. */
|
||||
TYPE_SIZE_UNIT (type)
|
||||
= convert (sizetype,
|
||||
size_binop (FLOOR_DIV_EXPR, TYPE_SIZE (type),
|
||||
bitsize_int (BITS_PER_UNIT)));
|
||||
|
||||
/* Once again evaluate only once, either now or as soon as safe. */
|
||||
if (TYPE_SIZE_UNIT (type) != 0
|
||||
&& TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST)
|
||||
TYPE_SIZE_UNIT (type) = variable_size (TYPE_SIZE_UNIT (type));
|
||||
|
||||
/* Also layout any other variants of the type. */
|
||||
if (TYPE_NEXT_VARIANT (type)
|
||||
|| type != TYPE_MAIN_VARIANT (type))
|
||||
{
|
||||
tree variant;
|
||||
/* Record layout info of this variant. */
|
||||
tree size = TYPE_SIZE (type);
|
||||
tree size_unit = TYPE_SIZE_UNIT (type);
|
||||
unsigned int align = TYPE_ALIGN (type);
|
||||
enum machine_mode mode = TYPE_MODE (type);
|
||||
|
||||
/* Copy it into all variants. */
|
||||
for (variant = TYPE_MAIN_VARIANT (type);
|
||||
variant != 0;
|
||||
variant = TYPE_NEXT_VARIANT (variant))
|
||||
{
|
||||
TYPE_SIZE (variant) = size;
|
||||
TYPE_SIZE_UNIT (variant) = size_unit;
|
||||
TYPE_ALIGN (variant) = align;
|
||||
TYPE_MODE (variant) = mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Do all of the work required to layout the type indicated by RLI,
|
||||
once the fields have been laid out. This function will call `free'
|
||||
for RLI. */
|
||||
|
||||
void
|
||||
finish_record_layout (rli)
|
||||
record_layout_info rli;
|
||||
{
|
||||
/* Compute the final size. */
|
||||
finalize_record_size (rli);
|
||||
/* Compute the TYPE_MODE for the record. */
|
||||
compute_record_mode (rli->t);
|
||||
/* Lay out any static members. This is done now because their type
|
||||
may use the record's type. */
|
||||
while (rli->pending_statics)
|
||||
{
|
||||
layout_decl (TREE_VALUE (rli->pending_statics), 0);
|
||||
rli->pending_statics = TREE_CHAIN (rli->pending_statics);
|
||||
}
|
||||
/* Perform any last tweaks to the TYPE_SIZE, etc. */
|
||||
finalize_type_size (rli->t);
|
||||
/* Clean up. */
|
||||
free (rli);
|
||||
}
|
||||
|
||||
|
||||
/* Lay out a UNION_TYPE or QUAL_UNION_TYPE type.
|
||||
Lay out all the fields, set their positions to zero,
|
||||
@ -877,7 +1070,6 @@ layout_type (type)
|
||||
tree type;
|
||||
{
|
||||
int old;
|
||||
tree pending_statics;
|
||||
|
||||
if (type == 0)
|
||||
abort ();
|
||||
@ -886,8 +1078,8 @@ layout_type (type)
|
||||
if (TYPE_SIZE (type))
|
||||
return;
|
||||
|
||||
/* Make sure all nodes we allocate are not momentary;
|
||||
they must last past the current statement. */
|
||||
/* Make sure all nodes we allocate are not momentary; they must last
|
||||
past the current statement. */
|
||||
old = suspend_momentary ();
|
||||
|
||||
/* Put all our nodes into the same obstack as the type. Also,
|
||||
@ -1095,87 +1287,17 @@ layout_type (type)
|
||||
}
|
||||
|
||||
case RECORD_TYPE:
|
||||
pending_statics = layout_record (type);
|
||||
TYPE_MODE (type) = BLKmode;
|
||||
if (TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
|
||||
{
|
||||
tree field;
|
||||
enum machine_mode mode = VOIDmode;
|
||||
record_layout_info rli;
|
||||
|
||||
/* A record which has any BLKmode members must itself be BLKmode;
|
||||
it can't go in a register.
|
||||
Unless the member is BLKmode only because it isn't aligned. */
|
||||
/* Initialize the layout information. */
|
||||
rli = new_record_layout_info (type);
|
||||
/* Layout all the fields. */
|
||||
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
|
||||
{
|
||||
unsigned HOST_WIDE_INT bitpos;
|
||||
|
||||
if (TREE_CODE (field) != FIELD_DECL
|
||||
|| TREE_CODE (TREE_TYPE (field)) == ERROR_MARK)
|
||||
continue;
|
||||
|
||||
if (TYPE_MODE (TREE_TYPE (field)) == BLKmode
|
||||
&& ! TYPE_NO_FORCE_BLK (TREE_TYPE (field)))
|
||||
goto record_lose;
|
||||
|
||||
if (TREE_CODE (DECL_FIELD_BITPOS (field)) != INTEGER_CST)
|
||||
goto record_lose;
|
||||
|
||||
bitpos = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field));
|
||||
|
||||
/* Must be BLKmode if any field crosses a word boundary,
|
||||
since extract_bit_field can't handle that in registers. */
|
||||
if (bitpos / BITS_PER_WORD
|
||||
!= ((TREE_INT_CST_LOW (DECL_SIZE (field)) + bitpos - 1)
|
||||
/ BITS_PER_WORD)
|
||||
/* But there is no problem if the field is entire words. */
|
||||
&& TREE_INT_CST_LOW (DECL_SIZE (field)) % BITS_PER_WORD != 0)
|
||||
goto record_lose;
|
||||
|
||||
/* If this field is the whole struct, remember its mode so
|
||||
that, say, we can put a double in a class into a DF
|
||||
register instead of forcing it to live in the stack. */
|
||||
if (simple_cst_equal (TYPE_SIZE (type), DECL_SIZE (field)))
|
||||
mode = DECL_MODE (field);
|
||||
|
||||
#ifdef STRUCT_FORCE_BLK
|
||||
/* With some targets, eg. c4x, it is sub-optimal
|
||||
to access an aligned BLKmode structure as a scalar. */
|
||||
if (mode == VOIDmode && STRUCT_FORCE_BLK (field))
|
||||
goto record_lose;
|
||||
#endif /* STRUCT_FORCE_BLK */
|
||||
}
|
||||
|
||||
if (mode != VOIDmode)
|
||||
/* We only have one real field; use its mode. */
|
||||
TYPE_MODE (type) = mode;
|
||||
else
|
||||
TYPE_MODE (type)
|
||||
= mode_for_size_tree (TYPE_SIZE (type), MODE_INT, 1);
|
||||
|
||||
/* If structure's known alignment is less than
|
||||
what the scalar mode would need, and it matters,
|
||||
then stick with BLKmode. */
|
||||
if (TYPE_MODE (type) != BLKmode
|
||||
&& STRICT_ALIGNMENT
|
||||
&& ! (TYPE_ALIGN (type) >= BIGGEST_ALIGNMENT
|
||||
|| (TYPE_ALIGN (type) >=
|
||||
GET_MODE_ALIGNMENT (TYPE_MODE (type)))))
|
||||
{
|
||||
/* If this is the only reason this type is BLKmode,
|
||||
then don't force containing types to be BLKmode. */
|
||||
TYPE_NO_FORCE_BLK (type) = 1;
|
||||
TYPE_MODE (type) = BLKmode;
|
||||
}
|
||||
|
||||
record_lose: ;
|
||||
}
|
||||
|
||||
/* Lay out any static members. This is done now
|
||||
because their type may use the record's type. */
|
||||
while (pending_statics)
|
||||
{
|
||||
layout_decl (TREE_VALUE (pending_statics), 0);
|
||||
pending_statics = TREE_CHAIN (pending_statics);
|
||||
layout_field (rli, field);
|
||||
/* Finish laying out the record. */
|
||||
finish_record_layout (rli);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1253,72 +1375,10 @@ layout_type (type)
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* Normally, use the alignment corresponding to the mode chosen.
|
||||
However, where strict alignment is not required, avoid
|
||||
over-aligning structures, since most compilers do not do this
|
||||
alignment. */
|
||||
|
||||
if (TYPE_MODE (type) != BLKmode && TYPE_MODE (type) != VOIDmode
|
||||
&& (STRICT_ALIGNMENT
|
||||
|| (TREE_CODE (type) != RECORD_TYPE && TREE_CODE (type) != UNION_TYPE
|
||||
&& TREE_CODE (type) != QUAL_UNION_TYPE
|
||||
&& TREE_CODE (type) != ARRAY_TYPE)))
|
||||
TYPE_ALIGN (type) = GET_MODE_ALIGNMENT (TYPE_MODE (type));
|
||||
|
||||
/* Do machine-dependent extra alignment. */
|
||||
#ifdef ROUND_TYPE_ALIGN
|
||||
TYPE_ALIGN (type)
|
||||
= ROUND_TYPE_ALIGN (type, TYPE_ALIGN (type), BITS_PER_UNIT);
|
||||
#endif
|
||||
|
||||
#ifdef ROUND_TYPE_SIZE
|
||||
if (TYPE_SIZE (type) != 0)
|
||||
TYPE_SIZE (type)
|
||||
= ROUND_TYPE_SIZE (type, TYPE_SIZE (type), TYPE_ALIGN (type));
|
||||
#endif
|
||||
|
||||
/* Evaluate nonconstant size only once, either now or as soon as safe. */
|
||||
if (TYPE_SIZE (type) != 0 && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
|
||||
TYPE_SIZE (type) = variable_size (TYPE_SIZE (type));
|
||||
|
||||
/* If we failed to find a simple way to calculate the unit size
|
||||
of the type above, find it by division. */
|
||||
if (TYPE_SIZE_UNIT (type) == 0 && TYPE_SIZE (type) != 0)
|
||||
/* TYPE_SIZE (type) is computed in bitsizetype. After the division, the
|
||||
result will fit in sizetype. We will get more efficient code using
|
||||
sizetype, so we force a conversion. */
|
||||
TYPE_SIZE_UNIT (type)
|
||||
= convert (sizetype,
|
||||
size_binop (FLOOR_DIV_EXPR, TYPE_SIZE (type),
|
||||
bitsize_int (BITS_PER_UNIT)));
|
||||
|
||||
/* Once again evaluate only once, either now or as soon as safe. */
|
||||
if (TYPE_SIZE_UNIT (type) != 0
|
||||
&& TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST)
|
||||
TYPE_SIZE_UNIT (type) = variable_size (TYPE_SIZE_UNIT (type));
|
||||
|
||||
/* Also layout any other variants of the type. */
|
||||
if (TYPE_NEXT_VARIANT (type)
|
||||
|| type != TYPE_MAIN_VARIANT (type))
|
||||
{
|
||||
tree variant;
|
||||
/* Record layout info of this variant. */
|
||||
tree size = TYPE_SIZE (type);
|
||||
tree size_unit = TYPE_SIZE_UNIT (type);
|
||||
unsigned int align = TYPE_ALIGN (type);
|
||||
enum machine_mode mode = TYPE_MODE (type);
|
||||
|
||||
/* Copy it into all variants. */
|
||||
for (variant = TYPE_MAIN_VARIANT (type);
|
||||
variant != 0;
|
||||
variant = TYPE_NEXT_VARIANT (variant))
|
||||
{
|
||||
TYPE_SIZE (variant) = size;
|
||||
TYPE_SIZE_UNIT (variant) = size_unit;
|
||||
TYPE_ALIGN (variant) = align;
|
||||
TYPE_MODE (variant) = mode;
|
||||
}
|
||||
}
|
||||
/* Compute the final TYPE_SIZE, TYPE_ALIGN, etc. for TYPE. For
|
||||
RECORD_TYPEs, finish_record_layout already called this function. */
|
||||
if (TREE_CODE (type) != RECORD_TYPE)
|
||||
finalize_type_size (type);
|
||||
|
||||
pop_obstacks ();
|
||||
resume_momentary (old);
|
||||
|
40
gcc/tree.h
40
gcc/tree.h
@ -1776,12 +1776,46 @@ extern tree build_qualified_type PARAMS ((tree, int));
|
||||
extern tree build_type_copy PARAMS ((tree));
|
||||
|
||||
/* Given a ..._TYPE node, calculate the TYPE_SIZE, TYPE_SIZE_UNIT,
|
||||
TYPE_ALIGN and TYPE_MODE fields.
|
||||
If called more than once on one node, does nothing except
|
||||
for the first time. */
|
||||
TYPE_ALIGN and TYPE_MODE fields. If called more than once on one
|
||||
node, does nothing except for the first time. */
|
||||
|
||||
extern void layout_type PARAMS ((tree));
|
||||
|
||||
/* These functions allow a front-end to perform a manual layout of a
|
||||
RECORD_TYPE. (For instance, if the placement of subsequent fields
|
||||
depends on the placement of fields so far.) Begin by calling
|
||||
new_record_layout_info. Then, call layout_field for each of the
|
||||
fields. Then, call finish_record_layout. See layout_type for the
|
||||
default way in which these functions are used. */
|
||||
|
||||
struct record_layout_info_s
|
||||
{
|
||||
/* The RECORD_TYPE that we are laying out. */
|
||||
tree t;
|
||||
/* The size of the record so far, in bits. */
|
||||
unsigned HOST_WIDE_INT const_size;
|
||||
/* The alignment of the record so far, in bits. */
|
||||
unsigned int record_align;
|
||||
/* If the record can have a variable size, then this will be
|
||||
non-NULL, and the total size will be CONST_SIZE + VAR_SIZE. */
|
||||
tree var_size;
|
||||
/* If the record can have a variable size, then this will be the
|
||||
maximum alignment that we know VAR_SIZE has. */
|
||||
unsigned int var_align;
|
||||
/* The static variables (i.e., class variables, as opposed to
|
||||
instance variables) encountered in T. */
|
||||
tree pending_statics;
|
||||
unsigned int unpacked_align;
|
||||
int packed_maybe_necessary;
|
||||
};
|
||||
|
||||
typedef struct record_layout_info_s *record_layout_info;
|
||||
|
||||
extern record_layout_info new_record_layout_info
|
||||
PARAMS ((tree));
|
||||
extern void layout_field PARAMS ((record_layout_info, tree));
|
||||
extern void finish_record_layout PARAMS ((record_layout_info));
|
||||
|
||||
/* Given a hashcode and a ..._TYPE node (for which the hashcode was made),
|
||||
return a canonicalized ..._TYPE node, so that duplicates are not made.
|
||||
How the hash code is computed is up to the caller, as long as any two
|
||||
|
Loading…
Reference in New Issue
Block a user