To refresh everyone's memory, here is the problem:

struct
{
    unsigned int a : 4;
    unsigned char b;
    unsigned int c: 6;
} var;

void seta(){
      var.a = 12;
}

Stores into <a> cannot touch <b>, so we can't store with anything wider (e.g. a 32 bit store) that will touch <b>. This problem can be seen on strictly aligned targets such as Arm, where we store the above sequence with a 32-bit store. Or on x86-64 with <a> being volatile (PR48124).

This patch fixes both problems, but only for the C++ memory model. This is NOT a generic fix PR48124, only a fix when using "--param allow-store-data-races=0".

The gist of this patch is in max_field_size(), where we calculate the maximum number of bits we can store into. In doing this calculation I assume we can store into the padding without causing any races. So, padding between fields and at the end of the structure are included.

Tested on x86-64 with "--param allow-store-data-races=0".

How does this look?  I'd like a review before committing to the branch.
Aldy

        * Makefile.in (expr.o): Depend on PARAMS_H.
        * machmode.h (get_best_mode): Add argument.
        * fold-const.c (optimize_bit_field_compare): Add argument to
        get_best_mode.
        (fold_truthop): Same.
        * ifcvt.c (noce_emit_move_insn): Add argument to store_bit_field.
        * expr.c (emit_group_store): Same.
        (copy_blkmode_from_reg): Same.
        (write_complex_part): Same.
        (optimize_bitfield_assignment_op): Add argument.
        Add argument to get_best_mode.
        (max_field_size): New.
        (expand_assignment): Calculate maxbits and pass it down
        accordingly.
        (store_field): New argument.
        (expand_expr_real_2): New argument to store_field.
        Include params.h.
        * expr.h (store_bit_field): New argument.
        * stor-layout.c (get_best_mode): Restrict mode expansion by taking
        into account maxbits.
        * calls.c (store_unaligned_arguments_into_pseudos): New argument
        to store_bit_field.
        * expmed.c (store_bit_field_1): New argument.  Use it.
        (store_bit_field): Same.
        (store_fixed_bit_field): Same.
        (store_split_bit_field): Same.
        (extract_bit_field_1): Pass new argument to get_best_mode.
        (extract_bit_field): Same.
        * stmt.c (store_bit_field): Pass new argument to store_bit_field.
        * tree.h (DECL_THREAD_VISIBLE_P): New.

Index: machmode.h
===================================================================
--- machmode.h  (revision 170745)
+++ machmode.h  (working copy)
@@ -248,7 +248,9 @@ extern enum machine_mode mode_for_vector
 
 /* Find the best mode to use to access a bit field.  */
 
