OSDN Git Service

* gcc.target/i386/sse-22a.c: New test.
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index e225d24..f170596 100644 (file)
@@ -55,6 +55,7 @@ along with GCC; see the file COPYING3.  If not see
 #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.
@@ -143,7 +144,9 @@ static void store_constructor_field (rtx, unsigned HOST_WIDE_INT,
                                     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, 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);
@@ -336,8 +339,8 @@ convert_move (rtx to, rtx from, int unsignedp)
      TO here.  */
 
   if (GET_CODE (from) == SUBREG && SUBREG_PROMOTED_VAR_P (from)
-      && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (from)))
-         >= GET_MODE_SIZE (to_mode))
+      && (GET_MODE_PRECISION (GET_MODE (SUBREG_REG (from)))
+         >= GET_MODE_PRECISION (to_mode))
       && SUBREG_PROMOTED_UNSIGNED_P (from) == unsignedp)
     from = gen_lowpart (to_mode, from), from_mode = to_mode;
 
@@ -478,8 +481,8 @@ convert_move (rtx to, rtx from, int unsignedp)
   /* Now both modes are integers.  */
 
   /* Handle expanding beyond a word.  */
-  if (GET_MODE_BITSIZE (from_mode) < GET_MODE_BITSIZE (to_mode)
-      && GET_MODE_BITSIZE (to_mode) > BITS_PER_WORD)
+  if (GET_MODE_PRECISION (from_mode) < GET_MODE_PRECISION (to_mode)
+      && GET_MODE_PRECISION (to_mode) > BITS_PER_WORD)
     {
       rtx insns;
       rtx lowpart;
@@ -503,7 +506,7 @@ convert_move (rtx to, rtx from, int unsignedp)
          return;
        }
       /* Next, try converting via full word.  */
