OSDN Git Service

* config/h8300/h8300.md (a peephole2): Remove useless code.
[pf3gnuchains/gcc-fork.git] / gcc / stor-layout.c
index dae4c2d..6caaf5f 100644 (file)
@@ -1,6 +1,6 @@
 /* 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.
 
@@ -22,6 +22,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "tree.h"
 #include "rtl.h"
 #include "tm_p.h"
@@ -48,7 +50,7 @@ tree sizetype_tab[(int) TYPE_KIND_LAST];
    The value is measured in bits.  */
 unsigned int maximum_field_alignment;
 
-/* If non-zero, the alignment of a bitstring or (power-)set value, in bits.
+/* If nonzero, the alignment of a bitstring or (power-)set value, in bits.
    May be overridden by front-ends.  */
 unsigned int set_alignment = 0;
 
@@ -60,6 +62,14 @@ static int reference_types_internal = 0;
 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.  */
@@ -96,7 +106,7 @@ get_pending_sizes ()
   return chain;
 }
 
-/* Return non-zero if EXPR is present on the pending sizes list.  */
+/* Return nonzero if EXPR is present on the pending sizes list.  */
 
 int
 is_pending_size (expr)
@@ -147,6 +157,8 @@ tree
 variable_size (size)
      tree size;
 {
+  tree save;
+
   /* If the language-processor is to take responsibility for variable-sized
      items (e.g., languages which have elaboration procedures like Ada),
      just return SIZE unchanged.  Likewise for self-referential sizes and
@@ -156,7 +168,12 @@ variable_size (size)
       || contains_placeholder_p (size))
     return size;
 
-  size = save_expr (size);
+  if (TREE_CODE (size) == MINUS_EXPR && integer_onep (TREE_OPERAND (size, 1)))
+    /* If this is the upper bound of a C array, leave the minus 1 outside
+       the SAVE_EXPR so it can be folded away.  */
+    TREE_OPERAND (size, 0) = save = save_expr (TREE_OPERAND (size, 0));
+  else
+    size = save = save_expr (size);
 
   /* If an array with a variable number of elements is declared, and
      the elements require destruction, we will emit a cleanup for the
@@ -166,8 +183,8 @@ variable_size (size)
      `unsaved', i.e., all SAVE_EXPRs are recalculated.  However, we do
      not wish to do that here; the array-size is the same in both
      places.  */
-  if (TREE_CODE (size) == SAVE_EXPR)
-    SAVE_EXPR_PERSISTENT_P (size) = 1;
+  if (TREE_CODE (save) == SAVE_EXPR)
+    SAVE_EXPR_PERSISTENT_P (save) = 1;
 
   if ((*lang_hooks.decls.global_bindings_p) ())
     {
@@ -180,16 +197,13 @@ variable_size (size)
     }
 
   if (immediate_size_expand)
-    /* NULL_RTX is not defined; neither is the rtx type.
-       Also, we would like to pass const0_rtx here, but don't have it.  */
-    expand_expr (size, expand_expr (integer_zero_node, NULL_RTX, VOIDmode, 0),
-                VOIDmode, 0);
+    expand_expr (save, const0_rtx, VOIDmode, 0);
   else if (cfun != 0 && cfun->x_dont_save_pending_sizes_p)
     /* The front-end doesn't want us to keep a list of the expressions
        that determine sizes for variable size objects.  */
     ;
   else
-    put_pending_size (size);
+    put_pending_size (save);
 
   return size;
 }
@@ -295,6 +309,29 @@ int_mode_for_mode (mode)
   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.  */
 
@@ -501,7 +538,7 @@ start_record_layout (t)
 #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;
@@ -536,25 +573,6 @@ byte_from_pos (offset, bitpos)
 }
 
 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;
@@ -644,130 +662,23 @@ rli_size_so_far (rli)
   return bit_from_pos (rli->offset, rli->bitpos);
 }
 
-/* Called from place_field to handle unions.  */
-
-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.)  */
+/* 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.  */
 
-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
@@ -785,13 +696,13 @@ place_field (rli, field)
      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
 
@@ -807,7 +718,7 @@ place_field (rli, field)
         affect the alignment of a record; even a zero-sized field
         can do this.  The alignment should be to the alignment of
         the type, except that for zero-size bitfields this only
