OSDN Git Service

x
[pf3gnuchains/gcc-fork.git] / gcc / stor-layout.c
index 0e6efe9..e55961a 100644 (file)
@@ -1,5 +1,5 @@
 /* C-compiler utilities for types and variables storage layout
-   Copyright (C) 1987, 1988, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 92-96, 1997 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,13 +15,16 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 #include "config.h"
 #include <stdio.h>
 
 #include "tree.h"
+#include "flags.h"
+#include "except.h"
 #include "function.h"
 
 #define CEIL(x,y) (((x) + (y) - 1) / (y))
@@ -40,9 +43,18 @@ tree size_zero_node;
 
 tree size_one_node;
 
-#define GET_MODE_ALIGNMENT(MODE)   \
-  MIN (BIGGEST_ALIGNMENT,         \
-       MAX (1, (GET_MODE_UNIT_SIZE (MODE) * BITS_PER_UNIT)))
+/* If nonzero, this is an upper limit on alignment of structure fields.
+   The value is measured in bits.  */
+int maximum_field_alignment;
+
+/* If non-zero, the alignment of a bitstring or (power-)set value, in bits.
+   May be overridden by front-ends.  */
+int set_alignment = 0;
+
+static enum machine_mode smallest_mode_for_size  PROTO((unsigned int,
+                                                       enum mode_class));
+static tree layout_record      PROTO((tree));
+static void layout_union       PROTO((tree));
 \f
 /* SAVE_EXPRs for sizes of types and decls, waiting to be expanded.  */
 
@@ -57,29 +69,58 @@ tree
 get_pending_sizes ()
 {
   tree chain = pending_sizes;
+  tree t;
+
+  /* Put each SAVE_EXPR into the current function.  */
+  for (t = chain; t; t = TREE_CHAIN (t))
+    SAVE_EXPR_CONTEXT (TREE_VALUE (t)) = current_function_decl;
   pending_sizes = 0;
   return chain;
 }
 
-/* Given a size SIZE that isn't constant, return a SAVE_EXPR
+void
+put_pending_sizes (chain)
+     tree chain;
+{
+  if (pending_sizes)
+    abort ();
+
+  pending_sizes = chain;
+}
+
+/* Given a size SIZE that may not be a constant, return a SAVE_EXPR
    to serve as the actual size-expression for a type or decl.  */
 
-static tree
+tree
 variable_size (size)
      tree size;
 {
+  /* 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.  */
+  if (TREE_CONSTANT (size)
+      || global_bindings_p () < 0 || contains_placeholder_p (size))
+    return size;
+
   size = save_expr (size);
 
   if (global_bindings_p ())
     {
-      error ("variable-size type declared outside of any function");
+      if (TREE_CONSTANT (size))
+       error ("type size can't be explicitly evaluated");
+      else
+       error ("variable-size type declared outside of any function");
+
       return size_int (1);
     }
 
   if (immediate_size_expand)
-    expand_expr (size, 0, VOIDmode, 0);
+    /* 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_PTR, VOIDmode, 0),
+                VOIDmode, 0);
   else
-    pending_sizes = tree_cons (0, size, pending_sizes);
+    pending_sizes = tree_cons (NULL_TREE, size, pending_sizes);
 
   return size;
 }
@@ -104,7 +145,7 @@ mode_for_size (size, class, limit)
   if (limit && size > MAX_FIXED_MODE_SIZE)
     return BLKmode;
 
-  /* Get the last mode which has this size, in the specified class.  */
+  /* Get the first mode which has this size, in the specified class.  */
   for (mode = GET_CLASS_NARROWEST_MODE (class); mode != VOIDmode;
        mode = GET_MODE_WIDER_MODE (mode))
     if (GET_MODE_BITSIZE (mode) == size)
@@ -113,6 +154,26 @@ mode_for_size (size, class, limit)
   return BLKmode;
 }
 
+/* Similar, but never return BLKmode; return the narrowest mode that
+   contains at least the requested number of bits.  */
+
+static enum machine_mode
+smallest_mode_for_size (size, class)
+     unsigned int size;
+     enum mode_class class;
+{
+  register enum machine_mode mode;
+
+  /* Get the first mode which has at least this size, in the
+     specified class.  */
+  for (mode = GET_CLASS_NARROWEST_MODE (class); mode != VOIDmode;
+       mode = GET_MODE_WIDER_MODE (mode))
+    if (GET_MODE_BITSIZE (mode) >= size)
+      return mode;
+
+  abort ();
+}
+
 /* Return the value of VALUE, rounded up to a multiple of DIVISOR.  */
 
 tree