-      else if (GET_MODE_BITSIZE (from_mode) < BITS_PER_WORD
+      else if (GET_MODE_PRECISION (from_mode) < BITS_PER_WORD
               && ((code = can_extend_p (to_mode, word_mode, unsignedp))
                   != CODE_FOR_nothing))
        {
@@ -529,7 +532,7 @@ convert_move (rtx to, rtx from, int unsignedp)
        from = force_reg (from_mode, from);
 
       /* Get a copy of FROM widened to a word, if necessary.  */
-      if (GET_MODE_BITSIZE (from_mode) < BITS_PER_WORD)
+      if (GET_MODE_PRECISION (from_mode) < BITS_PER_WORD)
        lowpart_mode = word_mode;
       else
        lowpart_mode = from_mode;
@@ -567,8 +570,8 @@ convert_move (rtx to, rtx from, int unsignedp)
     }
 
   /* Truncating multi-word to a word or less.  */
-  if (GET_MODE_BITSIZE (from_mode) > BITS_PER_WORD
-      && GET_MODE_BITSIZE (to_mode) <= BITS_PER_WORD)
+  if (GET_MODE_PRECISION (from_mode) > BITS_PER_WORD
+      && GET_MODE_PRECISION (to_mode) <= BITS_PER_WORD)
     {
       if (!((MEM_P (from)
             && ! MEM_VOLATILE_P (from)
@@ -586,8 +589,7 @@ convert_move (rtx to, rtx from, int unsignedp)
 
   /* For truncation, usually we can just refer to FROM in a narrower mode.  */
   if (GET_MODE_BITSIZE (to_mode) < GET_MODE_BITSIZE (from_mode)
-      && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (to_mode),
-                               GET_MODE_BITSIZE (from_mode)))
+      && TRULY_NOOP_TRUNCATION_MODES_P (to_mode, from_mode))
     {
       if (!((MEM_P (from)
             && ! MEM_VOLATILE_P (from)
@@ -604,7 +606,7 @@ convert_move (rtx to, rtx from, int unsignedp)
     }
 
   /* Handle extension.  */
-  if (GET_MODE_BITSIZE (to_mode) > GET_MODE_BITSIZE (from_mode))
+  if (GET_MODE_PRECISION (to_mode) > GET_MODE_PRECISION (from_mode))
     {
       /* Convert directly if that works.  */
       if ((code = can_extend_p (to_mode, from_mode, unsignedp))
@@ -625,8 +627,7 @@ convert_move (rtx to, rtx from, int unsignedp)
            if (((can_extend_p (to_mode, intermediate, unsignedp)
                  != CODE_FOR_nothing)
                 || (GET_MODE_SIZE (to_mode) < GET_MODE_SIZE (intermediate)
-                    && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (to_mode),
-                                              GET_MODE_BITSIZE (intermediate))))
+                    && TRULY_NOOP_TRUNCATION_MODES_P (to_mode, intermediate)))
                && (can_extend_p (intermediate, from_mode, unsignedp)
                    != CODE_FOR_nothing))
              {
@@ -637,8 +638,8 @@ convert_move (rtx to, rtx from, int unsignedp)
 
          /* No suitable intermediate mode.
             Generate what we need with shifts.  */
-         shift_amount = (GET_MODE_BITSIZE (to_mode)
-                         - GET_MODE_BITSIZE (from_mode));
+         shift_amount = (GET_MODE_PRECISION (to_mode)
+                         - GET_MODE_PRECISION (from_mode));
          from = gen_lowpart (to_mode, force_reg (from_mode, from));
          tmp = expand_shift (LSHIFT_EXPR, to_mode, from, shift_amount,
                              to, unsignedp);
@@ -666,7 +667,7 @@ convert_move (rtx to, rtx from, int unsignedp)
      ??? Code above formerly short-circuited this, for most integer
      mode pairs, with a force_reg in from_mode followed by a recursive
      call to this routine.  Appears always to have been wrong.  */
-  if (GET_MODE_BITSIZE (to_mode) < GET_MODE_BITSIZE (from_mode))
+  if (GET_MODE_PRECISION (to_mode) < GET_MODE_PRECISION (from_mode))
     {
       rtx temp = force_reg (to_mode, gen_lowpart (to_mode, from));
       emit_move_insn (to, temp);
@@ -744,24 +745,24 @@ convert_modes (enum machine_mode mode, enum machine_mode oldmode, rtx x, int uns
      wider than HOST_BITS_PER_WIDE_INT, we must be narrowing the operand.  */
 
   if ((CONST_INT_P (x)
-       && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+       && GET_MODE_PRECISION (mode) <= HOST_BITS_PER_WIDE_INT)
       || (GET_MODE_CLASS (mode) == MODE_INT
          && GET_MODE_CLASS (oldmode) == MODE_INT
          && (GET_CODE (x) == CONST_DOUBLE
-             || (GET_MODE_SIZE (mode) <= GET_MODE_SIZE (oldmode)
+             || (GET_MODE_PRECISION (mode) <= GET_MODE_PRECISION (oldmode)
                  && ((MEM_P (x) && ! MEM_VOLATILE_P (x)
                       && direct_load[(int) mode])
                      || (REG_P (x)
                          && (! HARD_REGISTER_P (x)
                              || HARD_REGNO_MODE_OK (REGNO (x), mode))
-                         && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
-                                                   GET_MODE_BITSIZE (GET_MODE (x)))))))))
+                         && TRULY_NOOP_TRUNCATION_MODES_P (mode,
+                                                           GET_MODE (x))))))))
     {
       /* ?? If we don't know OLDMODE, we have to assume here that
         X does not need sign- or zero-extension.   This may not be
         the case, but it's the best we can do.  */
       if (CONST_INT_P (x) && oldmode != VOIDmode
-         && GET_MODE_SIZE (mode) > GET_MODE_SIZE (oldmode))
+         && GET_MODE_PRECISION (mode) > GET_MODE_PRECISION (oldmode))
        {
          HOST_WIDE_INT val = INTVAL (x);
 
@@ -1168,8 +1169,8 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method,
     {
       x = shallow_copy_rtx (x);
       y = shallow_copy_rtx (y);
-      set_mem_size (x, size);
-      set_mem_size (y, size);
+      set_mem_size (x, INTVAL (size));
+      set_mem_size (y, INTVAL (size));
     }
 
   if (CONST_INT_P (size) && MOVE_BY_PIECES_P (INTVAL (size), align))
@@ -2076,7 +2077,7 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
        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, 0, mode, tmps[i]);
     }
 
   /* Copy from the pseudo into the (probable) hard reg.  */
@@ -2170,7 +2171,7 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
 
       /* 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, 0, copy_mode,
                       extract_bit_field (src, bitsize,
                                          xbitpos % BITS_PER_WORD, 1, false,
                                          NULL_RTX, copy_mode, copy_mode));
@@ -2807,7 +2808,7 @@ write_complex_part (rtx cplx, rtx val, bool imag_p)
        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, 0, imode, val);
 }
 
 /* Extract one of the components of the complex value CPLX.  Extract the
@@ -3513,12 +3514,175 @@ push_block (rtx size, int extra, int below)
   return memory_address (GET_CLASS_NARROWEST_MODE (MODE_INT), temp);
 }
 
-#ifdef PUSH_ROUNDING
+/* A utility routine that returns the base of an auto-inc memory, or NULL.  */
+
+static rtx
+mem_autoinc_base (rtx mem)
+{
+  if (MEM_P (mem))
+    {
+      rtx addr = XEXP (mem, 0);
+      if (GET_RTX_CLASS (GET_CODE (addr)) == RTX_AUTOINC)
+       return XEXP (addr, 0);
+    }
+  return NULL;
+}
+
+/* A utility routine used here, in reload, and in try_split.  The insns
+   after PREV up to and including LAST are known to adjust the stack,
+   with a final value of END_ARGS_SIZE.  Iterate backward from LAST
+   placing notes as appropriate.  PREV may be NULL, indicating the
+   entire insn sequence prior to LAST should be scanned.
+
+   The set of allowed stack pointer modifications is small:
+     (1) One or more auto-inc style memory references (aka pushes),
+     (2) One or more addition/subtraction with the SP as destination,
+     (3) A single move insn with the SP as destination,
+     (4) A call_pop insn.
+
+   Insns in the sequence that do not modify the SP are ignored.
+
+   The return value is the amount of adjustment that can be trivially
+   verified, via immediate operand or auto-inc.  If the adjustment
+   cannot be trivially extracted, the return value is INT_MIN.  */
+
+int
+fixup_args_size_notes (rtx prev, rtx last, int end_args_size)
+{
+  int args_size = end_args_size;
+  bool saw_unknown = false;
+  rtx insn;
+
+  for (insn = last; insn != prev; insn = PREV_INSN (insn))
+    {
+      rtx dest, set, pat;
+      HOST_WIDE_INT this_delta = 0;
+      int i;
 
+      if (!NONDEBUG_INSN_P (insn))
+       continue;
+      pat = PATTERN (insn);
+      set = NULL;
+
+      /* Look for a call_pop pattern.  */
+      if (CALL_P (insn))
+       {
+         /* We're not supposed to see non-pop call patterns here.  */
+         gcc_assert (GET_CODE (pat) == PARALLEL);
+
+         /* All call_pop have a stack pointer adjust in the parallel.
+            The call itself is always first, and the stack adjust is
+            usually last, so search from the end.  */
+         for (i = XVECLEN (pat, 0) - 1; i > 0; --i)
+           {
+             set = XVECEXP (pat, 0, i);
+             if (GET_CODE (set) != SET)
+               continue;
+             dest = SET_DEST (set);
+             if (dest == stack_pointer_rtx)
+               break;
+           }
+         /* We'd better have found the stack pointer adjust.  */
+         gcc_assert (i > 0);
+         /* Fall through to process the extracted SET and DEST
+            as if it was a standalone insn.  */
+       }
+      else if (GET_CODE (pat) == SET)
+       set = pat;
+      else if ((set = single_set (insn)) != NULL)
+       ;
+      else if (GET_CODE (pat) == PARALLEL)
+       {
+         /* ??? Some older ports use a parallel with a stack adjust
+            and a store for a PUSH_ROUNDING pattern, rather than a
+            PRE/POST_MODIFY rtx.  Don't force them to update yet...  */
+         /* ??? See h8300 and m68k, pushqi1.  */
+         for (i = XVECLEN (pat, 0) - 1; i >= 0; --i)
+           {
+             set = XVECEXP (pat, 0, i);
+             if (GET_CODE (set) != SET)
+               continue;
+             dest = SET_DEST (set);
+             if (dest == stack_pointer_rtx)
+               break;
+
+             /* We do not expect an auto-inc of the sp in the parallel.  */
+             gcc_checking_assert (mem_autoinc_base (dest)
+                                  != stack_pointer_rtx);
+             gcc_checking_assert (mem_autoinc_base (SET_SRC (set))
+                                  != stack_pointer_rtx);
+           }
+         if (i < 0)
+           continue;
+       }
+      else
+       continue;
+      dest = SET_DEST (set);
+
+      /* Look for direct modifications of the stack pointer.  */
+      if (REG_P (dest) && REGNO (dest) == STACK_POINTER_REGNUM)
+       {
+         gcc_assert (!saw_unknown);
+         /* Look for a trivial adjustment, otherwise assume nothing.  */
+         /* Note that the SPU restore_stack_block pattern refers to
+            the stack pointer in V4SImode.  Consider that non-trivial.  */
+         if (SCALAR_INT_MODE_P (GET_MODE (dest))
+             && GET_CODE (SET_SRC (set)) == PLUS
+             && XEXP (SET_SRC (set), 0) == stack_pointer_rtx
+             && CONST_INT_P (XEXP (SET_SRC (set), 1)))
+           this_delta = INTVAL (XEXP (SET_SRC (set), 1));
+         /* ??? Reload can generate no-op moves, which will be cleaned
+            up later.  Recognize it and continue searching.  */
+         else if (rtx_equal_p (dest, SET_SRC (set)))
+           this_delta = 0;
+         else
+           saw_unknown = true;
+       }
+      /* Otherwise only think about autoinc patterns.  */
+      else if (mem_autoinc_base (dest) == stack_pointer_rtx)
+       {
+         rtx addr = XEXP (dest, 0);
+         gcc_assert (!saw_unknown);
+         switch (GET_CODE (addr))
+           {
+           case PRE_INC:
+           case POST_INC:
+             this_delta = GET_MODE_SIZE (GET_MODE (dest));
+             break;
+           case PRE_DEC:
+           case POST_DEC:
+             this_delta = -GET_MODE_SIZE (GET_MODE (dest));
+             break;
+           case PRE_MODIFY:
+           case POST_MODIFY:
+             addr = XEXP (addr, 1);
+             gcc_assert (GET_CODE (addr) == PLUS);
+             gcc_assert (XEXP (addr, 0) == stack_pointer_rtx);
+             gcc_assert (CONST_INT_P (XEXP (addr, 1)));
+             this_delta = INTVAL (XEXP (addr, 1));
+             break;
+           default:
+             gcc_unreachable ();
+           }
+       }
+      else
+       continue;
+
+      add_reg_note (insn, REG_ARGS_SIZE, GEN_INT (args_size));
+#ifdef STACK_GROWS_DOWNWARD
+      this_delta = -this_delta;
+#endif
+      args_size -= this_delta;
+    }
+
+  return saw_unknown ? INT_MIN : args_size;
+}
+
+#ifdef PUSH_ROUNDING
 /* Emit single push insn.  */
 
 static void
-emit_single_push_insn (enum machine_mode mode, rtx x, tree type)
+emit_single_push_insn_1 (enum machine_mode mode, rtx x, tree type)
 {
   rtx dest_addr;
   unsigned rounded_size = PUSH_ROUNDING (GET_MODE_SIZE (mode));
@@ -3602,6 +3766,30 @@ emit_single_push_insn (enum machine_mode mode, rtx x, tree type)
     }
   emit_move_insn (dest, x);
 }