-        applies if there was an immediately prior, non-zero-size
+        applies if there was an immediately prior, nonzero-size
         bitfield.  (That's the way it is, experimentally.) */
       if (! integer_zerop (DECL_SIZE (field))
          ? ! DECL_PACKED (field)
@@ -833,17 +744,18 @@ place_field (rli, field)
       && 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);
@@ -858,7 +770,14 @@ place_field (rli, field)
          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));
@@ -873,6 +792,116 @@ place_field (rli, field)
       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))
@@ -949,14 +978,10 @@ place_field (rli, field)
 
       /* 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
 
@@ -992,14 +1017,10 @@ place_field (rli, field)
 
       /* 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
 
@@ -1007,14 +1028,14 @@ place_field (rli, field)
      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)
@@ -1022,12 +1043,12 @@ place_field (rli, field)
          || (rli->prev_field && ! DECL_PACKED (rli->prev_field))))
     {
       /* At this point, either the prior or current are bitfields,
-        (possibly both), and we're dealing with MS packing. */
+        (possibly both), and we're dealing with MS packing.  */
       tree prev_saved = rli->prev_field;
 
       /* Is the prior field a bitfield?  If so, handle "runs" of same
-        type size fields. */
-      if (rli->prev_field /* necessarily a bitfield if it exists. */) 
+        type size fields.  */
+      if (rli->prev_field /* necessarily a bitfield if it exists.  */)
        {
          /* If both are bitfields, nonzero, and the same size, this is
             the middle of a run.  Zero declared size fields are special
@@ -1049,7 +1070,8 @@ place_field (rli, field)
 
              if (rli->remaining_in_alignment < bitsize)
                {
-                 /* out of bits; bump up to next 'word'. */
+                 /* 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));
@@ -1060,8 +1082,8 @@ place_field (rli, 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
@@ -1079,12 +1101,12 @@ place_field (rli, field)
              else
                {
                  /* We "use up" size zero fields; the code below should behave
-                    as if the prior field was not a bitfield. */
+                    as if the prior field was not a bitfield.  */
                  prev_saved = NULL;
                }
 
-             /* Cause a new bitfield to be captured, either this time (if 
-                currently a bitfield) or next time we see one. */
+             /* 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)))
                {
@@ -1096,7 +1118,7 @@ place_field (rli, 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
@@ -1107,24 +1129,24 @@ place_field (rli, field)
         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));
 
-         /* Now align (conventionally) for the new type. */
+         /* Now align (conventionally) for the new type.  */
          if (!DECL_PACKED(field))
              type_align = MAX(TYPE_ALIGN (type), type_align);
 
@@ -1142,7 +1164,7 @@ place_field (rli, field)
 
          rli->bitpos = round_up (rli->bitpos, type_align);
           /* If we really aligned, don't allow subsequent bitfields
-            to undo that. */
+            to undo that.  */
          rli->prev_field = NULL;
        }
     }
@@ -1153,8 +1175,6 @@ place_field (rli, 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.  */
@@ -1173,7 +1193,7 @@ place_field (rli, field)
   if (known_align != actual_align)
     layout_decl (field, actual_align);
 
-  /* Only the MS bitfields use this. */
+  /* Only the MS bitfields use this.  */
   if (rli->prev_field == NULL && DECL_BIT_FIELD_TYPE(field))
       rli->prev_field = field;
 
@@ -1208,7 +1228,7 @@ place_field (rli, field)
 
 /* 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)
@@ -1238,15 +1258,7 @@ 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));
@@ -1484,11 +1496,14 @@ finalize_type_size (type)
 
 /* 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.  */
+   for RLI, unless FREE_P is false.  Passing a value other than false
+   for FREE_P is bad practice; this option only exists to support the
+   G++ 3.2 ABI.  */
 
 void
-finish_record_layout (rli)
+finish_record_layout (rli, free_p)
      record_layout_info rli;
+     int free_p;
 {
   /* Compute the final size.  */
   finalize_record_size (rli);
@@ -1508,9 +1523,50 @@ finish_record_layout (rli)
     }
 
   /* Clean up.  */
-  free (rli);
+  if (free_p)
+    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
@@ -1611,13 +1667,15 @@ layout_type (type)
     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;
       }
@@ -1763,7 +1821,7 @@ layout_type (type)
          (*lang_adjust_rli) (rli);
 
        /* Finish laying out the record.  */
-       finish_record_layout (rli);
+       finish_record_layout (rli, /*free_p=*/true);
       }
       break;