OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / stor-layout.c
index ed36c5b..944f2d2 100644 (file)
@@ -1,7 +1,7 @@
 /* C-compiler utilities for types and variables storage layout
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1996, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
-   Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+   2011 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -65,10 +65,6 @@ static int excess_unit_span (HOST_WIDE_INT, HOST_WIDE_INT, HOST_WIDE_INT,
 #endif
 extern void debug_rli (record_layout_info);
 \f
-/* SAVE_EXPRs for sizes of types and decls, waiting to be expanded.  */
-
-static GTY(()) VEC(tree,gc) *pending_sizes;
-
 /* Show that REFERENCE_TYPES are internal and should use address_mode.
    Called only by front end.  */
 
@@ -78,48 +74,12 @@ internal_reference_types (void)
   reference_types_internal = 1;
 }
 
-/* Get a VEC of all the objects put on the pending sizes list.  */
-
-VEC(tree,gc) *
-get_pending_sizes (void)
-{
-  VEC(tree,gc) *chain = pending_sizes;
-
-  pending_sizes = 0;
-  return chain;
-}
-
-/* Add EXPR to the pending sizes list.  */
-
-void
-put_pending_size (tree expr)
-{
-  /* Strip any simple arithmetic from EXPR to see if it has an underlying
-     SAVE_EXPR.  */
-  expr = skip_simple_arithmetic (expr);
-
-  if (TREE_CODE (expr) == SAVE_EXPR)
-    VEC_safe_push (tree, gc, pending_sizes, expr);
-}
-
-/* Put a chain of objects into the pending sizes list, which must be
-   empty.  */
-
-void
-put_pending_sizes (VEC(tree,gc) *chain)
-{
-  gcc_assert (!pending_sizes);
-  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.  */
 
 tree
 variable_size (tree size)
 {
-  tree save;
-
   /* Obviously.  */
   if (TREE_CONSTANT (size))
     return size;
@@ -129,42 +89,13 @@ variable_size (tree size)
   if (CONTAINS_PLACEHOLDER_P (size))
     return self_referential_size (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.  */
-  if (lang_hooks.decls.global_bindings_p () < 0)
-    return size;
-
-  size = 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
-     array.  That cleanup is run both on normal exit from the block
-     and in the exception-handler for the block.  Normally, when code
-     is used in both ordinary code and in an exception handler it is
-     `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.  */
-  save = skip_simple_arithmetic (size);
-
-  if (cfun && cfun->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.  Trust it.  */
-    return size;
-
+  /* If we are in the global binding level, we can't make a SAVE_EXPR
+     since it may end up being shared across functions, so it is up
+     to the front-end to deal with this case.  */
   if (lang_hooks.decls.global_bindings_p ())
-    {
-      if (TREE_CONSTANT (size))
-       error ("type size can%'t be explicitly evaluated");
-      else
-       error ("variable-size type declared outside of any function");
-
-      return size_one_node;
-    }
-
-  put_pending_size (save);
+    return size;
 
-  return size;
+  return save_expr (size);
 }
 
 /* An array of functions used for self-referential size computation.  */
@@ -246,6 +177,9 @@ copy_self_referential_tree_r (tree *tp, int *walk_subtrees, void *data)
   else if (code == SAVE_EXPR)
     return error_mark_node;
 
+  else if (code == STATEMENT_LIST)
+    gcc_unreachable ();
+
   return copy_tree_r (tp, walk_subtrees, data);
 }
 
@@ -367,7 +301,7 @@ self_referential_size (tree size)
   VEC_safe_push (tree, gc, size_functions, fndecl);
 
   /* Replace the original expression with a call to the size function.  */
-  return build_call_expr_loc_vec (input_location, fndecl, args);
+  return build_call_expr_loc_vec (UNKNOWN_LOCATION, fndecl, args);
 }
 
 /* Take, queue and compile all the size functions.  It is essential that
@@ -546,6 +480,34 @@ get_mode_alignment (enum machine_mode mode)
   return MIN (BIGGEST_ALIGNMENT, MAX (1, mode_base_align[mode]*BITS_PER_UNIT));
 }
 
+/* Return the natural mode of an array, given that it is SIZE bytes in
+   total and has elements of type ELEM_TYPE.  */
+
+static enum machine_mode
+mode_for_array (tree elem_type, tree size)
+{
+  tree elem_size;
+  unsigned HOST_WIDE_INT int_size, int_elem_size;
+  bool limit_p;
+
+  /* One-element arrays get the component type's mode.  */
+  elem_size = TYPE_SIZE (elem_type);
+  if (simple_cst_equal (size, elem_size))
+    return TYPE_MODE (elem_type);
+
+  limit_p = true;
+  if (host_integerp (size, 1) && host_integerp (elem_size, 1))
+    {
+      int_size = tree_low_cst (size, 1);
+      int_elem_size = tree_low_cst (elem_size, 1);
+      if (int_elem_size > 0
+         && int_size % int_elem_size == 0
+         && targetm.array_mode_supported_p (TYPE_MODE (elem_type),
+                                            int_size / int_elem_size))
+       limit_p = false;
+    }
+  return mode_for_size_tree (size, MODE_INT, limit_p);
+}
 \f
 /* Subroutine of layout_decl: Force alignment required for the data type.
    But if the decl itself wants greater alignment, don't override that.  */
@@ -660,12 +622,13 @@ layout_decl (tree decl, unsigned int known_align)
          /* See if we can use an ordinary integer mode for a bit-field.
             Conditions are: a fixed size that is correct for another mode,
             occupying a complete byte or bytes on proper boundary,
-            and not volatile or not -fstrict-volatile-bitfields.  */
+            and not -fstrict-volatile-bitfields.  If the latter is set,
+            we unfortunately can't check TREE_THIS_VOLATILE, as a cast
+            may make a volatile object later.  */
          if (TYPE_SIZE (type) != 0
              && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
              && GET_MODE_CLASS (TYPE_MODE (type)) == MODE_INT
-             && !(TREE_THIS_VOLATILE (decl)
-                  && flag_strict_volatile_bitfields > 0))
+             && flag_strict_volatile_bitfields <= 0)
            {
              enum machine_mode xmode
                = mode_for_size_tree (DECL_SIZE (decl), MODE_INT, 1);
@@ -973,7 +936,8 @@ update_alignment_for_field (record_layout_info rli, tree field,
         applies if there was an immediately prior, nonzero-size
         bitfield.  (That's the way it is, experimentally.) */
       if ((!is_bitfield && !DECL_PACKED (field))
-         || (!integer_zerop (DECL_SIZE (field))
+         || ((DECL_SIZE (field) == NULL_TREE
+              || !integer_zerop (DECL_SIZE (field)))
              ? !DECL_PACKED (field)
              : (rli->prev_field
                 && DECL_BIT_FIELD_TYPE (rli->prev_field)
@@ -1177,15 +1141,14 @@ place_field (record_layout_info rli, tree field)
     }
 
   /* Does this field automatically have alignment it needs by virtue
-     of the fields that precede it and the record's own alignment?
-     We already align ms_struct fields, so don't re-align them.  */
-  if (known_align < desired_align
-      && !targetm.ms_bitfield_layout_p (rli->t))
+     of the fields that precede it and the record's own alignment?  */
+  if (known_align < desired_align)
     {
       /* No, we need to skip space before this field.
         Bump the cumulative size to multiple of field alignment.  */
 
-      if (DECL_SOURCE_LOCATION (field) != BUILTINS_LOCATION)
+      if (!targetm.ms_bitfield_layout_p (rli->t)
+          && DECL_SOURCE_LOCATION (field) != BUILTINS_LOCATION)
        warning (OPT_Wpadded, "padding struct to align %q+D", field);
 
       /* If the alignment is still within offset_align, just align
@@ -1207,7 +1170,8 @@ place_field (record_layout_info rli, tree field)
 
       if (! TREE_CONSTANT (rli->offset))
        rli->offset_align = desired_align;
-
+      if (targetm.ms_bitfield_layout_p (rli->t))
+       rli->prev_field = NULL;
     }
 
   /* Handle compatibility with PCC.  Note that if the record has any
@@ -1758,6 +1722,221 @@ finalize_type_size (tree type)
     }
 }
 
+/* Return a new underlying object for a bitfield started with FIELD.  */
+
+static tree
+start_bitfield_representative (tree field)
+{
+  tree repr = make_node (FIELD_DECL);
+  DECL_FIELD_OFFSET (repr) = DECL_FIELD_OFFSET (field);
+  /* Force the representative to begin at a BITS_PER_UNIT aligned
+     boundary - C++ may use tail-padding of a base object to
+     continue packing bits so the bitfield region does not start
+     at bit zero (see g++.dg/abi/bitfield5.C for example).
+     Unallocated bits may happen for other reasons as well,
+     for example Ada which allows explicit bit-granular structure layout.  */
+  DECL_FIELD_BIT_OFFSET (repr)
+    = size_binop (BIT_AND_EXPR,
+                 DECL_FIELD_BIT_OFFSET (field),
+                 bitsize_int (~(BITS_PER_UNIT - 1)));
+  SET_DECL_OFFSET_ALIGN (repr, DECL_OFFSET_ALIGN (field));
+  DECL_SIZE (repr) = DECL_SIZE (field);
+  DECL_SIZE_UNIT (repr) = DECL_SIZE_UNIT (field);
+  DECL_PACKED (repr) = DECL_PACKED (field);
+  DECL_CONTEXT (repr) = DECL_CONTEXT (field);
+  return repr;
+}
+
+/* Finish up a bitfield group that was started by creating the underlying
+   object REPR with the last field in the bitfield group FIELD.  */
+
+static void
+finish_bitfield_representative (tree repr, tree field)
+{
+  unsigned HOST_WIDE_INT bitsize, maxbitsize;
+  enum machine_mode mode;
+  tree nextf, size;
+
+  size = size_diffop (DECL_FIELD_OFFSET (field),
+                     DECL_FIELD_OFFSET (repr));
+  gcc_assert (host_integerp (size, 1));
+  bitsize = (tree_low_cst (size, 1) * BITS_PER_UNIT
+            + tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
+            - tree_low_cst (DECL_FIELD_BIT_OFFSET (repr), 1)
+            + tree_low_cst (DECL_SIZE (field), 1));
+
+  /* Round up bitsize to multiples of BITS_PER_UNIT.  */
+  bitsize = (bitsize + BITS_PER_UNIT - 1) & ~(BITS_PER_UNIT - 1);
+
+  /* Now nothing tells us how to pad out bitsize ...  */
+  nextf = DECL_CHAIN (field);
+  while (nextf && TREE_CODE (nextf) != FIELD_DECL)
+    nextf = DECL_CHAIN (nextf);
+  if (nextf)
+    {
+      tree maxsize;
+      /* If there was an error, the field may be not laid out
+         correctly.  Don't bother to do anything.  */
+      if (TREE_TYPE (nextf) == error_mark_node)
+       return;
+      maxsize = size_diffop (DECL_FIELD_OFFSET (nextf),
+                            DECL_FIELD_OFFSET (repr));
+      if (host_integerp (maxsize, 1))
+       {
+         maxbitsize = (tree_low_cst (maxsize, 1) * BITS_PER_UNIT
+                       + tree_low_cst (DECL_FIELD_BIT_OFFSET (nextf), 1)
+                       - tree_low_cst (DECL_FIELD_BIT_OFFSET (repr), 1));
+         /* If the group ends within a bitfield nextf does not need to be
+            aligned to BITS_PER_UNIT.  Thus round up.  */
+         maxbitsize = (maxbitsize + BITS_PER_UNIT - 1) & ~(BITS_PER_UNIT - 1);
+       }
+      else
+       maxbitsize = bitsize;
+    }
+  else
+    {
+      /* ???  If you consider that tail-padding of this struct might be
+         re-used when deriving from it we cannot really do the following
+        and thus need to set maxsize to bitsize?  Also we cannot
+        generally rely on maxsize to fold to an integer constant, so
+        use bitsize as fallback for this case.  */
+      tree maxsize = size_diffop (TYPE_SIZE_UNIT (DECL_CONTEXT (field)),
+                                 DECL_FIELD_OFFSET (repr));
+      if (host_integerp (maxsize, 1))
+       maxbitsize = (tree_low_cst (maxsize, 1) * BITS_PER_UNIT
+                     - tree_low_cst (DECL_FIELD_BIT_OFFSET (repr), 1));
+      else
+       maxbitsize = bitsize;
+    }
+
+  /* Only if we don't artificially break up the representative in
+     the middle of a large bitfield with different possibly
+     overlapping representatives.  And all representatives start
+     at byte offset.  */
+  gcc_assert (maxbitsize % BITS_PER_UNIT == 0);
+
+  /* Find the smallest nice mode to use.  */
+  for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
+       mode = GET_MODE_WIDER_MODE (mode))
+    if (GET_MODE_BITSIZE (mode) >= bitsize)
+      break;
+  if (mode != VOIDmode
+      && (GET_MODE_BITSIZE (mode) > maxbitsize
+         || GET_MODE_BITSIZE (mode) > MAX_FIXED_MODE_SIZE))
+    mode = VOIDmode;
+
+  if (mode == VOIDmode)
+    {
+      /* We really want a BLKmode representative only as a last resort,
+         considering the member b in
+          struct { int a : 7; int b : 17; int c; } __attribute__((packed));
+        Otherwise we simply want to split the representative up
+        allowing for overlaps within the bitfield region as required for
+          struct { int a : 7; int b : 7;
+                   int c : 10; int d; } __attribute__((packed));
+        [0, 15] HImode for a and b, [8, 23] HImode for c.  */
+      DECL_SIZE (repr) = bitsize_int (bitsize);
+      DECL_SIZE_UNIT (repr) = size_int (bitsize / BITS_PER_UNIT);
+      DECL_MODE (repr) = BLKmode;
+      TREE_TYPE (repr) = build_array_type_nelts (unsigned_char_type_node,
+                                                bitsize / BITS_PER_UNIT);
+    }
+  else
+    {
+      unsigned HOST_WIDE_INT modesize = GET_MODE_BITSIZE (mode);
+      DECL_SIZE (repr) = bitsize_int (modesize);
+      DECL_SIZE_UNIT (repr) = size_int (modesize / BITS_PER_UNIT);
+      DECL_MODE (repr) = mode;
+      TREE_TYPE (repr) = lang_hooks.types.type_for_mode (mode, 1);
+    }
+
+  /* Remember whether the bitfield group is at the end of the
+     structure or not.  */
+  DECL_CHAIN (repr) = nextf;
+}
+
+/* Compute and set FIELD_DECLs for the underlying objects we should
+   use for bitfield access for the structure laid out with RLI.  */
+
+static void
+finish_bitfield_layout (record_layout_info rli)
+{
+  tree field, prev;
+  tree repr = NULL_TREE;
+
+  /* Unions would be special, for the ease of type-punning optimizations
+     we could use the underlying type as hint for the representative
+     if the bitfield would fit and the representative would not exceed
+     the union in size.  */
+  if (TREE_CODE (rli->t) != RECORD_TYPE)
+    return;
+
+  for (prev = NULL_TREE, field = TYPE_FIELDS (rli->t);
+       field; field = DECL_CHAIN (field))
+    {
+      if (TREE_CODE (field) != FIELD_DECL)
+       continue;
+
+      /* In the C++ memory model, consecutive bit fields in a structure are
+        considered one memory location and updating a memory location
+        may not store into adjacent memory locations.  */
+      if (!repr
+         && DECL_BIT_FIELD_TYPE (field))
+       {
+         /* Start new representative.  */
+         repr = start_bitfield_representative (field);
+       }
+      else if (repr
+              && ! DECL_BIT_FIELD_TYPE (field))
+       {
+         /* Finish off new representative.  */
+         finish_bitfield_representative (repr, prev);
+         repr = NULL_TREE;
+       }
+      else if (DECL_BIT_FIELD_TYPE (field))
+       {
+         gcc_assert (repr != NULL_TREE);
+
+         /* Zero-size bitfields finish off a representative and
+            do not have a representative themselves.  This is
+            required by the C++ memory model.  */
+         if (integer_zerop (DECL_SIZE (field)))
+           {
+             finish_bitfield_representative (repr, prev);
+             repr = NULL_TREE;
+           }
+
+         /* We assume that either DECL_FIELD_OFFSET of the representative
+            and each bitfield member is a constant or they are equal.
+            This is because we need to be able to compute the bit-offset
+            of each field relative to the representative in get_bit_range
+            during RTL expansion.
+            If these constraints are not met, simply force a new
+            representative to be generated.  That will at most
+            generate worse code but still maintain correctness with
+            respect to the C++ memory model.  */
+         else if (!((host_integerp (DECL_FIELD_OFFSET (repr), 1)
+                     && host_integerp (DECL_FIELD_OFFSET (field), 1))
+                    || operand_equal_p (DECL_FIELD_OFFSET (repr),
+                                        DECL_FIELD_OFFSET (field), 0)))
+           {
+             finish_bitfield_representative (repr, prev);
+             repr = start_bitfield_representative (field);
+           }
+       }
+      else
+       continue;
+
+      if (repr)
+       DECL_BIT_FIELD_REPRESENTATIVE (field) = repr;
+
+      prev = field;
+    }
+
+  if (repr)
+    finish_bitfield_representative (repr, prev);
+}
+
 /* 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, unless FREE_P is false.  Passing a value other than false
@@ -1778,6 +1957,9 @@ finish_record_layout (record_layout_info rli, int free_p)
   /* Perform any last tweaks to the TYPE_SIZE, etc.  */
   finalize_type_size (rli->t);
 
+  /* Compute bitfield representatives.  */
+  finish_bitfield_layout (rli);
+
   /* Propagate TYPE_PACKED to variants.  With C++ templates,
      handle_packed_attribute is too early to do this.  */
   for (variant = TYPE_NEXT_VARIANT (rli->t); variant;
@@ -1922,13 +2104,21 @@ layout_type (tree type)
         TYPE_UNSIGNED (type) = TYPE_UNSIGNED (TREE_TYPE (type));
        TYPE_SIZE_UNIT (type) = int_const_binop (MULT_EXPR,
                                                 TYPE_SIZE_UNIT (innertype),
-                                                size_int (nunits), 0);
+                                                size_int (nunits));
        TYPE_SIZE (type) = int_const_binop (MULT_EXPR, TYPE_SIZE (innertype),
-                                           bitsize_int (nunits), 0);
-
-       /* Always naturally align vectors.  This prevents ABI changes
-          depending on whether or not native vector modes are supported.  */
-       TYPE_ALIGN (type) = tree_low_cst (TYPE_SIZE (type), 0);
+                                           bitsize_int (nunits));
+
+       /* For vector types, we do not default to the mode's alignment.
+          Instead, query a target hook, defaulting to natural alignment.
+          This prevents ABI changes depending on whether or not native
+          vector modes are supported.  */
+       TYPE_ALIGN (type) = targetm.vector_alignment (type);
+
+       /* However, if the underlying mode requires a bigger alignment than
+          what the target hook provides, we cannot use the mode.  For now,
+          simply reject that case.  */
+       gcc_assert (TYPE_ALIGN (type)
+                   >= GET_MODE_ALIGNMENT (TYPE_MODE (type)));
         break;
       }
 
@@ -1996,15 +2186,15 @@ layout_type (tree type)
            if (integer_zerop (element_size))
              length = size_zero_node;
 
-           /* The initial subtraction should happen in the original type so
-              that (possible) negative values are handled appropriately.  */
+           /* The computation should happen in the original signedness so
+              that (possible) negative values are handled appropriately
+              when determining overflow.  */
            else
              length
-               = size_binop (PLUS_EXPR, size_one_node,
-                             fold_convert (sizetype,
-                                           fold_build2 (MINUS_EXPR,
-                                                        TREE_TYPE (lb),
-                                                        ub, lb)));
+               = fold_convert (sizetype,
+                               size_binop (PLUS_EXPR,
+                                           build_int_cst (TREE_TYPE (lb), 1),
+                                           size_binop (MINUS_EXPR, ub, lb)));
 
            TYPE_SIZE (type) = size_binop (MULT_EXPR, element_size,
                                           fold_convert (bitsizetype,
@@ -2039,14 +2229,8 @@ layout_type (tree type)
            && (TYPE_MODE (TREE_TYPE (type)) != BLKmode
                || TYPE_NO_FORCE_BLK (TREE_TYPE (type))))
          {
-           /* One-element arrays get the component type's mode.  */
-           if (simple_cst_equal (TYPE_SIZE (type),
-                                 TYPE_SIZE (TREE_TYPE (type))))
-             SET_TYPE_MODE (type, TYPE_MODE (TREE_TYPE (type)));
-           else
-             SET_TYPE_MODE (type, mode_for_size_tree (TYPE_SIZE (type),
-                                                      MODE_INT, 1));
-
+           SET_TYPE_MODE (type, mode_for_array (TREE_TYPE (type),
+                                                TYPE_SIZE (type)));
            if (TYPE_MODE (type) != BLKmode
                && STRICT_ALIGNMENT && TYPE_ALIGN (type) < BIGGEST_ALIGNMENT
                && TYPE_ALIGN (type) < GET_MODE_ALIGNMENT (TYPE_MODE (type)))
@@ -2131,12 +2315,12 @@ vector_type_mode (const_tree t)
 
   gcc_assert (TREE_CODE (t) == VECTOR_TYPE);
 
-  mode = t->type.mode;
+  mode = t->type_common.mode;
   if (VECTOR_MODE_P (mode)
       && (!targetm.vector_mode_supported_p (mode)
          || !have_regs_of_mode[mode]))
     {
-      enum machine_mode innermode = TREE_TYPE (t)->type.mode;
+      enum machine_mode innermode = TREE_TYPE (t)->type_common.mode;
 
       /* For integers, try mapping it to a same-sized scalar mode.  */
       if (GET_MODE_CLASS (innermode) == MODE_INT)
@@ -2232,93 +2416,76 @@ make_accum_type (int precision, int unsignedp, int satp)
   return type;
 }
 
-/* Initialize sizetype and bitsizetype to a reasonable and temporary
-   value to enable integer types to be created.  */
+/* Initialize sizetypes so layout_type can use them.  */
 
 void
 initialize_sizetypes (void)
 {
-  tree t = make_node (INTEGER_TYPE);
-  int precision = GET_MODE_BITSIZE (SImode);
-
-  SET_TYPE_MODE (t, SImode);
-  TYPE_ALIGN (t) = GET_MODE_ALIGNMENT (SImode);
-  TYPE_IS_SIZETYPE (t) = 1;
-  TYPE_UNSIGNED (t) = 1;
-  TYPE_SIZE (t) = build_int_cst (t, precision);
-  TYPE_SIZE_UNIT (t) = build_int_cst (t, GET_MODE_SIZE (SImode));
-  TYPE_PRECISION (t) = precision;
-
-  set_min_and_max_values_for_integral_type (t, precision, true);
-
-  sizetype = t;
-  bitsizetype = build_distinct_type_copy (t);
-}
-
-/* Make sizetype a version of TYPE, and initialize *sizetype accordingly.
-   We do this by overwriting the stub sizetype and bitsizetype nodes created
-   by initialize_sizetypes.  This makes sure that (a) anything stubby about
-   them no longer exists and (b) any INTEGER_CSTs created with such a type,
-   remain valid.  */
-
-void
-set_sizetype (tree type)
-{
-  tree t, max;
-  int oprecision = TYPE_PRECISION (type);
-  /* The *bitsizetype types use a precision that avoids overflows when
-     calculating signed sizes / offsets in bits.  However, when
-     cross-compiling from a 32 bit to a 64 bit host, we are limited to 64 bit
-     precision.  */
-  int precision
-    = MIN (oprecision + BITS_PER_UNIT_LOG + 1, MAX_FIXED_MODE_SIZE);
-  precision
-    = GET_MODE_PRECISION (smallest_mode_for_size (precision, MODE_INT));
-  if (precision > HOST_BITS_PER_WIDE_INT * 2)
-    precision = HOST_BITS_PER_WIDE_INT * 2;
-
-  /* sizetype must be an unsigned type.  */
-  gcc_assert (TYPE_UNSIGNED (type));
-
-  t = build_distinct_type_copy (type);
-  /* We want to use sizetype's cache, as we will be replacing that type.  */
-  TYPE_CACHED_VALUES (t) = TYPE_CACHED_VALUES (sizetype);
-  TYPE_CACHED_VALUES_P (t) = TYPE_CACHED_VALUES_P (sizetype);
-  TREE_TYPE (TYPE_CACHED_VALUES (t)) = type;
-  TYPE_UID (t) = TYPE_UID (sizetype);
-  TYPE_IS_SIZETYPE (t) = 1;
-
-  /* Replace our original stub sizetype.  */
-  memcpy (sizetype, t, tree_size (sizetype));
-  TYPE_MAIN_VARIANT (sizetype) = sizetype;
-  TYPE_CANONICAL (sizetype) = sizetype;
-
+  int precision, bprecision;
+
+  /* Get sizetypes precision from the SIZE_TYPE target macro.  */
+  if (strcmp (SIZE_TYPE, "unsigned int") == 0)
+    precision = INT_TYPE_SIZE;
+  else if (strcmp (SIZE_TYPE, "long unsigned int") == 0)
+    precision = LONG_TYPE_SIZE;
+  else if (strcmp (SIZE_TYPE, "long long unsigned int") == 0)
+    precision = LONG_LONG_TYPE_SIZE;
+  else if (strcmp (SIZE_TYPE, "short unsigned int") == 0)
+    precision = SHORT_TYPE_SIZE;
+  else
+    gcc_unreachable ();
+
+  bprecision
+    = MIN (precision + BITS_PER_UNIT_LOG + 1, MAX_FIXED_MODE_SIZE);
+  bprecision
+    = GET_MODE_PRECISION (smallest_mode_for_size (bprecision, MODE_INT));
+  if (bprecision > HOST_BITS_PER_WIDE_INT * 2)
+    bprecision = HOST_BITS_PER_WIDE_INT * 2;
+
+  /* Create stubs for sizetype and bitsizetype so we can create constants.  */
+  sizetype = make_node (INTEGER_TYPE);
+  TYPE_NAME (sizetype) = get_identifier ("sizetype");
+  TYPE_PRECISION (sizetype) = precision;
+  TYPE_UNSIGNED (sizetype) = 1;
+  TYPE_IS_SIZETYPE (sizetype) = 1;
+  bitsizetype = make_node (INTEGER_TYPE);
+  TYPE_NAME (bitsizetype) = get_identifier ("bitsizetype");
+  TYPE_PRECISION (bitsizetype) = bprecision;
+  TYPE_UNSIGNED (bitsizetype) = 1;
+  TYPE_IS_SIZETYPE (bitsizetype) = 1;
+
+  /* Now layout both types manually.  */
+  SET_TYPE_MODE (sizetype, smallest_mode_for_size (precision, MODE_INT));
+  TYPE_ALIGN (sizetype) = GET_MODE_ALIGNMENT (TYPE_MODE (sizetype));
+  TYPE_SIZE (sizetype) = bitsize_int (precision);
+  TYPE_SIZE_UNIT (sizetype) = size_int (GET_MODE_SIZE (TYPE_MODE (sizetype)));
+  set_min_and_max_values_for_integral_type (sizetype, precision,
+                                           /*is_unsigned=*/true);
   /* sizetype is unsigned but we need to fix TYPE_MAX_VALUE so that it is
      sign-extended in a way consistent with force_fit_type.  */
-  max = TYPE_MAX_VALUE (sizetype);
   TYPE_MAX_VALUE (sizetype)
-    = double_int_to_tree (sizetype, tree_to_double_int (max));
-
-  t = make_node (INTEGER_TYPE);
-  TYPE_NAME (t) = get_identifier ("bit_size_type");
-  /* We want to use bitsizetype's cache, as we will be replacing that type.  */
-  TYPE_CACHED_VALUES (t) = TYPE_CACHED_VALUES (bitsizetype);
-  TYPE_CACHED_VALUES_P (t) = TYPE_CACHED_VALUES_P (bitsizetype);
-  TYPE_PRECISION (t) = precision;
-  TYPE_UID (t) = TYPE_UID (bitsizetype);
-  TYPE_IS_SIZETYPE (t) = 1;
-
-  /* Replace our original stub bitsizetype.  */
-  memcpy (bitsizetype, t, tree_size (bitsizetype));
-  TYPE_MAIN_VARIANT (bitsizetype) = bitsizetype;
-  TYPE_CANONICAL (bitsizetype) = bitsizetype;
-
-  fixup_unsigned_type (bitsizetype);
+    = double_int_to_tree (sizetype,
+                         tree_to_double_int (TYPE_MAX_VALUE (sizetype)));
+
+  SET_TYPE_MODE (bitsizetype, smallest_mode_for_size (bprecision, MODE_INT));
+  TYPE_ALIGN (bitsizetype) = GET_MODE_ALIGNMENT (TYPE_MODE (bitsizetype));
+  TYPE_SIZE (bitsizetype) = bitsize_int (bprecision);
+  TYPE_SIZE_UNIT (bitsizetype)
+    = size_int (GET_MODE_SIZE (TYPE_MODE (bitsizetype)));
+  set_min_and_max_values_for_integral_type (bitsizetype, bprecision,
+                                           /*is_unsigned=*/true);
+  /* bitsizetype is unsigned but we need to fix TYPE_MAX_VALUE so that it is
+     sign-extended in a way consistent with force_fit_type.  */
+  TYPE_MAX_VALUE (bitsizetype)
+    = double_int_to_tree (bitsizetype,
+                         tree_to_double_int (TYPE_MAX_VALUE (bitsizetype)));
 
   /* Create the signed variants of *sizetype.  */
-  ssizetype = make_signed_type (oprecision);
+  ssizetype = make_signed_type (TYPE_PRECISION (sizetype));
+  TYPE_NAME (ssizetype) = get_identifier ("ssizetype");
   TYPE_IS_SIZETYPE (ssizetype) = 1;
-  sbitsizetype = make_signed_type (precision);
+  sbitsizetype = make_signed_type (TYPE_PRECISION (bitsizetype));
+  TYPE_NAME (sbitsizetype) = get_identifier ("sbitsizetype");
   TYPE_IS_SIZETYPE (sbitsizetype) = 1;
 }
 \f
@@ -2427,6 +2594,13 @@ fixup_unsigned_type (tree type)
 /* Find the best machine mode to use when referencing a bit field of length
    BITSIZE bits starting at BITPOS.
 
+   BITREGION_START is the bit position of the first bit in this
+   sequence of bit fields.  BITREGION_END is the last bit in this
+   sequence.  If these two fields are non-zero, we should restrict the
+   memory access to a maximum sized chunk of
+   BITREGION_END - BITREGION_START + 1.  Otherwise, we are allowed to touch
+   any adjacent non bit-fields.
+
    The underlying object is known to be aligned to a boundary of ALIGN bits.
    If LARGEST_MODE is not VOIDmode, it means that we should not use a mode
    larger than LARGEST_MODE (usually SImode).
@@ -2444,18 +2618,29 @@ fixup_unsigned_type (tree type)
    decide which of the above modes should be used.  */
 
 enum machine_mode
-get_best_mode (int bitsize, int bitpos, unsigned int align,
+get_best_mode (int bitsize, int bitpos,
+              unsigned HOST_WIDE_INT bitregion_start,
+              unsigned HOST_WIDE_INT bitregion_end,
+              unsigned int align,
               enum machine_mode largest_mode, int volatilep)
 {
   enum machine_mode mode;
   unsigned int unit = 0;
+  unsigned HOST_WIDE_INT maxbits;
+
+  /* If unset, no restriction.  */
+  if (!bitregion_end)
+    maxbits = MAX_FIXED_MODE_SIZE;
+  else
+    maxbits = bitregion_end - bitregion_start + 1;
 
   /* Find the narrowest integer mode that contains the bit field.  */
   for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
        mode = GET_MODE_WIDER_MODE (mode))
     {
       unit = GET_MODE_BITSIZE (mode);
-      if ((bitpos % unit) + bitsize <= unit)
+      if (unit == GET_MODE_PRECISION (mode)
+         && (bitpos % unit) + bitsize <= unit)
        break;
     }
 
@@ -2468,7 +2653,10 @@ get_best_mode (int bitsize, int bitpos, unsigned int align,
         (Though at least one Unix compiler ignores this problem:
         that on the Sequent 386 machine.  */
       || MIN (unit, BIGGEST_ALIGNMENT) > align
-      || (largest_mode != VOIDmode && unit > GET_MODE_BITSIZE (largest_mode)))
+      || (largest_mode != VOIDmode && unit > GET_MODE_BITSIZE (largest_mode))
+      || unit > maxbits
+      || (bitregion_end
+         && bitpos - (bitpos % unit) + unit > bitregion_end + 1))
     return VOIDmode;
 
   if ((SLOW_BYTE_ACCESS && ! volatilep)
@@ -2480,11 +2668,15 @@ get_best_mode (int bitsize, int bitpos, unsigned int align,
           tmode = GET_MODE_WIDER_MODE (tmode))
        {
          unit = GET_MODE_BITSIZE (tmode);
-         if (bitpos / unit == (bitpos + bitsize - 1) / unit
+         if (unit == GET_MODE_PRECISION (tmode)
+             && bitpos / unit == (bitpos + bitsize - 1) / unit
              && unit <= BITS_PER_WORD
              && unit <= MIN (align, BIGGEST_ALIGNMENT)
+             && unit <= maxbits
              && (largest_mode == VOIDmode
-                 || unit <= GET_MODE_BITSIZE (largest_mode)))
+                 || unit <= GET_MODE_BITSIZE (largest_mode))
+             && (bitregion_end == 0
+                 || bitpos - (bitpos % unit) + unit <= bitregion_end + 1))
            wide_mode = tmode;
        }