+
+/* Emit and annotate a single push insn.  */
+
+static void
+emit_single_push_insn (enum machine_mode mode, rtx x, tree type)
+{
+  int delta, old_delta = stack_pointer_delta;
+  rtx prev = get_last_insn ();
+  rtx last;
+
+  emit_single_push_insn_1 (mode, x, type);
+
+  last = get_last_insn ();
+
+  /* Notice the common case where we emitted exactly one insn.  */
+  if (PREV_INSN (last) == prev)
+    {
+      add_reg_note (last, REG_ARGS_SIZE, GEN_INT (stack_pointer_delta));
+      return;
+    }
+
+  delta = fixup_args_size_notes (prev, last, stack_pointer_delta);
+  gcc_assert (delta == INT_MIN || delta == old_delta);
+}
 #endif
 
 /* Generate code to push X onto the stack, assuming it has mode MODE and
@@ -3942,6 +4130,8 @@ get_subtarget (rtx x)
 static bool
 optimize_bitfield_assignment_op (unsigned HOST_WIDE_INT bitsize,
                                 unsigned HOST_WIDE_INT bitpos,
+                                unsigned HOST_WIDE_INT bitregion_start,
+                                unsigned HOST_WIDE_INT bitregion_end,
                                 enum machine_mode mode1, rtx str_rtx,
                                 tree to, tree src)
 {
@@ -4003,6 +4193,7 @@ optimize_bitfield_assignment_op (unsigned HOST_WIDE_INT bitsize,
       if (str_bitsize == 0 || str_bitsize > BITS_PER_WORD)
        str_mode = word_mode;
       str_mode = get_best_mode (bitsize, bitpos,
+                               bitregion_start, bitregion_end,
                                MEM_ALIGN (str_rtx), str_mode, 0);
       if (str_mode == VOIDmode)
        return false;
@@ -4111,6 +4302,116 @@ optimize_bitfield_assignment_op (unsigned HOST_WIDE_INT bitsize,
   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 bit range of
+   consecutive bits in which this COMPONENT_REF belongs in.  The
+   values are returned in *BITSTART and *BITEND.  If either the C++
+   memory model is not activated, or this memory access is not thread
+   visible, 0 is returned in *BITSTART and *BITEND.
+
+   EXP is the COMPONENT_REF.
+   INNERDECL is the actual object being referenced.
+   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, a
+   range of 0..7 (because no one cares if we store into the
+   padding).  */
+
+static void
+get_bit_range (unsigned HOST_WIDE_INT *bitstart,
+              unsigned HOST_WIDE_INT *bitend,
+              tree exp, tree innerdecl,
+              HOST_WIDE_INT bitpos, HOST_WIDE_INT bitsize)
+{
+  tree field, record_type, fld;
+  bool found_field = false;
+  bool prev_field_is_bitfield;
+
+  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
+      || ((TREE_CODE (innerdecl) == MEM_REF
+          || TREE_CODE (innerdecl) == TARGET_MEM_REF)
+         && !ptr_deref_may_alias_global_p (TREE_OPERAND (innerdecl, 0)))
+      || (DECL_P (innerdecl)
+         && (DECL_THREAD_LOCAL_P (innerdecl)
+             || !TREE_STATIC (innerdecl))))
+    {
+      *bitstart = *bitend = 0;
+      return;
+    }
+
+  /* Bit field we're storing into.  */
+  field = TREE_OPERAND (exp, 1);
+  record_type = DECL_FIELD_CONTEXT (field);
+
+  /* Count the contiguous bitfields for the memory location that
+     contains FIELD.  */
+  *bitstart = 0;
+  prev_field_is_bitfield = true;
+  for (fld = TYPE_FIELDS (record_type); 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);
+
+      if (field == fld)
+       found_field = true;
+
+      if (DECL_BIT_FIELD_TYPE (fld) && bitsize > 0)
+       {
+         if (prev_field_is_bitfield == false)
+           {
+             *bitstart = bitpos;
+             prev_field_is_bitfield = true;
+           }
+       }
+      else
+       {
+         prev_field_is_bitfield = false;
+         if (found_field)
+           break;
+       }
+    }
+  gcc_assert (found_field);
+
+  if (fld)
+    {
+      /* We found the end of the bit field sequence.  Include the
+        padding up to the next field and be done.  */
+      *bitend = bitpos - 1;
+    }
+  else
+    {
+      /* If this is the last element in the structure, include the padding
+        at the end of structure.  */
+      *bitend = TREE_INT_CST_LOW (TYPE_SIZE (record_type)) - 1;
+    }
+}
 
 /* Expand an assignment that stores the value of FROM into TO.  If NONTEMPORAL
    is true, try generating a nontemporal store.  */