-extern enum machine_mode get_best_mode (int, int, unsigned int,
+extern enum machine_mode get_best_mode (int, int,
+                                       unsigned HOST_WIDE_INT,
+                                       unsigned int,
                                        enum machine_mode, int);
 
 /* Determine alignment, 1<=result<=BIGGEST_ALIGNMENT.  */
Index: tree.h
===================================================================
--- tree.h      (revision 170745)
+++ tree.h      (working copy)
@@ -3102,6 +3102,10 @@ struct GTY(()) tree_parm_decl {
 #define DECL_THREAD_LOCAL_P(NODE) \
   (VAR_DECL_CHECK (NODE)->decl_with_vis.tls_model >= TLS_MODEL_REAL)
 
+/* Return true if a VAR_DECL is visible from another thread.  */
+#define DECL_THREAD_VISIBLE_P(NODE) \
+  (TREE_STATIC (NODE) && !DECL_THREAD_LOCAL_P (NODE))
+
 /* In a non-local VAR_DECL with static storage duration, true if the
    variable has an initialization priority.  If false, the variable
    will be initialized at the DEFAULT_INIT_PRIORITY.  */
Index: fold-const.c
===================================================================
--- fold-const.c        (revision 170745)
+++ fold-const.c        (working copy)
@@ -3426,7 +3426,7 @@ optimize_bit_field_compare (location_t l
       && flag_strict_volatile_bitfields > 0)
     nmode = lmode;
   else
-    nmode = get_best_mode (lbitsize, lbitpos,
+    nmode = get_best_mode (lbitsize, lbitpos, 0,
                           const_p ? TYPE_ALIGN (TREE_TYPE (linner))
                           : MIN (TYPE_ALIGN (TREE_TYPE (linner)),
                                  TYPE_ALIGN (TREE_TYPE (rinner))),
@@ -5254,7 +5254,7 @@ fold_truthop (location_t loc, enum tree_
      to be relative to a field of that size.  */
   first_bit = MIN (ll_bitpos, rl_bitpos);
   end_bit = MAX (ll_bitpos + ll_bitsize, rl_bitpos + rl_bitsize);
-  lnmode = get_best_mode (end_bit - first_bit, first_bit,
+  lnmode = get_best_mode (end_bit - first_bit, first_bit, 0,
                          TYPE_ALIGN (TREE_TYPE (ll_inner)), word_mode,
                          volatilep);
   if (lnmode == VOIDmode)
@@ -5319,7 +5319,7 @@ fold_truthop (location_t loc, enum tree_
 
       first_bit = MIN (lr_bitpos, rr_bitpos);
       end_bit = MAX (lr_bitpos + lr_bitsize, rr_bitpos + rr_bitsize);
-      rnmode = get_best_mode (end_bit - first_bit, first_bit,
+      rnmode = get_best_mode (end_bit - first_bit, first_bit, 0,
                              TYPE_ALIGN (TREE_TYPE (lr_inner)), word_mode,
                              volatilep);
       if (rnmode == VOIDmode)
Index: ifcvt.c
===================================================================
--- ifcvt.c     (revision 170745)
+++ ifcvt.c     (working copy)
@@ -879,7 +879,7 @@ noce_emit_move_insn (rtx x, rtx y)
                }
 
              gcc_assert (start < (MEM_P (op) ? BITS_PER_UNIT : BITS_PER_WORD));
-             store_bit_field (op, size, start, GET_MODE (x), y);
+             store_bit_field (op, size, start, 0, GET_MODE (x), y);
              return;
            }
 
@@ -933,7 +933,7 @@ noce_emit_move_insn (rtx x, rtx y)
   inner = XEXP (outer, 0);
   outmode = GET_MODE (outer);
   bitpos = SUBREG_BYTE (outer) * BITS_PER_UNIT;
-  store_bit_field (inner, GET_MODE_BITSIZE (outmode), bitpos, outmode, y);
+  store_bit_field (inner, GET_MODE_BITSIZE (outmode), bitpos, 0, outmode, y);
 }
 
 /* Return sequence of instructions generated by if conversion.  This
Index: expr.c
===================================================================
--- expr.c      (revision 170745)
+++ expr.c      (working copy)
@@ -54,6 +54,7 @@ along with GCC; see the file COPYING3.  
 #include "diagnostic.h"
 #include "ssaexpand.h"
 #include "target-globals.h"
+#include "params.h"
 
 /* Decide whether a function's arguments should be processed
    from first to last or from last to first.
@@ -142,7 +143,8 @@ static void store_constructor_field (rtx
                                     HOST_WIDE_INT, enum machine_mode,
                                     tree, tree, int, alias_set_type);
 static void store_constructor (tree, rtx, int, HOST_WIDE_INT);
-static rtx store_field (rtx, HOST_WIDE_INT, HOST_WIDE_INT, enum machine_mode,
+static rtx store_field (rtx, HOST_WIDE_INT, HOST_WIDE_INT,
+                       unsigned HOST_WIDE_INT, enum machine_mode,
                        tree, tree, alias_set_type, bool);
 
 static unsigned HOST_WIDE_INT highest_pow2_factor_for_target (const_tree, 
const_tree);
@@ -2077,7 +2079,7 @@ emit_group_store (rtx orig_dst, rtx src,
        emit_move_insn (adjust_address (dest, mode, bytepos), tmps[i]);
       else
        store_bit_field (dest, bytelen * BITS_PER_UNIT, bytepos * BITS_PER_UNIT,
-                        mode, tmps[i]);
+                        0, mode, tmps[i]);
     }
 
   /* Copy from the pseudo into the (probable) hard reg.  */
@@ -2171,7 +2173,7 @@ copy_blkmode_from_reg (rtx tgtblk, rtx s
 
       /* Use xbitpos for the source extraction (right justified) and
         bitpos for the destination store (left justified).  */
-      store_bit_field (dst, bitsize, bitpos % BITS_PER_WORD, copy_mode,
+      store_bit_field (dst, bitsize, bitpos % BITS_PER_WORD, 0, copy_mode,
                       extract_bit_field (src, bitsize,
                                          xbitpos % BITS_PER_WORD, 1, false,
                                          NULL_RTX, copy_mode, copy_mode));
@@ -2830,7 +2832,7 @@ write_complex_part (rtx cplx, rtx val, b
        gcc_assert (MEM_P (cplx) && ibitsize < BITS_PER_WORD);
     }
 
-  store_bit_field (cplx, ibitsize, imag_p ? ibitsize : 0, imode, val);
+  store_bit_field (cplx, ibitsize, imag_p ? ibitsize : 0, 0, imode, val);
 }
 
 /* Extract one of the components of the complex value CPLX.  Extract the
@@ -3966,6 +3968,7 @@ get_subtarget (rtx x)
 static bool
 optimize_bitfield_assignment_op (unsigned HOST_WIDE_INT bitsize,
                                 unsigned HOST_WIDE_INT bitpos,
+                                unsigned HOST_WIDE_INT maxbits,
                                 enum machine_mode mode1, rtx str_rtx,
                                 tree to, tree src)
 {
@@ -4000,7 +4003,7 @@ optimize_bitfield_assignment_op (unsigne
 
       if (str_bitsize == 0 || str_bitsize > BITS_PER_WORD)
        str_mode = word_mode;
-      str_mode = get_best_mode (bitsize, bitpos,
+      str_mode = get_best_mode (bitsize, bitpos, maxbits,
                                MEM_ALIGN (str_rtx), str_mode, 0);
       if (str_mode == VOIDmode)
        return false;
@@ -4111,6 +4114,92 @@ optimize_bitfield_assignment_op (unsigne
   return false;
 }
 
+/* In the C++ memory model, consecutive bit fields in a structure are
+   considered one memory location.
+
+   Given a COMPONENT_REF, this function returns the maximum number of
+   bits we are allowed to store into, when storing into the
+   COMPONENT_REF.  We return 0, if there is no restriction.
+
+   EXP is the COMPONENT_REF.
+
+   BITPOS is the position in bits where the bit starts within the structure.
+   BITSIZE is size in bits of the field being referenced in EXP.
+
+   For example, while storing into FOO.A here...
+
+      struct {
+        BIT 0:
+          unsigned int a : 4;
+         unsigned int b : 1;
+       BIT 8:
+         unsigned char c;
+         unsigned int d : 6;
+      } foo;
+
+   ...we are not allowed to store past <b>, so for the layout above,
+   we would return 8 maximum bits (because who cares if we store into
+   the padding).  */
+
+
+static unsigned HOST_WIDE_INT
+max_field_size (tree exp, HOST_WIDE_INT bitpos, HOST_WIDE_INT bitsize)
+{
+  tree field, record_type, fld;
+  HOST_WIDE_INT maxbits = bitsize;
+
+  gcc_assert (TREE_CODE (exp) == COMPONENT_REF);
+
+  /* If other threads can't see this value, no need to restrict stores.  */
+  if (ALLOW_STORE_DATA_RACES
+      || !DECL_THREAD_VISIBLE_P (TREE_OPERAND (exp, 0)))
+    return 0;
+
+  field = TREE_OPERAND (exp, 1);
+  record_type = DECL_FIELD_CONTEXT (field);
+
+  /* Find the original field within the structure.  */
+  for (fld = TYPE_FIELDS (record_type); fld; fld = DECL_CHAIN (fld))
+    if (fld == field)
+      break;
+  gcc_assert (fld == field);
+
+  /* If this is the last element in the structure, we can touch from
+     BITPOS to the end of the structure (including the padding).  */
+  if (!DECL_CHAIN (fld))
+    return TREE_INT_CST_LOW (TYPE_SIZE (record_type)) - bitpos;
+
+  /* Count contiguous bit fields not separated by a 0-length bit-field.  */
+  for (fld = DECL_CHAIN (fld); fld; fld = DECL_CHAIN (fld))
+    {
+      tree t, offset;
+      enum machine_mode mode;
+      int unsignedp, volatilep;
+
+      if (TREE_CODE (fld) != FIELD_DECL)
+       continue;
+
+      t = build3 (COMPONENT_REF, TREE_TYPE (exp),
+                 unshare_expr (TREE_OPERAND (exp, 0)),
+                 fld, NULL_TREE);
+      get_inner_reference (t, &bitsize, &bitpos, &offset,
+                          &mode, &unsignedp, &volatilep, true);
+
+      /* Only count contiguous bit fields, that are not separated by a
+        zero-length bit field.  */
+      if (!DECL_BIT_FIELD (fld)
+         || bitsize == 0)
+       {
+         /* Include the padding up to the next field.  */
+         maxbits += bitpos - maxbits;
+         break;
+       }
+
+      maxbits += bitsize;
+    }
+
+  return maxbits;
+}
 
 /* Expand an assignment that stores the value of FROM into TO.  If NONTEMPORAL
    is true, try generating a nontemporal store.  */
@@ -4213,6 +4302,9 @@ expand_assignment (tree to, tree from, b
     {
       enum machine_mode mode1;
       HOST_WIDE_INT bitsize, bitpos;
+      /* Max consecutive bits we are allowed to touch while storing
+        into TO.  */
+      HOST_WIDE_INT maxbits = 0;
       tree offset;
       int unsignedp;
       int volatilep = 0;
@@ -4222,6 +4314,10 @@ expand_assignment (tree to, tree from, b
       tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1,
                                 &unsignedp, &volatilep, true);
 
+      if (TREE_CODE (to) == COMPONENT_REF
+         && DECL_BIT_FIELD (TREE_OPERAND (to, 1)))
+       maxbits = max_field_size (to, bitpos, bitsize);
+
       /* If we are going to use store_bit_field and extract_bit_field,
         make sure to_rtx will be safe for multiple use.  */
 
@@ -4322,11 +4418,12 @@ expand_assignment (tree to, tree from, b
                MEM_KEEP_ALIAS_SET_P (to_rtx) = 1;
            }
 
-         if (optimize_bitfield_assignment_op (bitsize, bitpos, mode1,
+         if (optimize_bitfield_assignment_op (bitsize, bitpos, maxbits, mode1,
                                               to_rtx, to, from))
            result = NULL;
          else
-           result = store_field (to_rtx, bitsize, bitpos, mode1, from,
+           result = store_field (to_rtx, bitsize, bitpos, maxbits,
+                                 mode1, from,
                                  TREE_TYPE (tem), get_alias_set (to),
                                  nontemporal);
        }
@@ -4734,7 +4831,7 @@ store_expr (tree exp, rtx target, int ca
                              : BLOCK_OP_NORMAL));
          else if (GET_MODE (target) == BLKmode)
            store_bit_field (target, INTVAL (expr_size (exp)) * BITS_PER_UNIT,
-                            0, GET_MODE (temp), temp);
+                            0, 0, GET_MODE (temp), temp);
          else
            convert_move (target, temp, unsignedp);
        }
@@ -5177,7 +5274,8 @@ store_constructor_field (rtx target, uns
       store_constructor (exp, target, cleared, bitsize / BITS_PER_UNIT);
     }
   else
-    store_field (target, bitsize, bitpos, mode, exp, type, alias_set, false);
+    store_field (target, bitsize, bitpos, 0, mode, exp, type, alias_set,
+                false);
 }
 
 /* Store the value of constructor EXP into the rtx TARGET.
@@ -5751,6 +5849,8 @@ store_constructor (tree exp, rtx target,
    BITSIZE bits, starting BITPOS bits from the start of TARGET.
    If MODE is VOIDmode, it means that we are storing into a bit-field.
 
+   MAXBITS is the number of bits we can store into, 0 if no limit.
+
    Always return const0_rtx unless we have something particular to
    return.
 
@@ -5764,6 +5864,7 @@ store_constructor (tree exp, rtx target,
 
 static rtx
 store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
+            unsigned HOST_WIDE_INT maxbits,
             enum machine_mode mode, tree exp, tree type,
             alias_set_type alias_set, bool nontemporal)
 {
@@ -5796,8 +5897,8 @@ store_field (rtx target, HOST_WIDE_INT b
       if (bitsize != (HOST_WIDE_INT) GET_MODE_BITSIZE (GET_MODE (target)))
        emit_move_insn (object, target);
 
-      store_field (blk_object, bitsize, bitpos, mode, exp, type, alias_set,
-                  nontemporal);
+      store_field (blk_object, bitsize, bitpos, maxbits,
+                  mode, exp, type, alias_set, nontemporal);
 
       emit_move_insn (target, object);
 
@@ -5912,7 +6013,7 @@ store_field (rtx target, HOST_WIDE_INT b
        }
 
       /* Store the value in the bitfield.  */
-      store_bit_field (target, bitsize, bitpos, mode, temp);
+      store_bit_field (target, bitsize, bitpos, maxbits, mode, temp);
 
       return const0_rtx;
     }
@@ -7323,7 +7424,7 @@ expand_expr_real_2 (sepops ops, rtx targ
                                                    (treeop0))
                                 * BITS_PER_UNIT),
                                (HOST_WIDE_INT) GET_MODE_BITSIZE (mode)),
-                          0, TYPE_MODE (valtype), treeop0,
+                          0, 0, TYPE_MODE (valtype), treeop0,
                           type, 0, false);
            }
 
Index: expr.h
===================================================================
--- expr.h      (revision 170745)
+++ expr.h      (working copy)
@@ -666,7 +666,8 @@ extern enum machine_mode
 mode_for_extraction (enum extraction_pattern, int);
 
 extern void store_bit_field (rtx, unsigned HOST_WIDE_INT,
-                            unsigned HOST_WIDE_INT, enum machine_mode, rtx);
+                            unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
+                            enum machine_mode, rtx);
 extern rtx extract_bit_field (rtx, unsigned HOST_WIDE_INT,
                              unsigned HOST_WIDE_INT, int, bool, rtx,
                              enum machine_mode, enum machine_mode);
