/* C-compiler utilities for types and variables storage layout
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1996, 1998,
- 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
This file is part of GCC.
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "tree.h"
#include "rtl.h"
#include "tm_p.h"
static void finalize_record_size PARAMS ((record_layout_info));
static void finalize_type_size PARAMS ((tree));
static void place_union_field PARAMS ((record_layout_info, tree));
+#if defined (PCC_BITFIELD_TYPE_MATTERS) || defined (BITFIELD_NBYTES_LIMITED)
+static int excess_unit_span PARAMS ((HOST_WIDE_INT, HOST_WIDE_INT,
+ HOST_WIDE_INT, HOST_WIDE_INT,
+ tree));
+#endif
+static unsigned int update_alignment_for_field
+ PARAMS ((record_layout_info, tree,
+ unsigned int));
extern void debug_rli PARAMS ((record_layout_info));
\f
/* SAVE_EXPRs for sizes of types and decls, waiting to be expanded. */
return mode;
}
+/* Return the alignment of MODE. This will be bounded by 1 and
+ BIGGEST_ALIGNMENT. */
+
+unsigned int
+get_mode_alignment (mode)
+ enum machine_mode mode;
+{
+ unsigned int alignment;
+
+ if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
+ || GET_MODE_CLASS (mode) == MODE_COMPLEX_INT)
+ alignment = GET_MODE_UNIT_SIZE (mode);
+ else
+ alignment = GET_MODE_SIZE (mode);
+
+ /* Extract the LSB of the size. */
+ alignment = alignment & -alignment;
+ alignment *= BITS_PER_UNIT;
+
+ alignment = MIN (BIGGEST_ALIGNMENT, MAX (1, alignment));
+ return alignment;
+}
+
/* Return the value of VALUE, rounded up to a multiple of DIVISOR.
This can only be applied to objects of a sizetype. */
#ifdef STRUCTURE_SIZE_BOUNDARY
/* Packed structures don't need to have minimum size. */
if (! TYPE_PACKED (t))
- rli->record_align = MAX (rli->record_align, STRUCTURE_SIZE_BOUNDARY);
+ rli->record_align = MAX (rli->record_align, (unsigned) STRUCTURE_SIZE_BOUNDARY);
#endif
rli->offset = size_zero_node;
}
void
-pos_from_byte (poffset, pbitpos, off_align, pos)
- tree *poffset, *pbitpos;
- unsigned int off_align;
- tree pos;
-{
- *poffset
- = size_binop (MULT_EXPR,
- convert (sizetype,
- size_binop (FLOOR_DIV_EXPR, pos,
- bitsize_int (off_align
- / BITS_PER_UNIT))),
- size_int (off_align / BITS_PER_UNIT));
- *pbitpos = size_binop (MULT_EXPR,
- size_binop (FLOOR_MOD_EXPR, pos,
- bitsize_int (off_align / BITS_PER_UNIT)),
- bitsize_unit_node);
-}
-
-void
pos_from_bit (poffset, pbitpos, off_align, pos)
tree *poffset, *pbitpos;
unsigned int off_align;
return bit_from_pos (rli->offset, rli->bitpos);
}
-/* Called from place_field to handle unions. */
+/* FIELD is about to be added to RLI->T. The alignment (in bits) of
+ the next available location is given by KNOWN_ALIGN. Update the
+ variable alignment fields in RLI, and return the alignment to give
+ the FIELD. */
-static void
-place_union_field (rli, field)
- record_layout_info rli;
- tree field;
-{
- unsigned int desired_align;
-
- layout_decl (field, 0);
-
- DECL_FIELD_OFFSET (field) = size_zero_node;
- DECL_FIELD_BIT_OFFSET (field) = bitsize_zero_node;
- SET_DECL_OFFSET_ALIGN (field, BIGGEST_ALIGNMENT);
-
- desired_align = DECL_ALIGN (field);
-
-#ifdef BIGGEST_FIELD_ALIGNMENT
- /* Some targets (i.e. i386) limit union field alignment
- to a lower boundary than alignment of variables unless
- it was overridden by attribute aligned. */
- if (! DECL_USER_ALIGN (field))
- desired_align =
- MIN (desired_align, (unsigned) BIGGEST_FIELD_ALIGNMENT);
-#endif
-
-#ifdef ADJUST_FIELD_ALIGN
- if (! DECL_USER_ALIGN (field))
- desired_align = ADJUST_FIELD_ALIGN (field, desired_align);
-#endif
-
- TYPE_USER_ALIGN (rli->t) |= DECL_USER_ALIGN (field);
-
- /* Union must be at least as aligned as any field requires. */
- rli->record_align = MAX (rli->record_align, desired_align);
- rli->unpadded_align = MAX (rli->unpadded_align, desired_align);
-
-#ifdef PCC_BITFIELD_TYPE_MATTERS
- /* On the m88000, a bit field of declare type `int' forces the
- entire union to have `int' alignment. */
- if (PCC_BITFIELD_TYPE_MATTERS && DECL_BIT_FIELD_TYPE (field))
- {
- unsigned int type_align = TYPE_ALIGN (TREE_TYPE (field));
-
-#ifdef ADJUST_FIELD_ALIGN
- if (! TYPE_USER_ALIGN (TREE_TYPE (field)))
- type_align = ADJUST_FIELD_ALIGN (field, type_align);
-#endif
- rli->record_align = MAX (rli->record_align, type_align);
- rli->unpadded_align = MAX (rli->unpadded_align, type_align);
- TYPE_USER_ALIGN (rli->t) |= TYPE_USER_ALIGN (TREE_TYPE (field));
- }
-#endif
-
- /* We assume the union's size will be a multiple of a byte so we don't
- bother with BITPOS. */
- if (TREE_CODE (rli->t) == UNION_TYPE)
- rli->offset = size_binop (MAX_EXPR, rli->offset, DECL_SIZE_UNIT (field));
- else if (TREE_CODE (rli->t) == QUAL_UNION_TYPE)
- rli->offset = fold (build (COND_EXPR, sizetype,
- DECL_QUALIFIER (field),
- DECL_SIZE_UNIT (field), rli->offset));
-}
-
-/* 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
-place_field (rli, field)
+static unsigned int
+update_alignment_for_field (rli, field, known_align)
record_layout_info rli;
tree field;
+ unsigned int known_align;
{
/* 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;
- unsigned int actual_align;
- unsigned int user_align;
/* The type of this field. */
tree type = TREE_TYPE (field);
-
- if (TREE_CODE (field) == ERROR_MARK || TREE_CODE (type) == ERROR_MARK)
- return;
-
- /* 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. */
- else if (TREE_CODE (field) != FIELD_DECL)
- return;
-
- /* Unions are laid out very differently than records, so split
- that code off to another function. */
- else if (TREE_CODE (rli->t) != RECORD_TYPE)
- {
- place_union_field (rli, field);
- return;
- }
-
- /* Work out the known alignment so far. Note that A & (-A) is the
- value of the least-significant bit in A that is one. */
- if (! integer_zerop (rli->bitpos))
- known_align = (tree_low_cst (rli->bitpos, 1)
- & - tree_low_cst (rli->bitpos, 1));
- else if (integer_zerop (rli->offset))
- known_align = BIGGEST_ALIGNMENT;
- else if (host_integerp (rli->offset, 1))
- known_align = (BITS_PER_UNIT
- * (tree_low_cst (rli->offset, 1)
- & - tree_low_cst (rli->offset, 1)));
- else
- known_align = rli->offset_align;
+ /* True if the field was explicitly aligned by the user. */
+ bool user_align;
/* Lay out the field so we know what alignment it needs. For a
packed field, use the alignment as specified, disregarding what
to a lower boundary than alignment of variables unless
it was overridden by attribute aligned. */
#ifdef BIGGEST_FIELD_ALIGNMENT
- if (! user_align)
+ if (!user_align)
desired_align
= MIN (desired_align, (unsigned) BIGGEST_FIELD_ALIGNMENT);
#endif
#ifdef ADJUST_FIELD_ALIGN
- if (! user_align)
+ if (!user_align)
desired_align = ADJUST_FIELD_ALIGN (field, desired_align);
#endif
&& DECL_BIT_FIELD_TYPE (field)
&& ! integer_zerop (TYPE_SIZE (type)))
{
- /* For these machines, a zero-length field does not
- affect the alignment of the structure as a whole.
- It does, however, affect the alignment of the next field
- within the structure. */
- if (! integer_zerop (DECL_SIZE (field)))
- 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'
- forces the entire structure to have `int' alignment. */
+ /* A zero-length bit-field affects the alignment of the next
+ field. */
+ if (!DECL_PACKED (field) && integer_zerop (DECL_SIZE (field)))
+ {
+ desired_align = TYPE_ALIGN (type);
+#ifdef ADJUST_FIELD_ALIGN
+ desired_align = ADJUST_FIELD_ALIGN (field, desired_align);
+#endif
+ }
+
+ /* Named bit-fields cause the entire structure to have the
+ alignment implied by their type. */
if (DECL_NAME (field) != 0)
{
unsigned int type_align = TYPE_ALIGN (type);
else if (DECL_PACKED (field))
type_align = MIN (type_align, BITS_PER_UNIT);
+ /* The alignment of the record is increased to the maximum
+ of the current alignment, the alignment indicated on the
+ field (i.e., the alignment specified by an __aligned__
+ attribute), and the alignment indicated by the type of
+ the field. */
+ rli->record_align = MAX (rli->record_align, desired_align);
rli->record_align = MAX (rli->record_align, type_align);
+
rli->unpadded_align = MAX (rli->unpadded_align, DECL_ALIGN (field));
if (warn_packed)
rli->unpacked_align = MAX (rli->unpacked_align, TYPE_ALIGN (type));
rli->unpadded_align = MAX (rli->unpadded_align, DECL_ALIGN (field));
}
+ TYPE_USER_ALIGN (rli->t) |= user_align;
+
+ return desired_align;
+}
+
+/* Called from place_field to handle unions. */
+
+static void
+place_union_field (rli, field)
+ record_layout_info rli;
+ tree field;
+{
+ update_alignment_for_field (rli, field, /*known_align=*/0);
+
+ DECL_FIELD_OFFSET (field) = size_zero_node;
+ DECL_FIELD_BIT_OFFSET (field) = bitsize_zero_node;
+ SET_DECL_OFFSET_ALIGN (field, BIGGEST_ALIGNMENT);
+
+ /* We assume the union's size will be a multiple of a byte so we don't
+ bother with BITPOS. */
+ if (TREE_CODE (rli->t) == UNION_TYPE)
+ rli->offset = size_binop (MAX_EXPR, rli->offset, DECL_SIZE_UNIT (field));
+ else if (TREE_CODE (rli->t) == QUAL_UNION_TYPE)
+ rli->offset = fold (build (COND_EXPR, sizetype,
+ DECL_QUALIFIER (field),
+ DECL_SIZE_UNIT (field), rli->offset));
+}
+
+#if defined (PCC_BITFIELD_TYPE_MATTERS) || defined (BITFIELD_NBYTES_LIMITED)
+/* A bitfield of SIZE with a required access alignment of ALIGN is allocated
+ at BYTE_OFFSET / BIT_OFFSET. Return nonzero if the field would span more
+ units of alignment than the underlying TYPE. */
+static int
+excess_unit_span (byte_offset, bit_offset, size, align, type)
+ HOST_WIDE_INT byte_offset, bit_offset, size, align;
+ tree type;
+{
+ /* Note that the calculation of OFFSET might overflow; we calculate it so
+ that we still get the right result as long as ALIGN is a power of two. */
+ unsigned HOST_WIDE_INT offset = byte_offset * BITS_PER_UNIT + bit_offset;
+
+ offset = offset % align;
+ return ((offset + size + align - 1) / align
+ > ((unsigned HOST_WIDE_INT) tree_low_cst (TYPE_SIZE (type), 1)
+ / align));
+}
+#endif
+
+/* 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
+place_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;
+ unsigned int actual_align;
+ /* The type of this field. */
+ tree type = TREE_TYPE (field);
+
+ if (TREE_CODE (field) == ERROR_MARK || TREE_CODE (type) == ERROR_MARK)
+ return;
+
+ /* 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. */
+ else if (TREE_CODE (field) != FIELD_DECL)
+ return;
+
+ /* Unions are laid out very differently than records, so split
+ that code off to another function. */
+ else if (TREE_CODE (rli->t) != RECORD_TYPE)
+ {
+ place_union_field (rli, field);
+ return;
+ }
+
+ /* Work out the known alignment so far. Note that A & (-A) is the
+ value of the least-significant bit in A that is one. */
+ if (! integer_zerop (rli->bitpos))
+ known_align = (tree_low_cst (rli->bitpos, 1)
+ & - tree_low_cst (rli->bitpos, 1));
+ else if (integer_zerop (rli->offset))
+ known_align = BIGGEST_ALIGNMENT;
+ else if (host_integerp (rli->offset, 1))
+ known_align = (BITS_PER_UNIT
+ * (tree_low_cst (rli->offset, 1)
+ & - tree_low_cst (rli->offset, 1)));
+ else
+ known_align = rli->offset_align;
+
+ desired_align = update_alignment_for_field (rli, field, known_align);
+
if (warn_packed && DECL_PACKED (field))
{
if (known_align > TYPE_ALIGN (type))
/* A bit field may not span more units of alignment of its type
than its type itself. Advance to next boundary if necessary. */
- if ((((offset * BITS_PER_UNIT + bit_offset + field_size +
- type_align - 1)
- / type_align)
- - (offset * BITS_PER_UNIT + bit_offset) / type_align)
- > tree_low_cst (TYPE_SIZE (type), 1) / type_align)
+ if (excess_unit_span (offset, bit_offset, field_size, type_align, type))
rli->bitpos = round_up (rli->bitpos, type_align);
- user_align |= TYPE_USER_ALIGN (type);
+ TYPE_USER_ALIGN (rli->t) |= TYPE_USER_ALIGN (type);
}
#endif
/* A bit field may not span the unit of alignment of its type.
Advance to next boundary if necessary. */
- /* ??? This code should match the code above for the
- PCC_BITFIELD_TYPE_MATTERS case. */
- if ((offset * BITS_PER_UNIT + bit_offset) / type_align
- != ((offset * BITS_PER_UNIT + bit_offset + field_size - 1)
- / type_align))
+ if (excess_unit_span (offset, bit_offset, field_size, type_align, type))
rli->bitpos = round_up (rli->bitpos, type_align);
- user_align |= TYPE_USER_ALIGN (type);
+ TYPE_USER_ALIGN (rli->t) |= TYPE_USER_ALIGN (type);
}
#endif
A subtlety:
When a bit field is inserted into a packed record, the whole
size of the underlying type is used by one or more same-size
- adjacent bitfields. (That is, if its long:3, 32 bits is
+ adjacent bitfields. (That is, if its long:3, 32 bits is
used in the record, and any additional adjacent long bitfields are
packed into the same chunk of 32 bits. However, if the size
changes, a new field of that size is allocated.) In an unpacked
- record, this is the same as using alignment, but not eqivalent
- when packing.
+ record, this is the same as using alignment, but not equivalent
+ when packing.
- Note: for compatability, we use the type size, not the type alignment
+ 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)
if (rli->remaining_in_alignment < bitsize)
{
/* out of bits; bump up to next 'word'. */
+ rli->offset = DECL_FIELD_OFFSET (rli->prev_field);
rli->bitpos = size_binop (PLUS_EXPR,
type_size,
DECL_FIELD_BIT_OFFSET(rli->prev_field));
}
else
{
- /* End of a run: if leaving a run of bitfields of the same type
- size, we have to "use up" the rest of the bits of the type
+ /* End of a run: if leaving a run of bitfields of the same type
+ size, we have to "use up" the rest of the bits of the type
size.
Compute the new position as the sum of the size for the prior
prev_saved = NULL;
}
- /* Cause a new bitfield to be captured, either this time (if
+ /* Cause a new bitfield to be captured, either this time (if
currently a bitfield) or next time we see one. */
if (!DECL_BIT_FIELD_TYPE(field)
|| integer_zerop (DECL_SIZE (field)))
/* If we're starting a new run of same size type bitfields
(or a run of non-bitfields), set up the "first of the run"
- fields.
+ fields.
That is, if the current field is not a bitfield, or if there
was a prior bitfield the type sizes differ, or if there wasn't
there wasn't. */
if (!DECL_BIT_FIELD_TYPE (field)
- || ( prev_saved != NULL
+ || ( prev_saved != NULL
? !simple_cst_equal (TYPE_SIZE (type),
TYPE_SIZE (TREE_TYPE (prev_saved)))
: !integer_zerop (DECL_SIZE (field)) ))
{
- unsigned int type_align = 8; /* Never below 8 for compatability */
+ unsigned int type_align = 8; /* Never below 8 for compatibility */
- /* (When not a bitfield), we could be seeing a flex array (with
+ /* (When not a bitfield), we could be seeing a flex array (with
no DECL_SIZE). Since we won't be using remaining_in_alignment
- until we see a bitfield (and come by here again) we just skip
+ until we see a bitfield (and come by here again) we just skip
calculating it. */
-
+
if (DECL_SIZE (field) != NULL)
- rli->remaining_in_alignment
+ rli->remaining_in_alignment
= TREE_INT_CST_LOW (TYPE_SIZE(TREE_TYPE(field)))
- TREE_INT_CST_LOW (DECL_SIZE (field));
DECL_FIELD_BIT_OFFSET (field) = rli->bitpos;
SET_DECL_OFFSET_ALIGN (field, rli->offset_align);
- TYPE_USER_ALIGN (rli->t) |= user_align;
-
/* 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. */
/* 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. */
+ indicated by RLI. */
static void
finalize_record_size (rli)
unpadded_size_unit
= size_binop (PLUS_EXPR, unpadded_size_unit, size_one_node);
- /* 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 (rli->t) && TREE_VEC_LENGTH (TYPE_BINFO (rli->t)) > 6)
- {
- TYPE_BINFO_SIZE (rli->t) = unpadded_size;
- TYPE_BINFO_SIZE_UNIT (rli->t) = unpadded_size_unit;
- }
-
- /* Round the size up to be a multiple of the required alignment */
+ /* Round the size up to be a multiple of the required alignment */
#ifdef ROUND_TYPE_SIZE
TYPE_SIZE (rli->t) = ROUND_TYPE_SIZE (rli->t, unpadded_size,
TYPE_ALIGN (rli->t));
free (rli);
}
\f
+
+/* Finish processing a builtin RECORD_TYPE type TYPE. It's name is
+ NAME, its fields are chained in reverse on FIELDS.
+
+ If ALIGN_TYPE is non-null, it is given the same alignment as
+ ALIGN_TYPE. */
+
+void
+finish_builtin_struct (type, name, fields, align_type)
+ tree type;
+ const char *name;
+ tree fields;
+ tree align_type;
+{
+ tree tail, next;
+
+ for (tail = NULL_TREE; fields; tail = fields, fields = next)
+ {
+ DECL_FIELD_CONTEXT (fields) = type;
+ next = TREE_CHAIN (fields);
+ TREE_CHAIN (fields) = tail;
+ }
+ TYPE_FIELDS (type) = tail;
+
+ if (align_type)
+ {
+ TYPE_ALIGN (type) = TYPE_ALIGN (align_type);
+ TYPE_USER_ALIGN (type) = TYPE_USER_ALIGN (align_type);
+ }
+
+ layout_type (type);
+#if 0 /* not yet, should get fixed properly later */
+ TYPE_NAME (type) = make_type_decl (get_identifier (name), type);
+#else
+ TYPE_NAME (type) = build_decl (TYPE_DECL, get_identifier (name), type);
+#endif
+ TYPE_STUB_DECL (type) = TYPE_NAME (type);
+ layout_decl (TYPE_NAME (type), 0);
+}
+
/* Calculate the mode, size, and alignment for TYPE.
For an array type, calculate the element separation as well.
Record TYPE on the chain of permanent or temporary types
case POINTER_TYPE:
case REFERENCE_TYPE:
{
- int nbits = ((TREE_CODE (type) == REFERENCE_TYPE
- && reference_types_internal)
- ? GET_MODE_BITSIZE (Pmode) : POINTER_SIZE);
- TYPE_MODE (type) = nbits == POINTER_SIZE ? ptr_mode : Pmode;
+ enum machine_mode mode = ((TREE_CODE (type) == REFERENCE_TYPE
+ && reference_types_internal)
+ ? Pmode : TYPE_MODE (type));
+
+ int nbits = GET_MODE_BITSIZE (mode);
+
TYPE_SIZE (type) = bitsize_int (nbits);
- TYPE_SIZE_UNIT (type) = size_int (nbits / BITS_PER_UNIT);
+ TYPE_SIZE_UNIT (type) = size_int (GET_MODE_SIZE (mode));
TREE_UNSIGNED (type) = 1;
TYPE_PRECISION (type) = nbits;
}