@@ -4210,6 +4511,8 @@ expand_assignment (tree to, tree from, bool nontemporal)
     {
       enum machine_mode mode1;
       HOST_WIDE_INT bitsize, bitpos;
+      unsigned HOST_WIDE_INT bitregion_start = 0;
+      unsigned HOST_WIDE_INT bitregion_end = 0;
       tree offset;
       int unsignedp;
       int volatilep = 0;
@@ -4219,6 +4522,11 @@ expand_assignment (tree to, tree from, bool nontemporal)
       tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1,
                                 &unsignedp, &volatilep, true);
 
+      if (TREE_CODE (to) == COMPONENT_REF
+         && DECL_BIT_FIELD_TYPE (TREE_OPERAND (to, 1)))
+       get_bit_range (&bitregion_start, &bitregion_end,
+                      to, tem, 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.  */
 
@@ -4281,7 +4589,7 @@ expand_assignment (tree to, tree from, bool nontemporal)
       if (!MEM_P (to_rtx)
          && GET_MODE (to_rtx) != BLKmode
          && (unsigned HOST_WIDE_INT) bitpos
-            >= GET_MODE_BITSIZE (GET_MODE (to_rtx)))
+            >= GET_MODE_PRECISION (GET_MODE (to_rtx)))
        {
          expand_normal (from);
          result = NULL;
@@ -4300,11 +4608,14 @@ expand_assignment (tree to, tree from, bool nontemporal)
                                 nontemporal);
          else if (bitpos + bitsize <= mode_bitsize / 2)
            result = store_field (XEXP (to_rtx, 0), bitsize, bitpos,
+                                 bitregion_start, bitregion_end,
                                  mode1, from, TREE_TYPE (tem),
                                  get_alias_set (to), nontemporal);
          else if (bitpos >= mode_bitsize / 2)
            result = store_field (XEXP (to_rtx, 1), bitsize,
-                                 bitpos - mode_bitsize / 2, mode1, from,
+                                 bitpos - mode_bitsize / 2,
+                                 bitregion_start, bitregion_end,
+                                 mode1, from,
                                  TREE_TYPE (tem), get_alias_set (to),
                                  nontemporal);
          else if (bitpos == 0 && bitsize == mode_bitsize)
@@ -4325,7 +4636,9 @@ expand_assignment (tree to, tree from, bool nontemporal)
                                            0);
              write_complex_part (temp, XEXP (to_rtx, 0), false);
              write_complex_part (temp, XEXP (to_rtx, 1), true);
-             result = store_field (temp, bitsize, bitpos, mode1, from,
+             result = store_field (temp, bitsize, bitpos,
+                                   bitregion_start, bitregion_end,
+                                   mode1, from,
                                    TREE_TYPE (tem), get_alias_set (to),
                                    nontemporal);
              emit_move_insn (XEXP (to_rtx, 0), read_complex_part (temp, false));
@@ -4350,11 +4663,15 @@ expand_assignment (tree to, tree from, bool nontemporal)
                MEM_KEEP_ALIAS_SET_P (to_rtx) = 1;
            }
 
-         if (optimize_bitfield_assignment_op (bitsize, bitpos, mode1,
+         if (optimize_bitfield_assignment_op (bitsize, bitpos,
+                                              bitregion_start, bitregion_end,
+                                              mode1,
                                               to_rtx, to, from))
            result = NULL;
          else
-           result = store_field (to_rtx, bitsize, bitpos, mode1, from,
+           result = store_field (to_rtx, bitsize, bitpos,
+                                 bitregion_start, bitregion_end,
+                                 mode1, from,
                                  TREE_TYPE (tem), get_alias_set (to),
                                  nontemporal);
        }
@@ -4747,7 +5064,7 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
                              : 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, 0, GET_MODE (temp), temp);
          else
            convert_move (target, temp, unsignedp);
        }
@@ -4848,16 +5165,136 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
   return NULL_RTX;
 }
 \f