Index: stor-layout.c
===================================================================
--- stor-layout.c       (revision 170745)
+++ stor-layout.c       (working copy)
@@ -2432,6 +2432,9 @@ fixup_unsigned_type (tree type)
 /* Find the best machine mode to use when referencing a bit field of length
    BITSIZE bits starting at BITPOS.
 
+   MAXBITS is the maximum number of bits we are allowed to touch, when
+   referencing this bit field.  MAXBITS is 0 if there is no limit.
+
    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).
@@ -2449,7 +2452,8 @@ 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 maxbits,
+              unsigned int align,
               enum machine_mode largest_mode, int volatilep)
 {
   enum machine_mode mode;
@@ -2488,6 +2492,7 @@ get_best_mode (int bitsize, int bitpos, 
          if (bitpos / unit == (bitpos + bitsize - 1) / unit
              && unit <= BITS_PER_WORD
              && unit <= MIN (align, BIGGEST_ALIGNMENT)
+             && (!maxbits || unit <= maxbits)
              && (largest_mode == VOIDmode
                  || unit <= GET_MODE_BITSIZE (largest_mode)))
            wide_mode = tmode;
Index: calls.c
===================================================================
--- calls.c     (revision 170745)
+++ calls.c     (working copy)
@@ -903,7 +903,7 @@ store_unaligned_arguments_into_pseudos (
            emit_move_insn (reg, const0_rtx);
 
            bytes -= bitsize / BITS_PER_UNIT;
-           store_bit_field (reg, bitsize, endian_correction, word_mode,
+           store_bit_field (reg, bitsize, endian_correction, 0, word_mode,
                             word);
          }
       }
Index: expmed.c
===================================================================
--- expmed.c    (revision 170745)
+++ expmed.c    (working copy)
@@ -47,9 +47,13 @@ struct target_expmed *this_target_expmed
 
 static void store_fixed_bit_field (rtx, unsigned HOST_WIDE_INT,
                                   unsigned HOST_WIDE_INT,
-                                  unsigned HOST_WIDE_INT, rtx);
+                                  unsigned HOST_WIDE_INT,
+                                  unsigned HOST_WIDE_INT,
+                                  rtx);
 static void store_split_bit_field (rtx, unsigned HOST_WIDE_INT,
-                                  unsigned HOST_WIDE_INT, rtx);
+                                  unsigned HOST_WIDE_INT,
+                                  unsigned HOST_WIDE_INT,
+                                  rtx);
 static rtx extract_fixed_bit_field (enum machine_mode, rtx,
                                    unsigned HOST_WIDE_INT,
                                    unsigned HOST_WIDE_INT,
@@ -349,7 +353,9 @@ check_predicate_volatile_ok (enum insn_c
 
 static bool
 store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
-                  unsigned HOST_WIDE_INT bitnum, enum machine_mode fieldmode,
+                  unsigned HOST_WIDE_INT bitnum,
+                  unsigned HOST_WIDE_INT maxbits,
+                  enum machine_mode fieldmode,
                   rtx value, bool fallback_p)
 {
   unsigned int unit
@@ -594,7 +600,9 @@ store_bit_field_1 (rtx str_rtx, unsigned
 
          if (!store_bit_field_1 (op0, MIN (BITS_PER_WORD,
                                            bitsize - i * BITS_PER_WORD),
-                                 bitnum + bit_offset, word_mode,
+                                 bitnum + bit_offset,
+                                 maxbits,
+                                 word_mode,
                                  value_word, fallback_p))
            {
              delete_insns_since (last);
@@ -773,9 +781,10 @@ store_bit_field_1 (rtx str_rtx, unsigned
         mode. Otherwise, use the smallest mode containing the field.  */
 
       if (GET_MODE (op0) == BLKmode
+         || (maxbits && GET_MODE_BITSIZE (GET_MODE (op0)) > maxbits)
          || (op_mode != MAX_MACHINE_MODE
              && GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (op_mode)))
