OSDN Git Service

* tree.h (record_layout_info_s): New structure.
authormmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 13 Mar 2000 09:12:50 +0000 (09:12 +0000)
committermmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 13 Mar 2000 09:12:50 +0000 (09:12 +0000)
(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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@32503 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/stor-layout.c
gcc/tree.h

index 658d776..d5c91d3 100644 (file)
@@ -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.
index d4bd2e8..d2c4b7b 100644 (file)
@@ -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));
 \f
 /* SAVE_EXPRs for sizes of types and decls, waiting to be expanded.  */
 
@@ -400,343 +402,353 @@ layout_decl (decl, known_align)
     }
 }
 \f
-/* 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.
-
-   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.  */
+/* 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.  */
 
-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.  */
+  return rli;
+}
 
-      if (TREE_CODE (field) == VAR_DECL)
-       {
-         pending_statics = tree_cons (NULL_TREE, field, pending_statics);
-         continue;
-       }
+/* 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.)  */
 
-      /* 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;
+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.  */
+  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.  */
-      if (DECL_PACKED (field))
-       desired_align = DECL_ALIGN (field);
-      layout_decl (field, known_align);
-      if (! DECL_PACKED (field))
-       desired_align = DECL_ALIGN (field);
-      /* Some targets (i.e. VMS) limit struct field alignment
-        to a lower boundary than alignment of variables.  */
+  /* 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);
+  if (! DECL_PACKED (field))
+    desired_align = DECL_ALIGN (field);
+  /* Some targets (i.e. VMS) limit struct field alignment
+     to a lower boundary than alignment of variables.  */
 #ifdef BIGGEST_FIELD_ALIGNMENT
-      desired_align = MIN (desired_align, BIGGEST_FIELD_ALIGNMENT);
+  desired_align = MIN (desired_align, BIGGEST_FIELD_ALIGNMENT);
 #endif
 #ifdef ADJUST_FIELD_ALIGN
-      desired_align = ADJUST_FIELD_ALIGN (field, desired_align);
+  desired_align = ADJUST_FIELD_ALIGN (field, desired_align);
 #endif
 
-      /* Record must have at least as much alignment as any field.
-        Otherwise, the alignment of the field within the record
-        is meaningless.  */
-
+  /* Record must have at least as much alignment as any field.
+     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)
-         && ! integer_zerop (TYPE_SIZE (type)))
+  if (PCC_BITFIELD_TYPE_MATTERS && type != error_mark_node
+      && 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.  */
+      if (DECL_NAME (field) != 0)
        {
-         /* 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)))
-           record_align = MAX (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.  */
-         if (DECL_NAME (field) != 0)
-           {
-             unsigned int type_align = TYPE_ALIGN (type);
+         unsigned int type_align = TYPE_ALIGN (type);
 
-             if (maximum_field_alignment != 0)
-               type_align = MIN (type_align, maximum_field_alignment);
-             else if (DECL_PACKED (field))
-               type_align = MIN (type_align, BITS_PER_UNIT);
+         if (maximum_field_alignment != 0)
+           type_align = MIN (type_align, maximum_field_alignment);
+         else if (DECL_PACKED (field))
+           type_align = MIN (type_align, BITS_PER_UNIT);
 
-             record_align = MAX (record_align, type_align);
-             if (warn_packed)
-               unpacked_align = MAX (unpacked_align, TYPE_ALIGN (type));
-           }
-       }
-      else
-#endif
-       {
-         record_align = MAX (record_align, desired_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
+    {
+      rli->record_align = MAX (rli->record_align, desired_align);
+      if (warn_packed)
+       rli->unpacked_align = MAX (rli->unpacked_align, TYPE_ALIGN (type));
+    }
 
-      if (warn_packed && DECL_PACKED (field))
+  if (warn_packed && DECL_PACKED (field))
+    {
+      if (rli->const_size % TYPE_ALIGN (type) == 0
+         || (rli->var_align % TYPE_ALIGN (type) == 0 
+             && rli->var_size != NULL_TREE))
        {
-         if (const_size % TYPE_ALIGN (type) == 0
-             || (var_align % TYPE_ALIGN (type) == 0 && var_size != NULL_TREE))
+         if (TYPE_ALIGN (type) > desired_align)
            {
-             if (TYPE_ALIGN (type) > desired_align)
-               {
-                 if (STRICT_ALIGNMENT)
-                   warning_with_decl (field, "packed attribute causes inefficient alignment for `%s'");
-                 else
-                   warning_with_decl (field, "packed attribute is unnecessary for `%s'");
-               }
+             if (STRICT_ALIGNMENT)
+               warning_with_decl (field, "packed attribute causes inefficient alignment for `%s'");
+             else
+               warning_with_decl (field, "packed attribute is unnecessary for `%s'");
            }
-         else
-           packed_maybe_necessary = 1;
        }
+      else
+       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))
-       {
-         /* No, we need to skip space before this field.
-            Bump the cumulative size to multiple of field alignment.  */
+  /* 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.  */
 
-         if (warn_padded)
-           warning_with_decl (field, "padding struct to align `%s'");
+      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;
-         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->var_size == NULL_TREE || rli->var_align % desired_align == 0)
+       rli->const_size
+         = CEIL (rli->const_size, desired_align) * desired_align;
+      else
+       {
+         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);
        }
+    }
 
 #ifdef PCC_BITFIELD_TYPE_MATTERS