+/* Return true if field F of structure TYPE is a flexible array.  */
+
+static bool
+flexible_array_member_p (const_tree f, const_tree type)
+{
+  const_tree tf;
+
+  tf = TREE_TYPE (f);
+  return (DECL_CHAIN (f) == NULL
+         && TREE_CODE (tf) == ARRAY_TYPE
+         && TYPE_DOMAIN (tf)
+         && TYPE_MIN_VALUE (TYPE_DOMAIN (tf))
+         && integer_zerop (TYPE_MIN_VALUE (TYPE_DOMAIN (tf)))
+         && !TYPE_MAX_VALUE (TYPE_DOMAIN (tf))
+         && int_size_in_bytes (type) >= 0);
+}
+
+/* If FOR_CTOR_P, return the number of top-level elements that a constructor
+   must have in order for it to completely initialize a value of type TYPE.
+   Return -1 if the number isn't known.
+
+   If !FOR_CTOR_P, return an estimate of the number of scalars in TYPE.  */
+
+static HOST_WIDE_INT
+count_type_elements (const_tree type, bool for_ctor_p)
+{
+  switch (TREE_CODE (type))
+    {
+    case ARRAY_TYPE:
+      {
+       tree nelts;
+
+       nelts = array_type_nelts (type);
+       if (nelts && host_integerp (nelts, 1))
+         {
+           unsigned HOST_WIDE_INT n;
+
+           n = tree_low_cst (nelts, 1) + 1;
+           if (n == 0 || for_ctor_p)
+             return n;
+           else
+             return n * count_type_elements (TREE_TYPE (type), false);
+         }
+       return for_ctor_p ? -1 : 1;
+      }
+
+    case RECORD_TYPE:
+      {
+       unsigned HOST_WIDE_INT n;
+       tree f;
+
+       n = 0;
+       for (f = TYPE_FIELDS (type); f ; f = DECL_CHAIN (f))
+         if (TREE_CODE (f) == FIELD_DECL)
+           {
+             if (!for_ctor_p)
+               n += count_type_elements (TREE_TYPE (f), false);
+             else if (!flexible_array_member_p (f, type))
+               /* Don't count flexible arrays, which are not supposed
+                  to be initialized.  */
+               n += 1;
+           }
+
+       return n;
+      }
+
+    case UNION_TYPE:
+    case QUAL_UNION_TYPE:
+      {
+       tree f;
+       HOST_WIDE_INT n, m;
+
+       gcc_assert (!for_ctor_p);
+       /* Estimate the number of scalars in each field and pick the
+          maximum.  Other estimates would do instead; the idea is simply
+          to make sure that the estimate is not sensitive to the ordering
+          of the fields.  */
+       n = 1;
+       for (f = TYPE_FIELDS (type); f ; f = DECL_CHAIN (f))
+         if (TREE_CODE (f) == FIELD_DECL)
+           {
+             m = count_type_elements (TREE_TYPE (f), false);
+             /* If the field doesn't span the whole union, add an extra
+                scalar for the rest.  */
+             if (simple_cst_equal (TYPE_SIZE (TREE_TYPE (f)),
+                                   TYPE_SIZE (type)) != 1)
+               m++;
+             if (n < m)
+               n = m;
+           }
+       return n;
+      }
+
+    case COMPLEX_TYPE:
+      return 2;
+
+    case VECTOR_TYPE:
+      return TYPE_VECTOR_SUBPARTS (type);
+
+    case INTEGER_TYPE:
+    case REAL_TYPE:
+    case FIXED_POINT_TYPE:
+    case ENUMERAL_TYPE:
+    case BOOLEAN_TYPE:
+    case POINTER_TYPE:
+    case OFFSET_TYPE:
+    case REFERENCE_TYPE:
+      return 1;
+
+    case ERROR_MARK:
+      return 0;
+
+    case VOID_TYPE:
+    case METHOD_TYPE:
+    case FUNCTION_TYPE:
+    case LANG_TYPE:
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* Helper for categorize_ctor_elements.  Identical interface.  */
 
 static bool
 categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
-                           HOST_WIDE_INT *p_elt_count,
-                           bool *p_must_clear)
+                           HOST_WIDE_INT *p_init_elts, bool *p_complete)
 {
   unsigned HOST_WIDE_INT idx;
-  HOST_WIDE_INT nz_elts, elt_count;
-  tree value, purpose;
+  HOST_WIDE_INT nz_elts, init_elts, num_fields;
+  tree value, purpose, elt_type;
 
   /* Whether CTOR is a valid constant initializer, in accordance with what
      initializer_constant_valid_p does.  If inferred from the constructor
@@ -4866,7 +5303,9 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
   bool const_p = const_from_elts_p ? true : TREE_STATIC (ctor);
 
   nz_elts = 0;
-  elt_count = 0;
+  init_elts = 0;
+  num_fields = 0;
+  elt_type = NULL_TREE;
 
   FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), idx, purpose, value)
     {
@@ -4881,6 +5320,8 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
            mult = (tree_low_cst (hi_index, 1)
                    - tree_low_cst (lo_index, 1) + 1);
        }
+      num_fields += mult;
+      elt_type = TREE_TYPE (value);
 
       switch (TREE_CODE (value))
        {
@@ -4888,11 +5329,11 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
          {
            HOST_WIDE_INT nz = 0, ic = 0;
 
-           bool const_elt_p
-             = categorize_ctor_elements_1 (value, &nz, &ic, p_must_clear);
+           bool const_elt_p = categorize_ctor_elements_1 (value, &nz, &ic,
+                                                          p_complete);
 
            nz_elts += mult * nz;
-           elt_count += mult * ic;
+           init_elts += mult * ic;
 
            if (const_from_elts_p && const_p)
              const_p = const_elt_p;
@@ -4904,12 +5345,12 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
        case FIXED_CST:
          if (!initializer_zerop (value))
            nz_elts += mult;
-         elt_count += mult;
+         init_elts += mult;
          break;
 
        case STRING_CST:
          nz_elts += mult * TREE_STRING_LENGTH (value);
-         elt_count += mult * TREE_STRING_LENGTH (value);
+         init_elts += mult * TREE_STRING_LENGTH (value);
          break;
 
        case COMPLEX_CST:
@@ -4917,7 +5358,7 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
            nz_elts += mult;
          if (!initializer_zerop (TREE_IMAGPART (value)))
            nz_elts += mult;
-         elt_count += mult;
+         init_elts += mult;
          break;
 
        case VECTOR_CST:
@@ -4927,65 +5368,31 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
              {
                if (!initializer_zerop (TREE_VALUE (v)))
                  nz_elts += mult;
-               elt_count += mult;
+               init_elts += mult;
              }
          }
          break;
 
        default:
          {
-           HOST_WIDE_INT tc = count_type_elements (TREE_TYPE (value), true);
-           if (tc < 1)
-             tc = 1;
+           HOST_WIDE_INT tc = count_type_elements (elt_type, false);
            nz_elts += mult * tc;
-           elt_count += mult * tc;
+           init_elts += mult * tc;
 
            if (const_from_elts_p && const_p)
-             const_p = initializer_constant_valid_p (value, TREE_TYPE (value))
+             const_p = initializer_constant_valid_p (value, elt_type)
                        != NULL_TREE;
          }
          break;
        }
     }
 
-  if (!*p_must_clear
-      && (TREE_CODE (TREE_TYPE (ctor)) == UNION_TYPE
-         || TREE_CODE (TREE_TYPE (ctor)) == QUAL_UNION_TYPE))
-    {
-      tree init_sub_type;
-      bool clear_this = true;
-
-      if (!VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (ctor)))
-       {
-         /* We don't expect more than one element of the union to be
-            initialized.  Not sure what we should do otherwise... */
-          gcc_assert (VEC_length (constructor_elt, CONSTRUCTOR_ELTS (ctor))
-                     == 1);
-
-          init_sub_type = TREE_TYPE (VEC_index (constructor_elt,
-                                               CONSTRUCTOR_ELTS (ctor),
-                                               0)->value);
-
-         /* ??? We could look at each element of the union, and find the
-            largest element.  Which would avoid comparing the size of the
-            initialized element against any tail padding in the union.
-            Doesn't seem worth the effort...  */
-         if (simple_cst_equal (TYPE_SIZE (TREE_TYPE (ctor)),
-                               TYPE_SIZE (init_sub_type)) == 1)
-           {
-             /* And now we have to find out if the element itself is fully
-                constructed.  E.g. for union { struct { int a, b; } s; } u
-                = { .s = { .a = 1 } }.  */
-             if (elt_count == count_type_elements (init_sub_type, false))
-               clear_this = false;
-           }
-       }
-
-      *p_must_clear = clear_this;
-    }
+  if (*p_complete && !complete_ctor_at_level_p (TREE_TYPE (ctor),
+                                               num_fields, elt_type))
+    *p_complete = false;
 
   *p_nz_elts += nz_elts;