-       bestmode = get_best_mode (bitsize, bitnum, MEM_ALIGN (op0),
+       bestmode = get_best_mode (bitsize, bitnum, maxbits, MEM_ALIGN (op0),
                                  (op_mode == MAX_MACHINE_MODE
                                   ? VOIDmode : op_mode),
                                  MEM_VOLATILE_P (op0));
@@ -803,7 +812,7 @@ store_bit_field_1 (rtx str_rtx, unsigned
          /* Fetch that unit, store the bitfield in it, then store
             the unit.  */
          tempreg = copy_to_reg (xop0);
-         if (store_bit_field_1 (tempreg, bitsize, xbitpos,
+         if (store_bit_field_1 (tempreg, bitsize, xbitpos, maxbits,
                                 fieldmode, orig_value, false))
            {
              emit_move_insn (xop0, tempreg);
@@ -816,21 +825,28 @@ store_bit_field_1 (rtx str_rtx, unsigned
   if (!fallback_p)
     return false;
 
-  store_fixed_bit_field (op0, offset, bitsize, bitpos, value);
+  store_fixed_bit_field (op0, offset, bitsize, bitpos, maxbits, value);
   return true;
 }
 
 /* Generate code to store value from rtx VALUE
    into a bit-field within structure STR_RTX
    containing BITSIZE bits starting at bit BITNUM.
+
+   MAXBITS is the maximum number of bits we are allowed to store into,
+   0 if no limit.
+
    FIELDMODE is the machine-mode of the FIELD_DECL node for this field.  */
 
 void
 store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
-                unsigned HOST_WIDE_INT bitnum, enum machine_mode fieldmode,
+                unsigned HOST_WIDE_INT bitnum,
+                unsigned HOST_WIDE_INT maxbits,
+                enum machine_mode fieldmode,
                 rtx value)
 {
-  if (!store_bit_field_1 (str_rtx, bitsize, bitnum, fieldmode, value, true))
+  if (!store_bit_field_1 (str_rtx, bitsize, bitnum, maxbits,
+                         fieldmode, value, true))
     gcc_unreachable ();
 }
 
@@ -846,7 +862,9 @@ store_bit_field (rtx str_rtx, unsigned H
 static void
 store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset,
                       unsigned HOST_WIDE_INT bitsize,
-                      unsigned HOST_WIDE_INT bitpos, rtx value)
+                      unsigned HOST_WIDE_INT bitpos,
+                      unsigned HOST_WIDE_INT maxbits,
+                      rtx value)
 {
   enum machine_mode mode;
   unsigned int total_bits = BITS_PER_WORD;
@@ -867,7 +885,7 @@ store_fixed_bit_field (rtx op0, unsigned
       /* Special treatment for a bit field split across two registers.  */
       if (bitsize + bitpos > BITS_PER_WORD)
        {
-         store_split_bit_field (op0, bitsize, bitpos, value);
+         store_split_bit_field (op0, bitsize, bitpos, maxbits, value);
          return;
        }
     }
@@ -885,10 +903,12 @@ store_fixed_bit_field (rtx op0, unsigned
 
       if (MEM_VOLATILE_P (op0)
           && GET_MODE_BITSIZE (GET_MODE (op0)) > 0
+         && GET_MODE_BITSIZE (GET_MODE (op0)) <= maxbits
          && flag_strict_volatile_bitfields > 0)
        mode = GET_MODE (op0);
       else
        mode = get_best_mode (bitsize, bitpos + offset * BITS_PER_UNIT,
+                             maxbits,
                              MEM_ALIGN (op0), mode, MEM_VOLATILE_P (op0));
 
       if (mode == VOIDmode)
@@ -896,7 +916,7 @@ store_fixed_bit_field (rtx op0, unsigned
          /* The only way this should occur is if the field spans word
             boundaries.  */
          store_split_bit_field (op0, bitsize, bitpos + offset * BITS_PER_UNIT,
-                                value);
+                                maxbits, value);
          return;
        }
 
@@ -1016,7 +1036,9 @@ store_fixed_bit_field (rtx op0, unsigned
 
 static void
 store_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
-                      unsigned HOST_WIDE_INT bitpos, rtx value)
+                      unsigned HOST_WIDE_INT bitpos,
+                      unsigned HOST_WIDE_INT maxbits,
+                      rtx value)
 {
   unsigned int unit;
   unsigned int bitsdone = 0;
@@ -1121,7 +1143,7 @@ store_split_bit_field (rtx op0, unsigned
       /* OFFSET is in UNITs, and UNIT is in bits.
          store_fixed_bit_field wants offset in bytes.  */
       store_fixed_bit_field (word, offset * unit / BITS_PER_UNIT, thissize,
-                            thispos, part);
+                            thispos, maxbits, part);
       bitsdone += thissize;
     }
 }
@@ -1608,7 +1630,7 @@ extract_bit_field_1 (rtx str_rtx, unsign
       if (GET_MODE (op0) == BLKmode
          || (ext_mode != MAX_MACHINE_MODE
              && GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (ext_mode)))
-       bestmode = get_best_mode (bitsize, bitnum, MEM_ALIGN (op0),
+       bestmode = get_best_mode (bitsize, bitnum, 0, MEM_ALIGN (op0),
                                  (ext_mode == MAX_MACHINE_MODE
                                   ? VOIDmode : ext_mode),
                                  MEM_VOLATILE_P (op0));
@@ -1734,7 +1756,7 @@ extract_fixed_bit_field (enum machine_mo
            mode = tmode;
        }
       else
-       mode = get_best_mode (bitsize, bitpos + offset * BITS_PER_UNIT,
+       mode = get_best_mode (bitsize, bitpos + offset * BITS_PER_UNIT, 0,
                              MEM_ALIGN (op0), word_mode, MEM_VOLATILE_P (op0));
 
       if (mode == VOIDmode)
Index: Makefile.in
===================================================================
--- Makefile.in (revision 170745)
+++ Makefile.in (working copy)
@@ -2890,7 +2890,7 @@ expr.o : expr.c $(CONFIG_H) $(SYSTEM_H) 
    typeclass.h hard-reg-set.h toplev.h $(DIAGNOSTIC_CORE_H) hard-reg-set.h 
$(EXCEPT_H) \
    reload.h langhooks.h intl.h $(TM_P_H) $(TARGET_H) \
    tree-iterator.h gt-expr.h $(MACHMODE_H) $(TIMEVAR_H) $(TREE_FLOW_H) \
-   $(TREE_PASS_H) $(DF_H) $(DIAGNOSTIC_H) vecprim.h $(SSAEXPAND_H)
+   $(TREE_PASS_H) $(DF_H) $(DIAGNOSTIC_H) vecprim.h $(SSAEXPAND_H) $(PARAMS_H)
 dojump.o : dojump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) 
$(TREE_H) \
    $(FLAGS_H) $(FUNCTION_H) $(EXPR_H) $(OPTABS_H) $(INSN_ATTR_H) insn-config.h 
\
    langhooks.h $(GGC_H) gt-dojump.h vecprim.h $(BASIC_BLOCK_H) output.h
Index: stmt.c
===================================================================
--- stmt.c      (revision 170745)
+++ stmt.c      (working copy)
@@ -1758,7 +1758,7 @@ expand_return (tree retval)
 
          /* Use bitpos for the source extraction (left justified) and
             xbitpos for the destination store (right justified).  */
-         store_bit_field (dst, bitsize, xbitpos % BITS_PER_WORD, word_mode,
+         store_bit_field (dst, bitsize, xbitpos % BITS_PER_WORD, 0, word_mode,
                           extract_bit_field (src, bitsize,
                                              bitpos % BITS_PER_WORD, 1, false,
                                              NULL_RTX, word_mode, word_mode));

Reply via email to