@@ -145,7 +206,7 @@ layout_decl (decl, known_align)
 {
   register tree type = TREE_TYPE (decl);
   register enum tree_code code = TREE_CODE (decl);
-  int spec_size = DECL_FRAME_SIZE (decl);
+  int spec_size = DECL_FIELD_SIZE (decl);
 
   if (code == CONST_DECL)
     return;
@@ -163,19 +224,12 @@ layout_decl (decl, known_align)
   /* Usually the size and mode come from the data type without change.  */
 
   DECL_MODE (decl) = TYPE_MODE (type);
-  DECL_SIZE (decl) = TYPE_SIZE (type);
   TREE_UNSIGNED (decl) = TREE_UNSIGNED (type);
+  if (DECL_SIZE (decl) == 0)
+    DECL_SIZE (decl) = TYPE_SIZE (type);
 
   if (code == FIELD_DECL && DECL_BIT_FIELD (decl))
     {
-      /* This is a bit-field.  We don't know how to handle
-        them except for integers and enums, and front end should
-        never generate them otherwise.  */
-
-      if (! (TREE_CODE (type) == INTEGER_TYPE
-            || TREE_CODE (type) == ENUMERAL_TYPE))
-       abort ();
-
       if (spec_size == 0 && DECL_NAME (decl) != 0)
        abort ();
 
@@ -183,18 +237,28 @@ layout_decl (decl, known_align)
       DECL_SIZE (decl) = size_int (spec_size);
     }
   /* Force alignment required for the data type.
-     But if the decl itself wants greater alignment, don't override that.  */
-  else if (TYPE_ALIGN (type) > DECL_ALIGN (decl))
+     But if the decl itself wants greater alignment, don't override that.
+     Likewise, if the decl is packed, don't override it.  */
+  else if (DECL_ALIGN (decl) == 0
+          || (! DECL_PACKED (decl) &&  TYPE_ALIGN (type) > DECL_ALIGN (decl)))
     DECL_ALIGN (decl) = TYPE_ALIGN (type);
 
   /* See if we can use an ordinary integer mode for a bit-field.  */
   /* Conditions are: a fixed size that is correct for another mode
      and occupying a complete byte or bytes on proper boundary.  */
   if (code == FIELD_DECL)
-    DECL_BIT_FIELD_TYPE (decl) = DECL_BIT_FIELD (decl) ? type : 0;
+    {
+      DECL_BIT_FIELD_TYPE (decl) = DECL_BIT_FIELD (decl) ? type : 0;
+      if (maximum_field_alignment != 0)
+       DECL_ALIGN (decl) = MIN (DECL_ALIGN (decl), maximum_field_alignment);
+      else if (DECL_PACKED (decl))
+       DECL_ALIGN (decl) = MIN (DECL_ALIGN (decl), BITS_PER_UNIT);
+    }
+
   if (DECL_BIT_FIELD (decl)
       && TYPE_SIZE (type) != 0
-      && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
+      && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
+      && GET_MODE_CLASS (TYPE_MODE (type)) == MODE_INT)
     {
       register enum machine_mode xmode
        = mode_for_size (TREE_INT_CST_LOW (DECL_SIZE (decl)), MODE_INT, 1);
@@ -211,6 +275,15 @@ layout_decl (decl, known_align)
        }
     }
 