-  *p_elt_count += elt_count;
+  *p_init_elts += init_elts;
 
   return const_p;
 }
@@ -4995,111 +5402,50 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
      and place it in *P_NZ_ELTS;
    * how many scalar fields in total are in CTOR,
      and place it in *P_ELT_COUNT.
-   * if a type is a union, and the initializer from the constructor
-     is not the largest element in the union, then set *p_must_clear.
+   * whether the constructor is complete -- in the sense that every
+     meaningful byte is explicitly given a value --
+     and place it in *P_COMPLETE.
 
    Return whether or not CTOR is a valid static constant initializer, the same
    as "initializer_constant_valid_p (CTOR, TREE_TYPE (CTOR)) != 0".  */
 
 bool
 categorize_ctor_elements (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
-                         HOST_WIDE_INT *p_elt_count,
-                         bool *p_must_clear)
+                         HOST_WIDE_INT *p_init_elts, bool *p_complete)
 {
   *p_nz_elts = 0;
-  *p_elt_count = 0;
-  *p_must_clear = false;
+  *p_init_elts = 0;
+  *p_complete = true;
 
-  return
-    categorize_ctor_elements_1 (ctor, p_nz_elts, p_elt_count, p_must_clear);
+  return categorize_ctor_elements_1 (ctor, p_nz_elts, p_init_elts, p_complete);
 }
 
-/* Count the number of scalars in TYPE.  Return -1 on overflow or
-   variable-sized.  If ALLOW_FLEXARR is true, don't count flexible
-   array member at the end of the structure.  */
+/* TYPE is initialized by a constructor with NUM_ELTS elements, the last
+   of which had type LAST_TYPE.  Each element was itself a complete
+   initializer, in the sense that every meaningful byte was explicitly
+   given a value.  Return true if the same is true for the constructor
+   as a whole.  */
 
-HOST_WIDE_INT
-count_type_elements (const_tree type, bool allow_flexarr)
+bool
+complete_ctor_at_level_p (const_tree type, HOST_WIDE_INT num_elts,
+                         const_tree last_type)
 {
-  const HOST_WIDE_INT max = ~((HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT-1));
-  switch (TREE_CODE (type))
+  if (TREE_CODE (type) == UNION_TYPE
+      || TREE_CODE (type) == QUAL_UNION_TYPE)
     {
-    case ARRAY_TYPE:
-      {
-       tree telts = array_type_nelts (type);
-       if (telts && host_integerp (telts, 1))
-         {
-           HOST_WIDE_INT n = tree_low_cst (telts, 1) + 1;
-           HOST_WIDE_INT m = count_type_elements (TREE_TYPE (type), false);
-           if (n == 0)
-             return 0;
-           else if (max / n > m)
-             return n * m;
-         }
-       return -1;
-      }
-
-    case RECORD_TYPE:
-      {
-       HOST_WIDE_INT n = 0, t;
-       tree f;
-
-       for (f = TYPE_FIELDS (type); f ; f = DECL_CHAIN (f))
-         if (TREE_CODE (f) == FIELD_DECL)
-           {
-             t = count_type_elements (TREE_TYPE (f), false);
-             if (t < 0)
-               {
-                 /* Check for structures with flexible array member.  */
-                 tree tf = TREE_TYPE (f);
-                 if (allow_flexarr
-                     && DECL_CHAIN (f) == NULL
-                     && TREE_CODE (tf) == ARRAY_TYPE
-                     && TYPE_DOMAIN (tf)
-                     && TYPE_MIN_VALUE (TYPE_DOMAIN (tf))
-                     && integer_zerop (TYPE_MIN_VALUE (TYPE_DOMAIN (tf)))
-                     && !TYPE_MAX_VALUE (TYPE_DOMAIN (tf))
-                     && int_size_in_bytes (type) >= 0)
-                   break;
-
-                 return -1;
-               }
-             n += t;
-           }
-
-       return n;
-      }
-
-    case UNION_TYPE:
-    case QUAL_UNION_TYPE:
-      return -1;
-
-    case COMPLEX_TYPE:
-      return 2;
-
-    case VECTOR_TYPE:
-      return TYPE_VECTOR_SUBPARTS (type);
-
-    case INTEGER_TYPE:
-    case REAL_TYPE:
-    case FIXED_POINT_TYPE:
-    case ENUMERAL_TYPE:
-    case BOOLEAN_TYPE:
-    case POINTER_TYPE:
-    case OFFSET_TYPE:
-    case REFERENCE_TYPE:
-      return 1;
+      if (num_elts == 0)
+       return false;
 
-    case ERROR_MARK:
-      return 0;
+      gcc_assert (num_elts == 1 && last_type);
 
-    case VOID_TYPE:
-    case METHOD_TYPE:
-    case FUNCTION_TYPE:
-    case LANG_TYPE:
-    default:
-      gcc_unreachable ();
+      /* ??? We could look at each element of the union, and find the
+        largest element.  Which would avoid comparing the size of the
+        initialized element against any tail padding in the union.
+        Doesn't seem worth the effort...  */
+      return simple_cst_equal (TYPE_SIZE (type), TYPE_SIZE (last_type)) == 1;
     }
+
+  return count_type_elements (type, true) == num_elts;
 }
 
 /* Return 1 if EXP contains mostly (3/4)  zeros.  */