-      if (PCC_BITFIELD_TYPE_MATTERS
-         && TREE_CODE (field) == FIELD_DECL
-         && type != error_mark_node
-         && DECL_BIT_FIELD_TYPE (field)
-         && !DECL_PACKED (field)
-         && maximum_field_alignment == 0
-         && !integer_zerop (DECL_SIZE (field)))
-       {
-         unsigned int type_align = TYPE_ALIGN (type);
-         register tree dsize = DECL_SIZE (field);
-         unsigned int field_size = TREE_INT_CST_LOW (dsize);
-
-         /* 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)
-             > TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (field))) / type_align)
-           const_size = CEIL (const_size, type_align) * type_align;
-       }
+  if (PCC_BITFIELD_TYPE_MATTERS
+      && TREE_CODE (field) == FIELD_DECL
+      && type != error_mark_node
+      && DECL_BIT_FIELD_TYPE (field)
+      && !DECL_PACKED (field)
+      && maximum_field_alignment == 0
+      && !integer_zerop (DECL_SIZE (field)))
+    {
+      unsigned int type_align = TYPE_ALIGN (type);
+      register tree dsize = DECL_SIZE (field);
+      unsigned int field_size = TREE_INT_CST_LOW (dsize);
+
+      /* A bit field may not span more units of alignment of its type
+        than its type itself.  Advance to next boundary if necessary.  */
+      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)
+       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
-         && type != error_mark_node
-         && DECL_BIT_FIELD_TYPE (field)
-         && !DECL_PACKED (field)
-         && !integer_zerop (DECL_SIZE (field)))
-       {
-         unsigned int type_align = TYPE_ALIGN (type);
-         register tree dsize = DECL_SIZE (field);
-         int field_size = TREE_INT_CST_LOW (dsize);
-
-         if (maximum_field_alignment != 0)
-           type_align = MIN (type_align, maximum_field_alignment);
-         /* ??? This test is opposite the test in the containing if
-            statement, so this code is unreachable currently.  */
-         else if (DECL_PACKED (field))
-           type_align = MIN (type_align, BITS_PER_UNIT);
+  if (BITFIELD_NBYTES_LIMITED
+      && TREE_CODE (field) == FIELD_DECL
+      && type != error_mark_node
+      && DECL_BIT_FIELD_TYPE (field)
+      && !DECL_PACKED (field)
+      && !integer_zerop (DECL_SIZE (field)))
+    {
+      unsigned int type_align = TYPE_ALIGN (type);
+      register tree dsize = DECL_SIZE (field);
+      int field_size = TREE_INT_CST_LOW (dsize);
 
-         /* 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 (const_size / type_align
-             != (const_size + field_size - 1) / type_align)
-           const_size = CEIL (const_size, type_align) * type_align;
-       }
+      if (maximum_field_alignment != 0)
+       type_align = MIN (type_align, maximum_field_alignment);
+      /* ??? This test is opposite the test in the containing if
+        statement, so this code is unreachable currently.  */
+      else if (DECL_PACKED (field))
+       type_align = MIN (type_align, BITS_PER_UNIT);
+
+      /* 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 (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.  */
+  /* Size so far becomes the position of this field.  */
 
-      if (var_size && 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;
-      else
-       {
-         DECL_FIELD_BITPOS (field) = bitsize_int (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);
-       }
-
-      /* Now add size of this field to the size of the record.  */
+  if (rli->var_size && rli->const_size)
+    DECL_FIELD_BITPOS (field)
+      = 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 (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 != rli->const_size)
+       layout_decl (field, rli->const_size);
+    }
 
-      {
-        register tree 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
-          printed in finish_struct.  */
-       if (dsize == 0)
-         /* Do nothing.  */;
-       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)
-         /* Use const_size if there's no overflow.  */
-         const_size += TREE_INT_CST_LOW (dsize);
-       else
-         {
-           if (var_size == NULL_TREE)
-             var_size = dsize;
-           else
-             var_size = size_binop (PLUS_EXPR, var_size, dsize);
-         }
-      }
+  /* Now add size of this field to the size of the record.  */
+  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
+     printed in finish_struct.  */
+  if (dsize == 0)
+    /* Do nothing.  */;
+  else if (TREE_CODE (dsize) == INTEGER_CST
+          && ! TREE_CONSTANT_OVERFLOW (dsize)
+          && TREE_INT_CST_HIGH (dsize) == 0
+          && TREE_INT_CST_LOW (dsize) + rli->const_size >= rli->const_size)
+    /* Use const_size if there's no overflow.  */
+    rli->const_size += TREE_INT_CST_LOW (dsize);
+  else
+    {
+      if (rli->var_size == NULL_TREE)
+       rli->var_size = dsize;
+      else
+       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;
     }
+}
+
+/* Compute the TYPE_MODE for the TYPE (which is a RECORD_TYPE).  */
 
-  return pending_statics;
+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);
+}
+
 \f
 /* 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,88 +1287,18 @@ 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;
-
-         /* 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)))
-               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);
-       }
+      {
+       tree field;
+       record_layout_info rli;
+
+       /* Initialize the layout information.  */
+       rli = new_record_layout_info (type);
+       /* Layout all the fields.  */
+       for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+         layout_field (rli, field);
+       /* Finish laying out the record.  */
+       finish_record_layout (rli);
+      }
       break;
 
     case UNION_TYPE:
@@ -1253,73 +1375,11 @@ 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));
+  /* 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);
 
-  /* 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;
-       }
-    }
-       
   pop_obstacks ();
   resume_momentary (old);
 
index cfb8e8e..faa4a90 100644 (file)
@@ -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