+  /* Turn off DECL_BIT_FIELD if we won't need it set.  */
+  if (DECL_BIT_FIELD (decl) && TYPE_MODE (type) == BLKmode
+      && known_align % TYPE_ALIGN (type) == 0
+      && DECL_SIZE (decl) != 0
+      && (TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST
+         || (TREE_INT_CST_LOW (DECL_SIZE (decl)) % BITS_PER_UNIT) == 0)
+      && DECL_ALIGN (decl) >= TYPE_ALIGN (type))
+    DECL_BIT_FIELD (decl) = 0;
+
   /* Evaluate nonconstant size only once, either now or as soon as safe.  */
   if (DECL_SIZE (decl) != 0 && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
     DECL_SIZE (decl) = variable_size (DECL_SIZE (decl));
@@ -245,7 +318,7 @@ layout_record (rec)
      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.  */
 register int const_size = 0;
register HOST_WIDE_INT const_size = 0;
   register tree var_size = 0;
   /* Once we start using VAR_SIZE, this is the maximum alignment
      that we know VAR_SIZE has.  */
@@ -254,6 +327,7 @@ layout_record (rec)
 
   for (field = TYPE_FIELDS (rec); field; field = TREE_CHAIN (field))
     {
+      register int known_align = var_size ? var_align : const_size;
       register int desired_align;
 
       /* If FIELD is static, then treat it like a separate variable,
@@ -262,9 +336,9 @@ layout_record (rec)
         In both cases, all we do is lay out the decl,
         and we do it *after* the record is laid out.  */
 
-      if (TREE_STATIC (field))
+      if (TREE_CODE (field) == VAR_DECL)
        {
-         pending_statics = tree_cons (NULL, field, pending_statics);
+         pending_statics = tree_cons (NULL_TREE, field, pending_statics);
          continue;
        }
       /* Enumerators and enum types which are local to this class need not
@@ -273,14 +347,11 @@ layout_record (rec)
        continue;
 
       /* Lay out the field so we know what alignment it needs.
-        For KNOWN_ALIGN, pass the number of bits from start of record
-        or some divisor of it.  */
-
-      /* For a packed field, use the alignment as specified,
+        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, var_size ? var_align : const_size);
+      layout_decl (field, known_align);
       if (! DECL_PACKED (field))
        desired_align = DECL_ALIGN (field);
       /* Some targets (i.e. VMS) limit struct field alignment
@@ -288,6 +359,9 @@ layout_record (rec)
 #ifdef BIGGEST_FIELD_ALIGNMENT
       desired_align = MIN (desired_align, BIGGEST_FIELD_ALIGNMENT);
 #endif
+#ifdef ADJUST_FIELD_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
@@ -297,6 +371,7 @@ layout_record (rec)
       record_align = MAX (record_align, desired_align);
 #else
       if (PCC_BITFIELD_TYPE_MATTERS && TREE_TYPE (field) != error_mark_node
+         && DECL_BIT_FIELD_TYPE (field)
          && ! integer_zerop (TYPE_SIZE (TREE_TYPE (field))))
        {
          /* For these machines, a zero-length field does not
@@ -310,7 +385,15 @@ layout_record (rec)
          /* A named bit field of declared type `int'
             forces the entire structure to have `int' alignment.  */
          if (DECL_NAME (field) != 0)
-           record_align = MAX (record_align, TYPE_ALIGN (TREE_TYPE (field)));
+           {
+             int type_align = TYPE_ALIGN (TREE_TYPE (field));
+             if (maximum_field_alignment != 0)
+               type_align = MIN (type_align, maximum_field_alignment);
+             else if (TYPE_PACKED (rec))
+               type_align = MIN (type_align, BITS_PER_UNIT);
+
+             record_align = MAX (record_align, type_align);
+           }
        }
       else
        record_align = MAX (record_align, desired_align);
@@ -334,7 +417,8 @@ layout_record (rec)
          else
            {
              if (const_size > 0)
-               var_size = size_binop (PLUS_EXPR, var_size, const_size);
+               var_size = size_binop (PLUS_EXPR, var_size,
+                                      size_int (const_size));
              const_size = 0;
              var_size = round_up (var_size, desired_align);
              var_align = MIN (var_align, desired_align);
@@ -345,17 +429,19 @@ layout_record (rec)
       if (PCC_BITFIELD_TYPE_MATTERS
          && TREE_CODE (field) == FIELD_DECL
          && TREE_TYPE (field) != error_mark_node
+         && DECL_BIT_FIELD_TYPE (field)
          && !DECL_PACKED (field)
+         && maximum_field_alignment == 0
          && !integer_zerop (DECL_SIZE (field)))
        {
          int type_align = TYPE_ALIGN (TREE_TYPE (field));
          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.  */
-         if (const_size / type_align
-             != (const_size + field_size - 1) / type_align)
+         /* 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 - const_size / type_align)
+             > TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (field))) / type_align)
            const_size = CEIL (const_size, type_align) * type_align;
        }
 #endif
@@ -366,6 +452,7 @@ layout_record (rec)
       if (BITFIELD_NBYTES_LIMITED
          && TREE_CODE (field) == FIELD_DECL
          && TREE_TYPE (field) != error_mark_node
+         && DECL_BIT_FIELD_TYPE (field)
          && !DECL_PACKED (field)
          && !integer_zerop (DECL_SIZE (field)))
        {
@@ -373,6 +460,11 @@ layout_record (rec)
          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);
+         else if (TYPE_PACKED (rec))
+           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.  */
          if (const_size / type_align
@@ -389,20 +481,15 @@ layout_record (rec)
       else if (var_size)
        DECL_FIELD_BITPOS (field) = var_size;
       else
-       DECL_FIELD_BITPOS (field) = size_int (const_size);
-
-      /* If this field is an anonymous union,
-        give each union-member the same position as the union has.  */
-
-      if (DECL_NAME (field) == 0
-         && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
        {
-         tree uelt = TYPE_FIELDS (TREE_TYPE (field));
-         for (; uelt; uelt = TREE_CHAIN (uelt))
-           {
-             DECL_FIELD_CONTEXT (uelt) = DECL_FIELD_CONTEXT (field);
-             DECL_FIELD_BITPOS (uelt) = DECL_FIELD_BITPOS (field);
-           }
+         DECL_FIELD_BITPOS (field) = size_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.  */
@@ -410,7 +497,16 @@ layout_record (rec)
       {
         register tree dsize = DECL_SIZE (field);
 
-       if (TREE_CODE (dsize) == INTEGER_CST)
+       /* 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
          {
@@ -455,7 +551,7 @@ layout_record (rec)
   return pending_statics;
 }
 \f
-/* Lay out a UNION_TYPE type.
+/* Lay out a UNION_TYPE or QUAL_UNION_TYPE type.
    Lay out all the fields, set their positions to zero,
    and compute the size and alignment of the union (maximum of any field).
    Note that if you set the TYPE_ALIGN before calling this
@@ -478,6 +574,12 @@ layout_union (rec)
   register int const_size = 0;
   register tree var_size = 0;
 
+  /* If this is a QUAL_UNION_TYPE, we want to process the fields in
+     the reverse order in building the COND_EXPR that denotes its
+     size.  We reverse them again later.  */
+  if (TREE_CODE (rec) == QUAL_UNION_TYPE)
+    TYPE_FIELDS (rec) = nreverse (TYPE_FIELDS (rec));
+
   for (field = TYPE_FIELDS (rec); field; field = TREE_CHAIN (field))
     {
       /* Enums which are local to this class need not be laid out.  */
@@ -494,21 +596,32 @@ layout_union (rec)
 #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
+      if (PCC_BITFIELD_TYPE_MATTERS && DECL_BIT_FIELD_TYPE (field))
        union_align = MAX (union_align, TYPE_ALIGN (TREE_TYPE (field)));
 #endif
 
-      /* Set union_size to max (decl_size, union_size).
-        There are more and less general ways to do this.
-        Use only CONST_SIZE unless forced to use VAR_SIZE.  */
+      if (TREE_CODE (rec) == UNION_TYPE)
+       {
+         /* Set union_size to max (decl_size, union_size).
+            There are more and less general ways to do this.
+            Use only CONST_SIZE unless forced to use VAR_SIZE.  */
 
-      if (TREE_CODE (DECL_SIZE (field)) == INTEGER_CST)
-       const_size = MAX (const_size, TREE_INT_CST_LOW (DECL_SIZE (field)));
-      else if (var_size == 0)
-       var_size = DECL_SIZE (field);
-      else
-       var_size = size_binop (MAX_EXPR, var_size, DECL_SIZE (field));
-    }
+         if (TREE_CODE (DECL_SIZE (field)) == INTEGER_CST)
+           const_size
+             = MAX (const_size, TREE_INT_CST_LOW (DECL_SIZE (field)));
+         else if (var_size == 0)
+           var_size = DECL_SIZE (field);
+         else
+           var_size = size_binop (MAX_EXPR, var_size, DECL_SIZE (field));
+       }
+      else if (TREE_CODE (rec) == QUAL_UNION_TYPE)
+       var_size = fold (build (COND_EXPR, sizetype, DECL_QUALIFIER (field),
+                               DECL_SIZE (field),
+                               var_size ? var_size : integer_zero_node));
+      }
+
+  if (TREE_CODE (rec) == QUAL_UNION_TYPE)
+    TYPE_FIELDS (rec) = nreverse (TYPE_FIELDS (rec));
 
   /* Determine the ultimate size of the union (in bytes).  */
   if (NULL == var_size)
@@ -564,36 +677,28 @@ layout_type (type)
      they must last past the current statement.  */
   old = suspend_momentary ();
 
-  /* If we are processing a permanent type, make nodes permanent.
-     If processing a temporary type, make it saveable, since the
-     type node itself is.  This is important if the function is inline,
-     since its decls will get copied later.  */
-  push_obstacks_nochange ();
-  if (allocation_temporary_p ())
-    {
-      if (TREE_PERMANENT (type))
-       end_temporary_allocation ();
-      else
-       saveable_allocation ();
-    }
+  /* Put all our nodes into the same obstack as the type.  Also,
+     make expressions saveable (this is a no-op for permanent types).  */
+
+  push_obstacks (TYPE_OBSTACK (type), TYPE_OBSTACK (type));
+  saveable_allocation ();
 
   switch (TREE_CODE (type))
     {
     case LANG_TYPE:
       /* This kind of type is the responsibility
-        of the languge-specific code.  */
+        of the language-specific code.  */
       abort ();
 
     case INTEGER_TYPE:
     case ENUMERAL_TYPE:
-      if (TREE_INT_CST_HIGH (TYPE_MIN_VALUE (type)) >= 0)
+    case CHAR_TYPE:
+      if (TREE_CODE (TYPE_MIN_VALUE (type)) == INTEGER_CST
+         && tree_int_cst_sgn (TYPE_MIN_VALUE (type)) >= 0)
        TREE_UNSIGNED (type) = 1;
 
-      /* We pass 0 for the last arg of mode_for_size because otherwise
-        on the Apollo using long long causes a crash.
-        It seems better to use integer modes than to try to support
-        integer types with BLKmode.  */
-      TYPE_MODE (type) = mode_for_size (TYPE_PRECISION (type), MODE_INT, 0);
+      TYPE_MODE (type) = smallest_mode_for_size (TYPE_PRECISION (type),
+                                                MODE_INT);
       TYPE_SIZE (type) = size_int (GET_MODE_BITSIZE (TYPE_MODE (type)));
       break;
 
@@ -618,19 +723,23 @@ layout_type (type)
       TYPE_MODE (type) = VOIDmode;
       break;
 
+    case OFFSET_TYPE:
+      TYPE_SIZE (type) = size_int (POINTER_SIZE);
+      TYPE_MODE (type) = ptr_mode;
+      break;
+
     case FUNCTION_TYPE:
     case METHOD_TYPE:
-      TYPE_MODE (type) = mode_for_size (2 * GET_MODE_BITSIZE (Pmode),
-                                       MODE_INT, 0);
-      TYPE_SIZE (type) = size_int (GET_MODE_BITSIZE (TYPE_MODE (type)));
+      TYPE_MODE (type) = mode_for_size (2 * POINTER_SIZE, MODE_INT, 0);
+      TYPE_SIZE (type) = size_int (2 * POINTER_SIZE);
       break;
 
     case POINTER_TYPE:
     case REFERENCE_TYPE:
-      TYPE_MODE (type) = Pmode;
-      TYPE_SIZE (type) = size_int (GET_MODE_BITSIZE (TYPE_MODE (type)));
+      TYPE_MODE (type) = ptr_mode;
+      TYPE_SIZE (type) = size_int (POINTER_SIZE);
       TREE_UNSIGNED (type) = 1;
-      TYPE_PRECISION (type) = GET_MODE_BITSIZE (TYPE_MODE (type));
+      TYPE_PRECISION (type) = POINTER_SIZE;
       break;
 
     case ARRAY_TYPE:
@@ -644,10 +753,37 @@ layout_type (type)
        if (index && TYPE_MAX_VALUE (index) && TYPE_MIN_VALUE (index)
            && TYPE_SIZE (element))
          {
-           tree length
-             = size_binop (PLUS_EXPR, size_one_node,
-                           size_binop (MINUS_EXPR, TYPE_MAX_VALUE (index),
-                                       TYPE_MIN_VALUE (index)));
+           tree ub = TYPE_MAX_VALUE (index);
+           tree lb = TYPE_MIN_VALUE (index);
+           tree length;
+
+           /* If UB is max (lb - 1, x), remove the MAX_EXPR since the
+              test for negative below covers it.  */
+           if (TREE_CODE (ub) == MAX_EXPR
+               && TREE_CODE (TREE_OPERAND (ub, 0)) == MINUS_EXPR
+               && integer_onep (TREE_OPERAND (TREE_OPERAND (ub, 0), 1))
+               && operand_equal_p (TREE_OPERAND (TREE_OPERAND (ub, 0), 0),
+                                   lb, 0))
+             ub = TREE_OPERAND (ub, 1);
+           else if (TREE_CODE (ub) == MAX_EXPR
+                    && TREE_CODE (TREE_OPERAND (ub, 1)) == MINUS_EXPR
+                    && integer_onep (TREE_OPERAND (TREE_OPERAND (ub, 1), 1))
+                    && operand_equal_p (TREE_OPERAND (TREE_OPERAND (ub, 1),
+                                                      0),
+                                        lb, 0))
+             ub = TREE_OPERAND (ub, 0);
+
+           length = size_binop (PLUS_EXPR, size_one_node,
+                                size_binop (MINUS_EXPR, ub, lb));
+
+           /* If neither bound is a constant and sizetype is signed, make
+              sure the size is never negative.  We should really do this
+              if *either* bound is non-constant, but this is the best
+              compromise between C and Ada.  */
+           if (! TREE_UNSIGNED (sizetype)
+               && TREE_CODE (TYPE_MIN_VALUE (index)) != INTEGER_CST
+               && TREE_CODE (TYPE_MAX_VALUE (index)) != INTEGER_CST)
+             length = size_binop (MAX_EXPR, length, size_zero_node);
 
            TYPE_SIZE (type) = size_binop (MULT_EXPR, length,
                                           TYPE_SIZE (element));
@@ -681,15 +817,13 @@ layout_type (type)
              = mode_for_size (TREE_INT_CST_LOW (TYPE_SIZE (type)),
                               MODE_INT, 1);
 
-#ifdef STRICT_ALIGNMENT
-           if (TYPE_ALIGN (type) < BIGGEST_ALIGNMENT
+           if (STRICT_ALIGNMENT && TYPE_ALIGN (type) < BIGGEST_ALIGNMENT
                && TYPE_ALIGN (type) < TREE_INT_CST_LOW (TYPE_SIZE (type))
                && TYPE_MODE (type) != BLKmode)
              {
                TYPE_NO_FORCE_BLK (type) = 1;
                TYPE_MODE (type) = BLKmode;
              }
-#endif
          }
        break;
       }
@@ -736,9 +870,10 @@ layout_type (type)
          /* If structure's known alignment is less than
             what the scalar mode would need, and it matters,
             then stick with BLKmode.  */
-#ifdef STRICT_ALIGNMENT
-         if (! (TYPE_ALIGN (type) >= BIGGEST_ALIGNMENT
-                || TYPE_ALIGN (type) >= TREE_INT_CST_LOW (TYPE_SIZE (type))))
+         if (STRICT_ALIGNMENT
+             && ! (TYPE_ALIGN (type) >= BIGGEST_ALIGNMENT
+                   || (TYPE_ALIGN (type)
+                       >= TREE_INT_CST_LOW (TYPE_SIZE (type)))))
            {
              if (TYPE_MODE (type) != BLKmode)
                /* If this is the only reason this type is BLKmode,
@@ -746,7 +881,7 @@ layout_type (type)
                TYPE_NO_FORCE_BLK (type) = 1;
              TYPE_MODE (type) = BLKmode;
            }
-#endif
+
        record_lose: ;
        }
 
@@ -760,17 +895,16 @@ layout_type (type)
       break;
 
     case UNION_TYPE:
+    case QUAL_UNION_TYPE:
       layout_union (type);
       TYPE_MODE (type) = BLKmode;
       if (TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
          /* If structure's known alignment is less than
             what the scalar mode would need, and it matters,
             then stick with BLKmode.  */
-#ifdef STRICT_ALIGNMENT
-         && (TYPE_ALIGN (type) >= BIGGEST_ALIGNMENT
-             || TYPE_ALIGN (type) >= TREE_INT_CST_LOW (TYPE_SIZE (type)))
-#endif
-         )
+         && (! STRICT_ALIGNMENT
+             || TYPE_ALIGN (type) >= BIGGEST_ALIGNMENT
+             || TYPE_ALIGN (type) >= TREE_INT_CST_LOW (TYPE_SIZE (type))))
        {
          tree field;
          /* A union which has any BLKmode members must itself be BLKmode;
@@ -794,6 +928,49 @@ layout_type (type)
        }
       break;
 
+    /* Pascal and Chill types */
+    case BOOLEAN_TYPE:          /* store one byte/boolean for now.  */
+      TYPE_MODE (type) = QImode;
+      TYPE_SIZE (type) = size_int (GET_MODE_BITSIZE (TYPE_MODE (type)));
+      TYPE_PRECISION (type) = 1;
+      TYPE_ALIGN (type) = GET_MODE_ALIGNMENT (TYPE_MODE (type));
+      if (TREE_CODE (TYPE_MIN_VALUE (type)) == INTEGER_CST
+         && tree_int_cst_sgn (TYPE_MIN_VALUE (type)) >= 0)
+       TREE_UNSIGNED (type) = 1;
+      break;
+
+    case SET_TYPE:
+      if (TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) != INTEGER_CST
+         || TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) != INTEGER_CST)
+       abort();
+      else
+       {
+#ifndef SET_WORD_SIZE
+#define SET_WORD_SIZE BITS_PER_WORD
+#endif
+         int alignment = set_alignment ? set_alignment : SET_WORD_SIZE;
+         int size_in_bits =
+           TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (type)))
+             - TREE_INT_CST_LOW (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) + 1;
+         int rounded_size
+           = ((size_in_bits + alignment - 1) / alignment) * alignment;
+         if (rounded_size > alignment)
+           TYPE_MODE (type) = BLKmode;
+         else
+           TYPE_MODE (type) = mode_for_size (alignment, MODE_INT, 1);
+         TYPE_SIZE (type) = size_int (rounded_size);
+         TYPE_ALIGN (type) = alignment;
+         TYPE_PRECISION (type) = size_in_bits;
+       }
+      break;
+
+    case FILE_TYPE:
+      /* The size may vary in different languages, so the language front end
+        should fill in the size.  */
+      TYPE_ALIGN (type) = BIGGEST_ALIGNMENT;
+      TYPE_MODE  (type) = BLKmode;
+      break;
+
     default:
       abort ();
     } /* end switch */
@@ -804,11 +981,10 @@ layout_type (type)
      alignment.  */
 
   if (TYPE_MODE (type) != BLKmode && TYPE_MODE (type) != VOIDmode
-#ifndef STRICT_ALIGNMENT
-      && (TREE_CODE (type) != RECORD_TYPE && TREE_CODE (type) != UNION_TYPE
-         && TREE_CODE (type) != ARRAY_TYPE)
-#endif
-      )
+      && (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));
 
   /* Evaluate nonconstant size only once, either now or as soon as safe.  */
@@ -853,14 +1029,18 @@ make_signed_type (precision)
   /* Create the extreme values based on the number of bits.  */
 
   TYPE_MIN_VALUE (type)
-    = build_int_2 ((precision-HOST_BITS_PER_INT > 0 ? 0 : (-1)<<(precision-1)),
-                  (-1)<<(precision-HOST_BITS_PER_INT-1 > 0
-                         ? precision-HOST_BITS_PER_INT-1
-                         : 0));
+    = build_int_2 ((precision - HOST_BITS_PER_WIDE_INT > 0
+                   ? 0 : (HOST_WIDE_INT) (-1) << (precision - 1)),
+                  (((HOST_WIDE_INT) (-1)
+                    << (precision - HOST_BITS_PER_WIDE_INT - 1 > 0
+                        ? precision - HOST_BITS_PER_WIDE_INT - 1
+                        : 0))));
   TYPE_MAX_VALUE (type)
-    = build_int_2 ((precision-HOST_BITS_PER_INT > 0 ? -1 : (1<<(precision-1))-1),
-                  (precision-HOST_BITS_PER_INT-1 > 0
-                   ? (1<<(precision-HOST_BITS_PER_INT-1))-1
+    = build_int_2 ((precision - HOST_BITS_PER_WIDE_INT > 0
+                   ? -1 : ((HOST_WIDE_INT) 1 << (precision - 1)) - 1),
+                  (precision - HOST_BITS_PER_WIDE_INT - 1 > 0
+                   ? (((HOST_WIDE_INT) 1
+                       << (precision - HOST_BITS_PER_WIDE_INT - 1))) - 1
                    : 0));
 
   /* Give this type's extreme values this type as their type.  */
@@ -906,7 +1086,41 @@ make_unsigned_type (precision)
 }
 
 /* Set the extreme values of TYPE based on its precision in bits,
-   the lay it out.  This is used both in `make_unsigned_type'
+   then lay it out.  Used when make_signed_type won't do
+   because the tree code is not INTEGER_TYPE.
+   E.g. for Pascal, when the -fsigned-char option is given.  */
+
+void
+fixup_signed_type (type)
+     tree type;
+{
+  register int precision = TYPE_PRECISION (type);
+
+  TYPE_MIN_VALUE (type)
+    = build_int_2 ((precision - HOST_BITS_PER_WIDE_INT > 0
+                   ? 0 : (HOST_WIDE_INT) (-1) << (precision - 1)),
+                  (((HOST_WIDE_INT) (-1)
+                    << (precision - HOST_BITS_PER_WIDE_INT - 1 > 0
+                        ? precision - HOST_BITS_PER_WIDE_INT - 1
+                        : 0))));
+  TYPE_MAX_VALUE (type)
+    = build_int_2 ((precision - HOST_BITS_PER_WIDE_INT > 0
+                   ? -1 : ((HOST_WIDE_INT) 1 << (precision - 1)) - 1),
+                  (precision - HOST_BITS_PER_WIDE_INT - 1 > 0
+                   ? (((HOST_WIDE_INT) 1
+                       << (precision - HOST_BITS_PER_WIDE_INT - 1))) - 1
+                   : 0));
+
+  TREE_TYPE (TYPE_MIN_VALUE (type)) = type;
+  TREE_TYPE (TYPE_MAX_VALUE (type)) = type;
+
+  /* Lay out the type: set its alignment, size, etc.  */
+
+  layout_type (type);
+}
+
+/* Set the extreme values of TYPE based on its precision in bits,
+   then lay it out.  This is used both in `make_unsigned_type'
    and for enumeral types.  */
 
 void
@@ -917,10 +1131,12 @@ fixup_unsigned_type (type)
 
   TYPE_MIN_VALUE (type) = build_int_2 (0, 0);
   TYPE_MAX_VALUE (type)
-    = build_int_2 (precision-HOST_BITS_PER_INT >= 0 ? -1 : (1<<precision)-1,
-                  precision-HOST_BITS_PER_INT > 0
-                  ? ((unsigned) ~0
-                     >> (HOST_BITS_PER_INT - (precision - HOST_BITS_PER_INT)))
+    = build_int_2 (precision - HOST_BITS_PER_WIDE_INT >= 0
+                  ? -1 : ((HOST_WIDE_INT) 1 << precision) - 1,
+                  precision - HOST_BITS_PER_WIDE_INT > 0
+                  ? ((unsigned HOST_WIDE_INT) ~0
+                     >> (HOST_BITS_PER_WIDE_INT
+                         - (precision - HOST_BITS_PER_WIDE_INT)))
                   : 0);
   TREE_TYPE (TYPE_MIN_VALUE (type)) = type;
   TREE_TYPE (TYPE_MAX_VALUE (type)) = type;
@@ -941,9 +1157,9 @@ fixup_unsigned_type (type)
    VOLATILEP is true or SLOW_BYTE_ACCESS is false, we return the smallest
    mode meeting these conditions.
 
-   Otherwise (VOLATILEP is false and SLOW_BYTE_ACCESS is true), if a mode
-   whose size is UNITS_PER_WORD meets all the conditions, it is returned
-   instead.  */
+   Otherwise (VOLATILEP is false and SLOW_BYTE_ACCESS is true), we return
+   the largest mode (but a mode no wider than UNITS_PER_WORD) that meets
+   all the conditions.  */
 
 enum machine_mode
 get_best_mode (bitsize, bitpos, align, largest_mode, volatilep)
@@ -966,7 +1182,7 @@ get_best_mode (bitsize, bitpos, align, largest_mode, volatilep)
 
   if (mode == MAX_MACHINE_MODE
       /* It is tempting to omit the following line
-        if STRICT_ALIGNMENT is not defined.
+        if STRICT_ALIGNMENT is true.
         But that is incorrect, since if the bitfield uses part of 3 bytes
         and we use a 4-byte mode, we could get a spurious segv
         if the extra 4th byte is past the end of memory.
@@ -976,12 +1192,25 @@ get_best_mode (bitsize, bitpos, align, largest_mode, volatilep)
       || (largest_mode != VOIDmode && unit > GET_MODE_BITSIZE (largest_mode)))
     return VOIDmode;
 
-  if (SLOW_BYTE_ACCESS
-      && ! volatilep
-      && BITS_PER_WORD <= MIN (align, BIGGEST_ALIGNMENT)
-      && (largest_mode == VOIDmode
-         || BITS_PER_WORD <= GET_MODE_BITSIZE (largest_mode)))
-    return word_mode;
+  if (SLOW_BYTE_ACCESS && ! volatilep)
+    {
+      enum machine_mode wide_mode = VOIDmode, tmode;
+
+      for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT); tmode != VOIDmode;
+          tmode = GET_MODE_WIDER_MODE (tmode))
+       {
+         unit = GET_MODE_BITSIZE (tmode);
+         if (bitpos / unit == (bitpos + bitsize - 1) / unit
+             && unit <= BITS_PER_WORD
+             && unit <= MIN (align, BIGGEST_ALIGNMENT)
+             && (largest_mode == VOIDmode
+                 || unit <= GET_MODE_BITSIZE (largest_mode)))
+           wide_mode = tmode;
+       }
+
+      if (wide_mode != VOIDmode)
+       return wide_mode;
+    }
 
   return mode;
 }