@@ -5108,18 +5454,12 @@ static int
 mostly_zeros_p (const_tree exp)
 {
   if (TREE_CODE (exp) == CONSTRUCTOR)
-
     {
-      HOST_WIDE_INT nz_elts, count, elts;
-      bool must_clear;
-
-      categorize_ctor_elements (exp, &nz_elts, &count, &must_clear);
-      if (must_clear)
-       return 1;
-
-      elts = count_type_elements (TREE_TYPE (exp), false);
+      HOST_WIDE_INT nz_elts, init_elts;
+      bool complete_p;
 
-      return nz_elts < elts / 4;
+      categorize_ctor_elements (exp, &nz_elts, &init_elts, &complete_p);
+      return !complete_p || nz_elts < init_elts / 4;
     }
 
   return initializer_zerop (exp);
@@ -5131,12 +5471,11 @@ static int
 all_zeros_p (const_tree exp)
 {
   if (TREE_CODE (exp) == CONSTRUCTOR)
-
     {
-      HOST_WIDE_INT nz_elts, count;
-      bool must_clear;
+      HOST_WIDE_INT nz_elts, init_elts;
+      bool complete_p;
 
-      categorize_ctor_elements (exp, &nz_elts, &count, &must_clear);
+      categorize_ctor_elements (exp, &nz_elts, &init_elts, &complete_p);
       return nz_elts == 0;
     }
 
@@ -5190,7 +5529,8 @@ store_constructor_field (rtx target, unsigned HOST_WIDE_INT bitsize,
       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, 0, mode, exp, type, alias_set,
+                false);
 }
 
 /* Store the value of constructor EXP into the rtx TARGET.
@@ -5764,6 +6104,11 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
    BITSIZE bits, starting BITPOS bits from the start of TARGET.
    If MODE is VOIDmode, it means that we are storing into a bit-field.
 
+   BITREGION_START is bitpos of the first bitfield in this region.
+   BITREGION_END is the bitpos of the ending bitfield in this region.
+   These two fields are 0, if the C++ memory model does not apply,
+   or we are not interested in keeping track of bitfield regions.
+
    Always return const0_rtx unless we have something particular to
    return.
 
@@ -5777,6 +6122,8 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
 
 static rtx
 store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
+            unsigned HOST_WIDE_INT bitregion_start,
+            unsigned HOST_WIDE_INT bitregion_end,
             enum machine_mode mode, tree exp, tree type,
             alias_set_type alias_set, bool nontemporal)
 {
@@ -5809,8 +6156,9 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
       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,
+                  bitregion_start, bitregion_end,
+                  mode, exp, type, alias_set, nontemporal);
 
       emit_move_insn (target, object);
 
@@ -5924,7 +6272,9 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
        }
 
       /* Store the value in the bitfield.  */
-      store_bit_field (target, bitsize, bitpos, mode, temp);
+      store_bit_field (target, bitsize, bitpos,
+                      bitregion_start, bitregion_end,
+                      mode, temp);
 
       return const0_rtx;
     }
@@ -6499,9 +6849,7 @@ force_operand (rtx value, rtx target)
 #ifdef INSN_SCHEDULING
   /* On machines that have insn scheduling, we want all memory reference to be
      explicit, so we need to deal with such paradoxical SUBREGs.  */
-  if (GET_CODE (value) == SUBREG && MEM_P (SUBREG_REG (value))
-      && (GET_MODE_SIZE (GET_MODE (value))
-         > GET_MODE_SIZE (GET_MODE (SUBREG_REG (value)))))
+  if (paradoxical_subreg_p (value) && MEM_P (SUBREG_REG (value)))
     value
       = simplify_gen_subreg (GET_MODE (value),
                             force_reg (GET_MODE (SUBREG_REG (value)),
@@ -6927,7 +7275,16 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
          /* If the DECL isn't in memory, then the DECL wasn't properly
             marked TREE_ADDRESSABLE, which will be either a front-end
             or a tree optimizer bug.  */
-         gcc_assert (MEM_P (result));
+
+         if (TREE_ADDRESSABLE (exp)
+             && ! MEM_P (result)
+             && ! targetm.calls.allocate_stack_slots_for_args())
+           {
+             error ("local frame unavailable (naked function?)");
+             return result;
+           }
+         else
+           gcc_assert (MEM_P (result));
          result = XEXP (result, 0);
 
          /* ??? Is this needed anymore?  */
@@ -7336,7 +7693,7 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
                                                    (treeop0))
                                 * BITS_PER_UNIT),
                                (HOST_WIDE_INT) GET_MODE_BITSIZE (mode)),
-                          0, TYPE_MODE (valtype), treeop0,
+                          0, 0, 0, TYPE_MODE (valtype), treeop0,
                           type, 0, false);
            }
 
@@ -7480,7 +7837,7 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
          if (modifier == EXPAND_STACK_PARM)
            target = 0;
          if (TREE_CODE (treeop0) == INTEGER_CST
-             && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+             && GET_MODE_PRECISION (mode) <= HOST_BITS_PER_WIDE_INT
              && TREE_CONSTANT (treeop1))
            {
              rtx constant_part;
@@ -7502,7 +7859,7 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
            }
 
          else if (TREE_CODE (treeop1) == INTEGER_CST
-                  && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+                  && GET_MODE_PRECISION (mode) <= HOST_BITS_PER_WIDE_INT
                   && TREE_CONSTANT (treeop0))
            {
              rtx constant_part;
@@ -8019,7 +8376,15 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
                         VOIDmode, EXPAND_NORMAL);
       if (modifier == EXPAND_STACK_PARM)
        target = 0;
-      temp = expand_unop (mode, one_cmpl_optab, op0, target, 1);
+      /* In case we have to reduce the result to bitfield precision
+        expand this as XOR with a proper constant instead.  */
+      if (reduce_bit_field)
+       temp = expand_binop (mode, xor_optab, op0,
+                            immed_double_int_const
+                              (double_int_mask (TYPE_PRECISION (type)), mode),
+                            target, 1, OPTAB_LIB_WIDEN);
+      else
+       temp = expand_unop (mode, one_cmpl_optab, op0, target, 1);
       gcc_assert (temp);
       return temp;
 
@@ -8028,26 +8393,8 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
         and (a bitwise1 b) bitwise2 b (etc)
         but that is probably not worth while.  */
 
-      /* BIT_AND_EXPR is for bitwise anding.  TRUTH_AND_EXPR is for anding two
-        boolean values when we want in all cases to compute both of them.  In
-        general it is fastest to do TRUTH_AND_EXPR by computing both operands
-        as actual zero-or-1 values and then bitwise anding.  In cases where
-        there cannot be any side effects, better code would be made by
-        treating TRUTH_AND_EXPR like TRUTH_ANDIF_EXPR; but the question is
-        how to recognize those cases.  */
-
-    case TRUTH_AND_EXPR:
-      code = BIT_AND_EXPR;
     case BIT_AND_EXPR:
-      goto binop;
-
-    case TRUTH_OR_EXPR:
-      code = BIT_IOR_EXPR;
     case BIT_IOR_EXPR:
-      goto binop;
-
-    case TRUTH_XOR_EXPR:
-      code = BIT_XOR_EXPR;
     case BIT_XOR_EXPR:
       goto binop;
 
@@ -8126,18 +8473,6 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
       emit_label (op1);
       return target;
 
-    case TRUTH_NOT_EXPR:
-      if (modifier == EXPAND_STACK_PARM)
-       target = 0;
-      op0 = expand_expr (treeop0, target,
-                        VOIDmode, EXPAND_NORMAL);
-      /* The parser is careful to generate TRUTH_NOT_EXPR
-        only with operands that are always zero or one.  */
-      temp = expand_binop (mode, xor_optab, op0, const1_rtx,
-                          target, 1, OPTAB_LIB_WIDEN);
-      gcc_assert (temp);
-      return temp;
-
     case COMPLEX_EXPR:
       /* Get the rtx code of the operands.  */
       op0 = expand_normal (treeop0);
@@ -8293,6 +8628,12 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
   temp = expand_binop (mode, this_optab, op0, op1, target,
                       unsignedp, OPTAB_LIB_WIDEN);
   gcc_assert (temp);
+  /* Bitwise operations do not need bitfield reduction as we expect their
+     operands being properly truncated.  */
+  if (code == BIT_XOR_EXPR
+      || code == BIT_AND_EXPR
+      || code == BIT_IOR_EXPR)
+    return temp;
   return REDUCE_BIT_FIELD (temp);
 }
 #undef REDUCE_BIT_FIELD
@@ -8696,7 +9037,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       {
        addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (exp));
        struct mem_address addr;
-       int icode, align;
+       enum insn_code icode;
+       int align;
 
        get_address_description (exp, &addr);
        op0 = addr_for_mem_ref (&addr, as, true);
@@ -8713,18 +9055,15 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
            && ((icode = optab_handler (movmisalign_optab, mode))
                != CODE_FOR_nothing))
          {
-           rtx reg, insn;
+           struct expand_operand ops[2];
 
            /* We've already validated the memory, and we're creating a
-              new pseudo destination.  The predicates really can't fail.  */
-           reg = gen_reg_rtx (mode);
-
-           /* Nor can the insn generator.  */
-           insn = GEN_FCN (icode) (reg, temp);
-           gcc_assert (insn != NULL_RTX);
-           emit_insn (insn);
-
-           return reg;
+              new pseudo destination.  The predicates really can't fail,
+              nor can the generator.  */
+           create_output_operand (&ops[0], NULL_RTX, mode);
+           create_fixed_operand (&ops[1], temp);
+           expand_insn (icode, 2, ops);
+           return ops[0].value;
          }
        return temp;
       }
@@ -8736,7 +9075,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
        enum machine_mode address_mode;
        tree base = TREE_OPERAND (exp, 0);
        gimple def_stmt;
-       int icode, align;
+       enum insn_code icode;
+       int align;
        /* Handle expansion of non-aliased memory with non-BLKmode.  That
           might end up in a register.  */
        if (TREE_CODE (base) == ADDR_EXPR)
@@ -8810,17 +9150,15 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
            && ((icode = optab_handler (movmisalign_optab, mode))
                != CODE_FOR_nothing))
          {
-           rtx reg, insn;
+           struct expand_operand ops[2];
 
            /* We've already validated the memory, and we're creating a
-              new pseudo destination.  The predicates really can't fail.  */
-           reg = gen_reg_rtx (mode);
-
-           /* Nor can the insn generator.  */
-           insn = GEN_FCN (icode) (reg, temp);
-           emit_insn (insn);
-
-           return reg;
+              new pseudo destination.  The predicates really can't fail,
+              nor can the generator.  */
+           create_output_operand (&ops[0], NULL_RTX, mode);
+           create_fixed_operand (&ops[1], temp);
+           expand_insn (icode, 2, ops);
+           return ops[0].value;
          }
        return temp;
       }
@@ -8972,7 +9310,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                   we can't do this optimization.  */
                && (! DECL_BIT_FIELD (field)
                    || ((GET_MODE_CLASS (DECL_MODE (field)) == MODE_INT)
-                       && (GET_MODE_BITSIZE (DECL_MODE (field))
+                       && (GET_MODE_PRECISION (DECL_MODE (field))
                            <= HOST_BITS_PER_WIDE_INT))))
              {
                if (DECL_BIT_FIELD (field)
@@ -8991,7 +9329,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                      }
                    else
                      {
-                       int count = GET_MODE_BITSIZE (imode) - bitsize;
+                       int count = GET_MODE_PRECISION (imode) - bitsize;
 
                        op0 = expand_shift (LSHIFT_EXPR, imode, op0, count,
                                            target, 0);
@@ -9435,7 +9773,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       /* If neither mode is BLKmode, and both modes are the same size
         then we can use gen_lowpart.  */
       else if (mode != BLKmode && GET_MODE (op0) != BLKmode
-              && GET_MODE_SIZE (mode) == GET_MODE_SIZE (GET_MODE (op0))
+              && (GET_MODE_PRECISION (mode)
+                  == GET_MODE_PRECISION (GET_MODE (op0)))
               && !COMPLEX_MODE_P (GET_MODE (op0)))
        {
          if (GET_CODE (op0) == SUBREG)
@@ -9517,47 +9856,6 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
       return op0;
 
-      /* Use a compare and a jump for BLKmode comparisons, or for function
-        type comparisons is HAVE_canonicalize_funcptr_for_compare.  */
-
-      /* Although TRUTH_{AND,OR}IF_EXPR aren't present in GIMPLE, they
-        are occassionally created by folding during expansion.  */
-    case TRUTH_ANDIF_EXPR:
-    case TRUTH_ORIF_EXPR:
-      if (! ignore
-         && (target == 0
-             || modifier == EXPAND_STACK_PARM
-             || ! safe_from_p (target, treeop0, 1)
-             || ! safe_from_p (target, treeop1, 1)
-             /* Make sure we don't have a hard reg (such as function's return
-                value) live across basic blocks, if not optimizing.  */
-             || (!optimize && REG_P (target)
-                 && REGNO (target) < FIRST_PSEUDO_REGISTER)))
-       target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
-
-      if (target)
-       emit_move_insn (target, const0_rtx);
-
-      op1 = gen_label_rtx ();
-      jumpifnot_1 (code, treeop0, treeop1, op1, -1);
-
-      if (target)
-       emit_move_insn (target, const1_rtx);
-
-      emit_label (op1);
-      return ignore ? const0_rtx : target;
-
-    case STATEMENT_LIST:
-      {
-       tree_stmt_iterator iter;
-
-       gcc_assert (ignore);
-
-       for (iter = tsi_start (exp); !tsi_end_p (iter); tsi_next (&iter))
-         expand_expr (tsi_stmt (iter), const0_rtx, VOIDmode, modifier);
-      }
-      return const0_rtx;
-
     case COND_EXPR:
       /* A COND_EXPR with its type being VOID_TYPE represents a
         conditional jump and is handled in
@@ -9758,7 +10056,7 @@ reduce_to_bit_field_precision (rtx exp, rtx target, tree type)
     }
   else
     {
-      int count = GET_MODE_BITSIZE (GET_MODE (exp)) - prec;
+      int count = GET_MODE_PRECISION (GET_MODE (exp)) - prec;
       exp = expand_shift (LSHIFT_EXPR, GET_MODE (exp),
                          exp, count, target, 0);
       return expand_shift (RSHIFT_EXPR, GET_MODE (exp),