OSDN Git Service

PR libgcj/23508
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index bc19bc1..6cfe2d1 100644 (file)
@@ -1,6 +1,6 @@
 /* Convert tree expression to rtl instructions, for GNU compiler.
    Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -16,8 +16,8 @@ for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 #include "config.h"
 #include "system.h"
@@ -126,7 +126,7 @@ static void move_by_pieces_1 (rtx (*) (rtx, ...), enum machine_mode,
                              struct move_by_pieces *);
 static bool block_move_libcall_safe_for_call_parm (void);
 static bool emit_block_move_via_movmem (rtx, rtx, rtx, unsigned);
-static rtx emit_block_move_via_libcall (rtx, rtx, rtx);
+static rtx emit_block_move_via_libcall (rtx, rtx, rtx, bool);
 static tree emit_block_move_libcall_fn (int);
 static void emit_block_move_via_loop (rtx, rtx, rtx, unsigned);
 static rtx clear_by_pieces_1 (void *, HOST_WIDE_INT, enum machine_mode);
@@ -134,8 +134,7 @@ static void clear_by_pieces (rtx, unsigned HOST_WIDE_INT, unsigned int);
 static void store_by_pieces_1 (struct store_by_pieces *, unsigned int);
 static void store_by_pieces_2 (rtx (*) (rtx, ...), enum machine_mode,
                               struct store_by_pieces *);
-static bool clear_storage_via_clrmem (rtx, rtx, unsigned);
-static rtx clear_storage_via_libcall (rtx, rtx);
+static rtx clear_storage_via_libcall (rtx, rtx, bool);
 static tree clear_storage_libcall_fn (int);
 static rtx compress_float_constant (rtx, rtx);
 static rtx get_subtarget (rtx);
@@ -146,7 +145,6 @@ static void store_constructor (tree, rtx, int, HOST_WIDE_INT);
 static rtx store_field (rtx, HOST_WIDE_INT, HOST_WIDE_INT, enum machine_mode,
                        tree, tree, int);
 
-static unsigned HOST_WIDE_INT highest_pow2_factor (tree);
 static unsigned HOST_WIDE_INT highest_pow2_factor_for_target (tree, tree);
 
 static int is_aligning_offset (tree, tree);
@@ -159,6 +157,7 @@ static void emit_single_push_insn (enum machine_mode, rtx, tree);
 #endif
 static void do_tablejump (rtx, enum machine_mode, rtx, rtx, rtx);
 static rtx const_vector_from_tree (tree);
+static void write_complex_part (rtx, rtx, bool);
 
 /* Record for each mode whether we can move a register directly to or
    from an object of that mode in memory.  If we can't, we won't try
@@ -199,14 +198,39 @@ static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
 /* This array records the insn_code of insns to perform block moves.  */
 enum insn_code movmem_optab[NUM_MACHINE_MODES];
 
-/* This array records the insn_code of insns to perform block clears.  */
-enum insn_code clrmem_optab[NUM_MACHINE_MODES];
+/* This array records the insn_code of insns to perform block sets.  */
+enum insn_code setmem_optab[NUM_MACHINE_MODES];
 
-/* These arrays record the insn_code of two different kinds of insns
+/* These arrays record the insn_code of three different kinds of insns
    to perform block compares.  */
 enum insn_code cmpstr_optab[NUM_MACHINE_MODES];
+enum insn_code cmpstrn_optab[NUM_MACHINE_MODES];
 enum insn_code cmpmem_optab[NUM_MACHINE_MODES];
 
+/* Synchronization primitives.  */
+enum insn_code sync_add_optab[NUM_MACHINE_MODES];
+enum insn_code sync_sub_optab[NUM_MACHINE_MODES];
+enum insn_code sync_ior_optab[NUM_MACHINE_MODES];
+enum insn_code sync_and_optab[NUM_MACHINE_MODES];
+enum insn_code sync_xor_optab[NUM_MACHINE_MODES];
+enum insn_code sync_nand_optab[NUM_MACHINE_MODES];
+enum insn_code sync_old_add_optab[NUM_MACHINE_MODES];
+enum insn_code sync_old_sub_optab[NUM_MACHINE_MODES];
+enum insn_code sync_old_ior_optab[NUM_MACHINE_MODES];
+enum insn_code sync_old_and_optab[NUM_MACHINE_MODES];
+enum insn_code sync_old_xor_optab[NUM_MACHINE_MODES];
+enum insn_code sync_old_nand_optab[NUM_MACHINE_MODES];
+enum insn_code sync_new_add_optab[NUM_MACHINE_MODES];
+enum insn_code sync_new_sub_optab[NUM_MACHINE_MODES];
+enum insn_code sync_new_ior_optab[NUM_MACHINE_MODES];
+enum insn_code sync_new_and_optab[NUM_MACHINE_MODES];
+enum insn_code sync_new_xor_optab[NUM_MACHINE_MODES];
+enum insn_code sync_new_nand_optab[NUM_MACHINE_MODES];
+enum insn_code sync_compare_and_swap[NUM_MACHINE_MODES];
+enum insn_code sync_compare_and_swap_cc[NUM_MACHINE_MODES];
+enum insn_code sync_lock_test_and_set[NUM_MACHINE_MODES];
+enum insn_code sync_lock_release[NUM_MACHINE_MODES];
+
 /* SLOW_UNALIGNED_ACCESS is nonzero if unaligned accesses are very slow.  */
 
 #ifndef SLOW_UNALIGNED_ACCESS
@@ -441,19 +465,27 @@ convert_move (rtx to, rtx from, int unsignedp)
     }
   if (GET_MODE_CLASS (from_mode) == MODE_PARTIAL_INT)
     {
+      rtx new_from;
       enum machine_mode full_mode
        = smallest_mode_for_size (GET_MODE_BITSIZE (from_mode), MODE_INT);
 
       gcc_assert (sext_optab->handlers[full_mode][from_mode].insn_code
                  != CODE_FOR_nothing);
 
-      emit_unop_insn (sext_optab->handlers[full_mode][from_mode].insn_code,
-                     to, from, UNKNOWN);
       if (to_mode == full_mode)
-       return;
+       {
+         emit_unop_insn (sext_optab->handlers[full_mode][from_mode].insn_code,
+                         to, from, UNKNOWN);
+         return;
+       }
+
+      new_from = gen_reg_rtx (full_mode);
+      emit_unop_insn (sext_optab->handlers[full_mode][from_mode].insn_code,
+                     new_from, from, UNKNOWN);
 
       /* else proceed to integer conversions below.  */
       from_mode = full_mode;
+      from = new_from;
     }
 
   /* Now both modes are integers.  */
@@ -610,9 +642,6 @@ convert_move (rtx to, rtx from, int unsignedp)
       if ((code = can_extend_p (to_mode, from_mode, unsignedp))
          != CODE_FOR_nothing)
        {
-         if (flag_force_mem)
-           from = force_not_mem (from);
-
          emit_unop_insn (code, to, from, equiv_code);
          return;
        }
@@ -1123,6 +1152,7 @@ emit_block_move (rtx x, rtx y, rtx size, enum block_op_methods method)
   switch (method)
     {
     case BLOCK_OP_NORMAL:
+    case BLOCK_OP_TAILCALL:
       may_use_call = true;
       break;
 
@@ -1171,7 +1201,8 @@ emit_block_move (rtx x, rtx y, rtx size, enum block_op_methods method)
   else if (emit_block_move_via_movmem (x, y, size, align))
     ;
   else if (may_use_call)
-    retval = emit_block_move_via_libcall (x, y, size);
+    retval = emit_block_move_via_libcall (x, y, size,
+                                         method == BLOCK_OP_TAILCALL);
   else
     emit_block_move_via_loop (x, y, size, align);
 
@@ -1219,8 +1250,7 @@ block_move_libcall_safe_for_call_parm (void)
        rtx tmp = FUNCTION_ARG (args_so_far, mode, NULL_TREE, 1);
        if (!tmp || !REG_P (tmp))
          return false;
-       if (FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode,
-                                       NULL_TREE, 1))
+       if (targetm.calls.arg_partial_bytes (&args_so_far, mode, NULL, 1))
          return false;
        FUNCTION_ARG_ADVANCE (args_so_far, mode, NULL_TREE, 1);
       }
@@ -1301,7 +1331,7 @@ emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align)
    Return the return value from memcpy, 0 otherwise.  */
 
 static rtx
-emit_block_move_via_libcall (rtx dst, rtx src, rtx size)
+emit_block_move_via_libcall (rtx dst, rtx src, rtx size, bool tailcall)
 {
   rtx dst_addr, src_addr;
   tree call_expr, arg_list, fn, src_tree, dst_tree, size_tree;
@@ -1343,6 +1373,7 @@ emit_block_move_via_libcall (rtx dst, rtx src, rtx size)
   call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
   call_expr = build3 (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
                      call_expr, arg_list, NULL_TREE);
+  CALL_EXPR_TAILCALL (call_expr) = tailcall;
 
   retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
 
@@ -1557,22 +1588,23 @@ gen_group_rtx (rtx orig)
   return gen_rtx_PARALLEL (GET_MODE (orig), gen_rtvec_v (length, tmps));
 }
 
-/* Emit code to move a block ORIG_SRC of type TYPE to a block DST,
-   where DST is non-consecutive registers represented by a PARALLEL.
-   SSIZE represents the total size of block ORIG_SRC in bytes, or -1
-   if not known.  */
+/* A subroutine of emit_group_load.  Arguments as for emit_group_load,
+   except that values are placed in TMPS[i], and must later be moved
+   into corresponding XEXP (XVECEXP (DST, 0, i), 0) element.  */
 
-void
-emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
+static void
+emit_group_load_1 (rtx *tmps, rtx dst, rtx orig_src, tree type, int ssize)
 {
-  rtx *tmps, src;
+  rtx src;
   int start, i;
   enum machine_mode m = GET_MODE (orig_src);
 
   gcc_assert (GET_CODE (dst) == PARALLEL);
 
-  if (!SCALAR_INT_MODE_P (m)
-      && !MEM_P (orig_src) && GET_CODE (orig_src) != CONCAT)
+  if (m != VOIDmode
+      && !SCALAR_INT_MODE_P (m)
+      && !MEM_P (orig_src)
+      && GET_CODE (orig_src) != CONCAT)
     {
       enum machine_mode imode = int_mode_for_mode (GET_MODE (orig_src));
       if (imode == BLKmode)
@@ -1585,7 +1617,7 @@ emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
       /* ...and back again.  */
       if (imode != BLKmode)
        src = gen_lowpart (imode, src);
-      emit_group_load (dst, src, type, ssize);
+      emit_group_load_1 (tmps, dst, src, type, ssize);
       return;
     }
 
@@ -1596,8 +1628,6 @@ emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
   else
     start = 1;
 
-  tmps = alloca (sizeof (rtx) * XVECLEN (dst, 0));
-
   /* Process the pieces.  */
   for (i = start; i < XVECLEN (dst, 0); i++)
     {
@@ -1651,6 +1681,11 @@ emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
          tmps[i] = gen_reg_rtx (mode);
          emit_move_insn (tmps[i], adjust_address (src, mode, bytepos));
        }
+      else if (COMPLEX_MODE_P (mode)
+              && GET_MODE (src) == mode
+              && bytelen == GET_MODE_SIZE (mode))
+       /* Let emit_move_complex do the bulk of the work.  */
+       tmps[i] = src;
       else if (GET_CODE (src) == CONCAT)
        {
          unsigned int slen = GET_MODE_SIZE (GET_MODE (src));
@@ -1673,11 +1708,12 @@ emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
          else
            {
              rtx mem;
-             
+
              gcc_assert (!bytepos);
              mem = assign_stack_temp (GET_MODE (src), slen, 0);
              emit_move_insn (mem, src);
-             tmps[i] = adjust_address (mem, mode, 0);
+             tmps[i] = extract_bit_field (mem, bytelen * BITS_PER_UNIT,
+                                          0, 1, NULL_RTX, mode, mode);
            }
        }
       /* FIXME: A SIMD parallel will eventually lead to a subreg of a
@@ -1708,10 +1744,61 @@ emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
        tmps[i] = expand_shift (LSHIFT_EXPR, mode, tmps[i],
                                build_int_cst (NULL_TREE, shift), tmps[i], 0);
     }
+}
+
+/* Emit code to move a block SRC of type TYPE to a block DST,
+   where DST is non-consecutive registers represented by a PARALLEL.
+   SSIZE represents the total size of block ORIG_SRC in bytes, or -1
+   if not known.  */
+
+void
+emit_group_load (rtx dst, rtx src, tree type, int ssize)
+{
+  rtx *tmps;
+  int i;
+
+  tmps = alloca (sizeof (rtx) * XVECLEN (dst, 0));
+  emit_group_load_1 (tmps, dst, src, type, ssize);
 
   /* Copy the extracted pieces into the proper (probable) hard regs.  */
-  for (i = start; i < XVECLEN (dst, 0); i++)
-    emit_move_insn (XEXP (XVECEXP (dst, 0, i), 0), tmps[i]);
+  for (i = 0; i < XVECLEN (dst, 0); i++)
+    {
+      rtx d = XEXP (XVECEXP (dst, 0, i), 0);
+      if (d == NULL)
+       continue;
+      emit_move_insn (d, tmps[i]);
+    }
+}
+
+/* Similar, but load SRC into new pseudos in a format that looks like
+   PARALLEL.  This can later be fed to emit_group_move to get things
+   in the right place.  */
+
+rtx
+emit_group_load_into_temps (rtx parallel, rtx src, tree type, int ssize)
+{
+  rtvec vec;
+  int i;
+
+  vec = rtvec_alloc (XVECLEN (parallel, 0));
+  emit_group_load_1 (&RTVEC_ELT (vec, 0), parallel, src, type, ssize);
+
+  /* Convert the vector to look just like the original PARALLEL, except
+     with the computed values.  */
+  for (i = 0; i < XVECLEN (parallel, 0); i++)
+    {
+      rtx e = XVECEXP (parallel, 0, i);
+      rtx d = XEXP (e, 0);
+
+      if (d)
+       {
+         d = force_reg (GET_MODE (d), RTVEC_ELT (vec, i));
+         e = alloc_EXPR_LIST (REG_NOTE_KIND (e), d, XEXP (e, 1));
+       }
+      RTVEC_ELT (vec, i) = e;
+    }
+
+  return gen_rtx_PARALLEL (GET_MODE (parallel), vec);
 }
 
 /* Emit code to move a block SRC to block DST, where SRC and DST are
@@ -1732,6 +1819,27 @@ emit_group_move (rtx dst, rtx src)
                    XEXP (XVECEXP (src, 0, i), 0));
 }
 
+/* Move a group of registers represented by a PARALLEL into pseudos.  */
+
+rtx
+emit_group_move_into_temps (rtx src)
+{
+  rtvec vec = rtvec_alloc (XVECLEN (src, 0));
+  int i;
+
+  for (i = 0; i < XVECLEN (src, 0); i++)
+    {
+      rtx e = XVECEXP (src, 0, i);
+      rtx d = XEXP (e, 0);
+
+      if (d)
+       e = alloc_EXPR_LIST (REG_NOTE_KIND (e), copy_to_reg (d), XEXP (e, 1));
+      RTVEC_ELT (vec, i) = e;
+    }
+
+  return gen_rtx_PARALLEL (GET_MODE (src), vec);
+}
+
 /* Emit code to move a block SRC to a block ORIG_DST of type TYPE,
    where SRC is non-consecutive registers represented by a PARALLEL.
    SSIZE represents the total size of block ORIG_DST, or -1 if not
@@ -2326,95 +2434,60 @@ store_by_pieces_2 (rtx (*genfun) (rtx, ...), enum machine_mode mode,
    its length in bytes.  */
 
 rtx
-clear_storage (rtx object, rtx size)
+clear_storage (rtx object, rtx size, enum block_op_methods method)
 {
-  rtx retval = 0;
-  unsigned int align = (MEM_P (object) ? MEM_ALIGN (object)
-                       : GET_MODE_ALIGNMENT (GET_MODE (object)));
+  enum machine_mode mode = GET_MODE (object);
+  unsigned int align;
+
+  gcc_assert (method == BLOCK_OP_NORMAL || method == BLOCK_OP_TAILCALL);
 
   /* If OBJECT is not BLKmode and SIZE is the same size as its mode,
      just move a zero.  Otherwise, do this a piece at a time.  */
-  if (GET_MODE (object) != BLKmode
+  if (mode != BLKmode
       && GET_CODE (size) == CONST_INT
-      && INTVAL (size) == (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (object)))
-    emit_move_insn (object, CONST0_RTX (GET_MODE (object)));
-  else
-    {
-      if (size == const0_rtx)
-       ;
-      else if (GET_CODE (size) == CONST_INT
-         && CLEAR_BY_PIECES_P (INTVAL (size), align))
-       clear_by_pieces (object, INTVAL (size), align);
-      else if (clear_storage_via_clrmem (object, size, align))
-       ;
-      else
-       retval = clear_storage_via_libcall (object, size);
-    }
-
-  return retval;
-}
-
-/* A subroutine of clear_storage.  Expand a clrmem pattern;
-   return true if successful.  */
-
-static bool
-clear_storage_via_clrmem (rtx object, rtx size, unsigned int align)
-{
-  /* Try the most limited insn first, because there's no point
-     including more than one in the machine description unless
-     the more limited one has some advantage.  */
-
-  rtx opalign = GEN_INT (align / BITS_PER_UNIT);
-  enum machine_mode mode;
-
-  for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
-       mode = GET_MODE_WIDER_MODE (mode))
+      && INTVAL (size) == (HOST_WIDE_INT) GET_MODE_SIZE (mode))
     {
-      enum insn_code code = clrmem_optab[(int) mode];
-      insn_operand_predicate_fn pred;
-
-      if (code != CODE_FOR_nothing
-         /* We don't need MODE to be narrower than
-            BITS_PER_HOST_WIDE_INT here because if SIZE is less than
-            the mode mask, as it is returned by the macro, it will
-            definitely be less than the actual mode mask.  */
-         && ((GET_CODE (size) == CONST_INT
-              && ((unsigned HOST_WIDE_INT) INTVAL (size)
-                  <= (GET_MODE_MASK (mode) >> 1)))
-             || GET_MODE_BITSIZE (mode) >= BITS_PER_WORD)
-         && ((pred = insn_data[(int) code].operand[0].predicate) == 0
-             || (*pred) (object, BLKmode))
-         && ((pred = insn_data[(int) code].operand[2].predicate) == 0
-             || (*pred) (opalign, VOIDmode)))
+      rtx zero = CONST0_RTX (mode);
+      if (zero != NULL)
        {
-         rtx op1;
-         rtx last = get_last_insn ();
-         rtx pat;
-
-         op1 = convert_to_mode (mode, size, 1);
-         pred = insn_data[(int) code].operand[1].predicate;
-         if (pred != 0 && ! (*pred) (op1, mode))
-           op1 = copy_to_mode_reg (mode, op1);
+         emit_move_insn (object, zero);
+         return NULL;
+       }
 
-         pat = GEN_FCN ((int) code) (object, op1, opalign);
-         if (pat)
+      if (COMPLEX_MODE_P (mode))
+       {
+         zero = CONST0_RTX (GET_MODE_INNER (mode));
+         if (zero != NULL)
            {
-             emit_insn (pat);
-             return true;
+             write_complex_part (object, zero, 0);
+             write_complex_part (object, zero, 1);
+             return NULL;
            }
-         else
-           delete_insns_since (last);
        }
     }
 
-  return false;
+  if (size == const0_rtx)
+    return NULL;
+
+  align = MEM_ALIGN (object);
+
+  if (GET_CODE (size) == CONST_INT
+      && CLEAR_BY_PIECES_P (INTVAL (size), align))
+    clear_by_pieces (object, INTVAL (size), align);
+  else if (set_storage_via_setmem (object, size, const0_rtx, align))
+    ;
+  else
+    return clear_storage_via_libcall (object, size,
+                                     method == BLOCK_OP_TAILCALL);
+
+  return NULL;
 }
 
 /* A subroutine of clear_storage.  Expand a call to memset.
    Return the return value of memset, 0 otherwise.  */
 
 static rtx
-clear_storage_via_libcall (rtx object, rtx size)
+clear_storage_via_libcall (rtx object, rtx size, bool tailcall)
 {
   tree call_expr, arg_list, fn, object_tree, size_tree;
   enum machine_mode size_mode;
@@ -2447,6 +2520,7 @@ clear_storage_via_libcall (rtx object, rtx size)
   call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
   call_expr = build3 (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
                      call_expr, arg_list, NULL_TREE);
+  CALL_EXPR_TAILCALL (call_expr) = tailcall;
 
   retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
 
@@ -2502,417 +2576,621 @@ clear_storage_libcall_fn (int for_call)
   return block_clear_fn;
 }
 \f
-/* Generate code to copy Y into X.
-   Both Y and X must have the same mode, except that
-   Y can be a constant with VOIDmode.
-   This mode cannot be BLKmode; use emit_block_move for that.
+/* Expand a setmem pattern; return true if successful.  */
 
-   Return the last instruction emitted.  */
-
-rtx
-emit_move_insn (rtx x, rtx y)
+bool
+set_storage_via_setmem (rtx object, rtx size, rtx val, unsigned int align)
 {
-  enum machine_mode mode = GET_MODE (x);
-  rtx y_cst = NULL_RTX;
-  rtx last_insn, set;
+  /* Try the most limited insn first, because there's no point
+     including more than one in the machine description unless
+     the more limited one has some advantage.  */
 
-  gcc_assert (mode != BLKmode
-             && (GET_MODE (y) == mode || GET_MODE (y) == VOIDmode));
+  rtx opalign = GEN_INT (align / BITS_PER_UNIT);
+  enum machine_mode mode;
 
-  if (CONSTANT_P (y))
+  for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
+       mode = GET_MODE_WIDER_MODE (mode))
     {
-      if (optimize
-         && SCALAR_FLOAT_MODE_P (GET_MODE (x))
-         && (last_insn = compress_float_constant (x, y)))
-       return last_insn;
-
-      y_cst = y;
+      enum insn_code code = setmem_optab[(int) mode];
+      insn_operand_predicate_fn pred;
 
-      if (!LEGITIMATE_CONSTANT_P (y))
+      if (code != CODE_FOR_nothing
+         /* We don't need MODE to be narrower than
+            BITS_PER_HOST_WIDE_INT here because if SIZE is less than
+            the mode mask, as it is returned by the macro, it will
+            definitely be less than the actual mode mask.  */
+         && ((GET_CODE (size) == CONST_INT
+              && ((unsigned HOST_WIDE_INT) INTVAL (size)
+                  <= (GET_MODE_MASK (mode) >> 1)))
+             || GET_MODE_BITSIZE (mode) >= BITS_PER_WORD)
+         && ((pred = insn_data[(int) code].operand[0].predicate) == 0
+             || (*pred) (object, BLKmode))
+         && ((pred = insn_data[(int) code].operand[3].predicate) == 0
+             || (*pred) (opalign, VOIDmode)))
        {
-         y = force_const_mem (mode, y);
+         rtx opsize, opchar;
+         enum machine_mode char_mode;
+         rtx last = get_last_insn ();
+         rtx pat;
 
-         /* If the target's cannot_force_const_mem prevented the spill,
-            assume that the target's move expanders will also take care
-            of the non-legitimate constant.  */
-         if (!y)
-           y = y_cst;
+         opsize = convert_to_mode (mode, size, 1);
+         pred = insn_data[(int) code].operand[1].predicate;
+         if (pred != 0 && ! (*pred) (opsize, mode))
+           opsize = copy_to_mode_reg (mode, opsize);
+         
+         opchar = val;
+         char_mode = insn_data[(int) code].operand[2].mode;
+         if (char_mode != VOIDmode)
+           {
+             opchar = convert_to_mode (char_mode, opchar, 1);
+             pred = insn_data[(int) code].operand[2].predicate;
+             if (pred != 0 && ! (*pred) (opchar, char_mode))
+               opchar = copy_to_mode_reg (char_mode, opchar);
+           }
+
+         pat = GEN_FCN ((int) code) (object, opsize, opchar, opalign);
+         if (pat)
+           {
+             emit_insn (pat);
+             return true;
+           }
+         else
+           delete_insns_since (last);
        }
     }
 
-  /* If X or Y are memory references, verify that their addresses are valid
-     for the machine.  */
-  if (MEM_P (x)
-      && ((! memory_address_p (GET_MODE (x), XEXP (x, 0))
-          && ! push_operand (x, GET_MODE (x)))
-         || (flag_force_addr
-             && CONSTANT_ADDRESS_P (XEXP (x, 0)))))
-    x = validize_mem (x);
+  return false;
+}
 
-  if (MEM_P (y)
-      && (! memory_address_p (GET_MODE (y), XEXP (y, 0))
-         || (flag_force_addr
-             && CONSTANT_ADDRESS_P (XEXP (y, 0)))))
-    y = validize_mem (y);
+\f
+/* Write to one of the components of the complex value CPLX.  Write VAL to
+   the real part if IMAG_P is false, and the imaginary part if its true.  */
 
-  gcc_assert (mode != BLKmode);
+static void
+write_complex_part (rtx cplx, rtx val, bool imag_p)
+{
+  enum machine_mode cmode;
+  enum machine_mode imode;
+  unsigned ibitsize;
 
-  last_insn = emit_move_insn_1 (x, y);
+  if (GET_CODE (cplx) == CONCAT)
+    {
+      emit_move_insn (XEXP (cplx, imag_p), val);
+      return;
+    }
 
-  if (y_cst && REG_P (x)
-      && (set = single_set (last_insn)) != NULL_RTX
-      && SET_DEST (set) == x
-      && ! rtx_equal_p (y_cst, SET_SRC (set)))
-    set_unique_reg_note (last_insn, REG_EQUAL, y_cst);
+  cmode = GET_MODE (cplx);
+  imode = GET_MODE_INNER (cmode);
+  ibitsize = GET_MODE_BITSIZE (imode);
 
-  return last_insn;
+  /* For MEMs simplify_gen_subreg may generate an invalid new address
+     because, e.g., the original address is considered mode-dependent
+     by the target, which restricts simplify_subreg from invoking
+     adjust_address_nv.  Instead of preparing fallback support for an
+     invalid address, we call adjust_address_nv directly.  */
+  if (MEM_P (cplx))
+    {
+      emit_move_insn (adjust_address_nv (cplx, imode,
+                                        imag_p ? GET_MODE_SIZE (imode) : 0),
+                     val);
+      return;
+    }
+
+  /* If the sub-object is at least word sized, then we know that subregging
+     will work.  This special case is important, since store_bit_field
+     wants to operate on integer modes, and there's rarely an OImode to
+     correspond to TCmode.  */
+  if (ibitsize >= BITS_PER_WORD
+      /* For hard regs we have exact predicates.  Assume we can split
+        the original object if it spans an even number of hard regs.
+        This special case is important for SCmode on 64-bit platforms
+        where the natural size of floating-point regs is 32-bit.  */
+      || (REG_P (cplx)
+         && REGNO (cplx) < FIRST_PSEUDO_REGISTER
+         && hard_regno_nregs[REGNO (cplx)][cmode] % 2 == 0))
+    {
+      rtx part = simplify_gen_subreg (imode, cplx, cmode,
+                                     imag_p ? GET_MODE_SIZE (imode) : 0);
+      if (part)
+        {
+         emit_move_insn (part, val);
+         return;
+       }
+      else
+       /* simplify_gen_subreg may fail for sub-word MEMs.  */
+       gcc_assert (MEM_P (cplx) && ibitsize < BITS_PER_WORD);
+    }
+
+  store_bit_field (cplx, ibitsize, imag_p ? ibitsize : 0, imode, val);
 }
 
-/* Low level part of emit_move_insn.
-   Called just like emit_move_insn, but assumes X and Y
-   are basically valid.  */
+/* Extract one of the components of the complex value CPLX.  Extract the
+   real part if IMAG_P is false, and the imaginary part if it's true.  */
 
-rtx
-emit_move_insn_1 (rtx x, rtx y)
+static rtx
+read_complex_part (rtx cplx, bool imag_p)
 {
-  enum machine_mode mode = GET_MODE (x);
-  enum machine_mode submode;
-  enum mode_class class = GET_MODE_CLASS (mode);
+  enum machine_mode cmode, imode;
+  unsigned ibitsize;
 
-  gcc_assert ((unsigned int) mode < (unsigned int) MAX_MACHINE_MODE);
+  if (GET_CODE (cplx) == CONCAT)
+    return XEXP (cplx, imag_p);
 
-  if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
-    return
-      emit_insn (GEN_FCN (mov_optab->handlers[(int) mode].insn_code) (x, y));
+  cmode = GET_MODE (cplx);
+  imode = GET_MODE_INNER (cmode);
+  ibitsize = GET_MODE_BITSIZE (imode);
 
-  /* Expand complex moves by moving real part and imag part, if possible.  */
-  else if ((class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT)
-          && BLKmode != (submode = GET_MODE_INNER (mode))
-          && (mov_optab->handlers[(int) submode].insn_code
-              != CODE_FOR_nothing))
+  /* Special case reads from complex constants that got spilled to memory.  */
+  if (MEM_P (cplx) && GET_CODE (XEXP (cplx, 0)) == SYMBOL_REF)
     {
-      /* Don't split destination if it is a stack push.  */
-      int stack = push_operand (x, GET_MODE (x));
-
-#ifdef PUSH_ROUNDING
-      /* In case we output to the stack, but the size is smaller than the
-        machine can push exactly, we need to use move instructions.  */
-      if (stack
-         && (PUSH_ROUNDING (GET_MODE_SIZE (submode))
-             != GET_MODE_SIZE (submode)))
+      tree decl = SYMBOL_REF_DECL (XEXP (cplx, 0));
+      if (decl && TREE_CODE (decl) == COMPLEX_CST)
        {
-         rtx temp;
-         HOST_WIDE_INT offset1, offset2;
+         tree part = imag_p ? TREE_IMAGPART (decl) : TREE_REALPART (decl);
+         if (CONSTANT_CLASS_P (part))
+           return expand_expr (part, NULL_RTX, imode, EXPAND_NORMAL);
+       }
+    }
 
-         /* Do not use anti_adjust_stack, since we don't want to update
-            stack_pointer_delta.  */
-         temp = expand_binop (Pmode,
-#ifdef STACK_GROWS_DOWNWARD
-                              sub_optab,
-#else
-                              add_optab,
-#endif
-                              stack_pointer_rtx,
-                              GEN_INT
-                                (PUSH_ROUNDING
-                                 (GET_MODE_SIZE (GET_MODE (x)))),
-                              stack_pointer_rtx, 0, OPTAB_LIB_WIDEN);
+  /* For MEMs simplify_gen_subreg may generate an invalid new address
+     because, e.g., the original address is considered mode-dependent
+     by the target, which restricts simplify_subreg from invoking
+     adjust_address_nv.  Instead of preparing fallback support for an
+     invalid address, we call adjust_address_nv directly.  */
+  if (MEM_P (cplx))
+    return adjust_address_nv (cplx, imode,
+                             imag_p ? GET_MODE_SIZE (imode) : 0);
+
+  /* If the sub-object is at least word sized, then we know that subregging
+     will work.  This special case is important, since extract_bit_field
+     wants to operate on integer modes, and there's rarely an OImode to
+     correspond to TCmode.  */
+  if (ibitsize >= BITS_PER_WORD
+      /* For hard regs we have exact predicates.  Assume we can split
+        the original object if it spans an even number of hard regs.
+        This special case is important for SCmode on 64-bit platforms
+        where the natural size of floating-point regs is 32-bit.  */
+      || (REG_P (cplx)
+         && REGNO (cplx) < FIRST_PSEUDO_REGISTER
+         && hard_regno_nregs[REGNO (cplx)][cmode] % 2 == 0))
+    {
+      rtx ret = simplify_gen_subreg (imode, cplx, cmode,
+                                    imag_p ? GET_MODE_SIZE (imode) : 0);
+      if (ret)
+        return ret;
+      else
+       /* simplify_gen_subreg may fail for sub-word MEMs.  */
+       gcc_assert (MEM_P (cplx) && ibitsize < BITS_PER_WORD);
+    }
 
-         if (temp != stack_pointer_rtx)
-           emit_move_insn (stack_pointer_rtx, temp);
+  return extract_bit_field (cplx, ibitsize, imag_p ? ibitsize : 0,
+                           true, NULL_RTX, imode, imode);
+}
+\f
+/* A subroutine of emit_move_insn_1.  Yet another lowpart generator.
+   NEW_MODE and OLD_MODE are the same size.  Return NULL if X cannot be
+   represented in NEW_MODE.  If FORCE is true, this will never happen, as
+   we'll force-create a SUBREG if needed.  */
 
-#ifdef STACK_GROWS_DOWNWARD
-         offset1 = 0;
-         offset2 = GET_MODE_SIZE (submode);
-#else
-         offset1 = -PUSH_ROUNDING (GET_MODE_SIZE (GET_MODE (x)));
-         offset2 = (-PUSH_ROUNDING (GET_MODE_SIZE (GET_MODE (x)))
-                    + GET_MODE_SIZE (submode));
-#endif
+static rtx
+emit_move_change_mode (enum machine_mode new_mode,
+                      enum machine_mode old_mode, rtx x, bool force)
+{
+  rtx ret;
 
-         emit_move_insn (change_address (x, submode,
-                                         gen_rtx_PLUS (Pmode,
-                                                       stack_pointer_rtx,
-                                                       GEN_INT (offset1))),
-                         gen_realpart (submode, y));
-         emit_move_insn (change_address (x, submode,
-                                         gen_rtx_PLUS (Pmode,
-                                                       stack_pointer_rtx,
-                                                       GEN_INT (offset2))),
-                         gen_imagpart (submode, y));
-       }
-      else
-#endif
-      /* If this is a stack, push the highpart first, so it
-        will be in the argument order.
+  if (reload_in_progress && MEM_P (x))
+    {
+      /* We can't use gen_lowpart here because it may call change_address
+        which is not appropriate if we were called when a reload was in
+        progress.  We don't have to worry about changing the address since
+        the size in bytes is supposed to be the same.  Copy the MEM to
+        change the mode and move any substitutions from the old MEM to
+        the new one.  */
 
-        In that case, change_address is used only to convert
-        the mode, not to change the address.  */
-      if (stack)
-       {
-         /* Note that the real part always precedes the imag part in memory
-            regardless of machine's endianness.  */
-#ifdef STACK_GROWS_DOWNWARD
-         emit_move_insn (gen_rtx_MEM (submode, XEXP (x, 0)),
-                         gen_imagpart (submode, y));
-         emit_move_insn (gen_rtx_MEM (submode, XEXP (x, 0)),
-                         gen_realpart (submode, y));
-#else
-         emit_move_insn (gen_rtx_MEM (submode, XEXP (x, 0)),
-                         gen_realpart (submode, y));
-         emit_move_insn (gen_rtx_MEM (submode, XEXP (x, 0)),
-                         gen_imagpart (submode, y));
-#endif
-       }
+      ret = adjust_address_nv (x, new_mode, 0);
+      copy_replacements (x, ret);
+    }
+  else
+    {
+      /* Note that we do want simplify_subreg's behavior of validating
+        that the new mode is ok for a hard register.  If we were to use
+        simplify_gen_subreg, we would create the subreg, but would
+        probably run into the target not being able to implement it.  */
+      /* Except, of course, when FORCE is true, when this is exactly what
+        we want.  Which is needed for CCmodes on some targets.  */
+      if (force)
+       ret = simplify_gen_subreg (new_mode, x, old_mode, 0);
       else
-       {
-         rtx realpart_x, realpart_y;
-         rtx imagpart_x, imagpart_y;
-
-         /* If this is a complex value with each part being smaller than a
-            word, the usual calling sequence will likely pack the pieces into
-            a single register.  Unfortunately, SUBREG of hard registers only
-            deals in terms of words, so we have a problem converting input
-            arguments to the CONCAT of two registers that is used elsewhere
-            for complex values.  If this is before reload, we can copy it into
-            memory and reload.  FIXME, we should see about using extract and
-            insert on integer registers, but complex short and complex char
-            variables should be rarely used.  */
-         if (GET_MODE_BITSIZE (mode) < 2 * BITS_PER_WORD
-             && (reload_in_progress | reload_completed) == 0)
-           {
-             int packed_dest_p
-               = (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER);
-             int packed_src_p
-               = (REG_P (y) && REGNO (y) < FIRST_PSEUDO_REGISTER);
+       ret = simplify_subreg (new_mode, x, old_mode, 0);
+    }
 
-             if (packed_dest_p || packed_src_p)
-               {
-                 enum mode_class reg_class = ((class == MODE_COMPLEX_FLOAT)
-                                              ? MODE_FLOAT : MODE_INT);
+  return ret;
+}
 
-                 enum machine_mode reg_mode
-                   = mode_for_size (GET_MODE_BITSIZE (mode), reg_class, 1);
+/* A subroutine of emit_move_insn_1.  Generate a move from Y into X using
+   an integer mode of the same size as MODE.  Returns the instruction
+   emitted, or NULL if such a move could not be generated.  */
 
-                 if (reg_mode != BLKmode)
-                   {
-                     rtx mem = assign_stack_temp (reg_mode,
-                                                  GET_MODE_SIZE (mode), 0);
-                     rtx cmem = adjust_address (mem, mode, 0);
+static rtx
+emit_move_via_integer (enum machine_mode mode, rtx x, rtx y)
+{
+  enum machine_mode imode;
+  enum insn_code code;
 
-                     if (packed_dest_p)
-                       {
-                         rtx sreg = gen_rtx_SUBREG (reg_mode, x, 0);
+  /* There must exist a mode of the exact size we require.  */
+  imode = int_mode_for_mode (mode);
+  if (imode == BLKmode)
+    return NULL_RTX;
+
+  /* The target must support moves in this mode.  */
+  code = mov_optab->handlers[imode].insn_code;
+  if (code == CODE_FOR_nothing)
+    return NULL_RTX;
+
+  x = emit_move_change_mode (imode, mode, x, false);
+  if (x == NULL_RTX)
+    return NULL_RTX;
+  y = emit_move_change_mode (imode, mode, y, false);
+  if (y == NULL_RTX)
+    return NULL_RTX;
+  return emit_insn (GEN_FCN (code) (x, y));
+}
 
-                         emit_move_insn_1 (cmem, y);
-                         return emit_move_insn_1 (sreg, mem);
-                       }
-                     else
-                       {
-                         rtx sreg = gen_rtx_SUBREG (reg_mode, y, 0);
+/* A subroutine of emit_move_insn_1.  X is a push_operand in MODE.
+   Return an equivalent MEM that does not use an auto-increment.  */
 
-                         emit_move_insn_1 (mem, sreg);
-                         return emit_move_insn_1 (x, cmem);
-                       }
-                   }
-               }
-           }
+static rtx
+emit_move_resolve_push (enum machine_mode mode, rtx x)
+{
+  enum rtx_code code = GET_CODE (XEXP (x, 0));
+  HOST_WIDE_INT adjust;
+  rtx temp;
 
-         realpart_x = gen_realpart (submode, x);
-         realpart_y = gen_realpart (submode, y);
-         imagpart_x = gen_imagpart (submode, x);
-         imagpart_y = gen_imagpart (submode, y);
-
-         /* Show the output dies here.  This is necessary for SUBREGs
-            of pseudos since we cannot track their lifetimes correctly;
-            hard regs shouldn't appear here except as return values.
-            We never want to emit such a clobber after reload.  */
-         if (x != y
-             && ! (reload_in_progress || reload_completed)
-             && (GET_CODE (realpart_x) == SUBREG
-                 || GET_CODE (imagpart_x) == SUBREG))
-           emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
-
-         emit_move_insn (realpart_x, realpart_y);
-         emit_move_insn (imagpart_x, imagpart_y);
-       }
+  adjust = GET_MODE_SIZE (mode);
+#ifdef PUSH_ROUNDING
+  adjust = PUSH_ROUNDING (adjust);
+#endif
+  if (code == PRE_DEC || code == POST_DEC)
+    adjust = -adjust;
+
+  /* Do not use anti_adjust_stack, since we don't want to update
+     stack_pointer_delta.  */
+  temp = expand_simple_binop (Pmode, PLUS, stack_pointer_rtx,
+                             GEN_INT (adjust), stack_pointer_rtx,
+                             0, OPTAB_LIB_WIDEN);
+  if (temp != stack_pointer_rtx)
+    emit_move_insn (stack_pointer_rtx, temp);
+
+  switch (code)
+    {
+    case PRE_INC:
+    case PRE_DEC:
+      temp = stack_pointer_rtx;
+      break;
+    case POST_INC:
+      temp = plus_constant (stack_pointer_rtx, -GET_MODE_SIZE (mode));
+      break;
+    case POST_DEC:
+      temp = plus_constant (stack_pointer_rtx, GET_MODE_SIZE (mode));
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  return replace_equiv_address (x, temp);
+}
+
+/* A subroutine of emit_move_complex.  Generate a move from Y into X.
+   X is known to satisfy push_operand, and MODE is known to be complex.
+   Returns the last instruction emitted.  */
+
+static rtx
+emit_move_complex_push (enum machine_mode mode, rtx x, rtx y)
+{
+  enum machine_mode submode = GET_MODE_INNER (mode);
+  bool imag_first;
+
+#ifdef PUSH_ROUNDING
+  unsigned int submodesize = GET_MODE_SIZE (submode);
 
-      return get_last_insn ();
+  /* In case we output to the stack, but the size is smaller than the
+     machine can push exactly, we need to use move instructions.  */
+  if (PUSH_ROUNDING (submodesize) != submodesize)
+    {
+      x = emit_move_resolve_push (mode, x);
+      return emit_move_insn (x, y);
     }
+#endif
 
-  /* Handle MODE_CC modes:  If we don't have a special move insn for this mode,
-     find a mode to do it in.  If we have a movcc, use it.  Otherwise,
-     find the MODE_INT mode of the same width.  */
-  else if (GET_MODE_CLASS (mode) == MODE_CC
-          && mov_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing)
+  /* Note that the real part always precedes the imag part in memory
+     regardless of machine's endianness.  */
+  switch (GET_CODE (XEXP (x, 0)))
     {
-      enum insn_code insn_code;
-      enum machine_mode tmode = VOIDmode;
-      rtx x1 = x, y1 = y;
+    case PRE_DEC:
+    case POST_DEC:
+      imag_first = true;
+      break;
+    case PRE_INC:
+    case POST_INC:
+      imag_first = false;
+      break;
+    default:
+      gcc_unreachable ();
+    }
 
-      if (mode != CCmode
-         && mov_optab->handlers[(int) CCmode].insn_code != CODE_FOR_nothing)
-       tmode = CCmode;
-      else
-       for (tmode = QImode; tmode != VOIDmode;
-            tmode = GET_MODE_WIDER_MODE (tmode))
-         if (GET_MODE_SIZE (tmode) == GET_MODE_SIZE (mode))
-           break;
+  emit_move_insn (gen_rtx_MEM (submode, XEXP (x, 0)),
+                 read_complex_part (y, imag_first));
+  return emit_move_insn (gen_rtx_MEM (submode, XEXP (x, 0)),
+                        read_complex_part (y, !imag_first));
+}
+
+/* A subroutine of emit_move_insn_1.  Generate a move from Y into X.
+   MODE is known to be complex.  Returns the last instruction emitted.  */
 
-      gcc_assert (tmode != VOIDmode);
+static rtx
+emit_move_complex (enum machine_mode mode, rtx x, rtx y)
+{
+  bool try_int;
+
+  /* Need to take special care for pushes, to maintain proper ordering
+     of the data, and possibly extra padding.  */
+  if (push_operand (x, mode))
+    return emit_move_complex_push (mode, x, y);
+
+  /* See if we can coerce the target into moving both values at once.  */
+
+  /* Move floating point as parts.  */
+  if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
+      && mov_optab->handlers[GET_MODE_INNER (mode)].insn_code != CODE_FOR_nothing)
+    try_int = false;
+  /* Not possible if the values are inherently not adjacent.  */
+  else if (GET_CODE (x) == CONCAT || GET_CODE (y) == CONCAT)
+    try_int = false;
+  /* Is possible if both are registers (or subregs of registers).  */
+  else if (register_operand (x, mode) && register_operand (y, mode))
+    try_int = true;
+  /* If one of the operands is a memory, and alignment constraints
+     are friendly enough, we may be able to do combined memory operations.
+     We do not attempt this if Y is a constant because that combination is
+     usually better with the by-parts thing below.  */
+  else if ((MEM_P (x) ? !CONSTANT_P (y) : MEM_P (y))
+          && (!STRICT_ALIGNMENT
+              || get_mode_alignment (mode) == BIGGEST_ALIGNMENT))
+    try_int = true;
+  else
+    try_int = false;
 
-      /* Get X and Y in TMODE.  We can't use gen_lowpart here because it
-        may call change_address which is not appropriate if we were
-        called when a reload was in progress.  We don't have to worry
-        about changing the address since the size in bytes is supposed to
-        be the same.  Copy the MEM to change the mode and move any
-        substitutions from the old MEM to the new one.  */
+  if (try_int)
+    {
+      rtx ret;
 
-      if (reload_in_progress)
+      /* For memory to memory moves, optimal behavior can be had with the
+        existing block move logic.  */
+      if (MEM_P (x) && MEM_P (y))
        {
-         x = gen_lowpart_common (tmode, x1);
-         if (x == 0 && MEM_P (x1))
-           {
-             x = adjust_address_nv (x1, tmode, 0);
-             copy_replacements (x1, x);
-           }
+         emit_block_move (x, y, GEN_INT (GET_MODE_SIZE (mode)),
+                          BLOCK_OP_NO_LIBCALL);
+         return get_last_insn ();
+       }
 
-         y = gen_lowpart_common (tmode, y1);
-         if (y == 0 && MEM_P (y1))
-           {
-             y = adjust_address_nv (y1, tmode, 0);
-             copy_replacements (y1, y);
-           }
+      ret = emit_move_via_integer (mode, x, y);
+      if (ret)
+       return ret;
+    }
+
+  /* Show the output dies here.  This is necessary for SUBREGs
+     of pseudos since we cannot track their lifetimes correctly;
+     hard regs shouldn't appear here except as return values.  */
+  if (!reload_completed && !reload_in_progress
+      && REG_P (x) && !reg_overlap_mentioned_p (x, y))
+    emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
+
+  write_complex_part (x, read_complex_part (y, false), false);
+  write_complex_part (x, read_complex_part (y, true), true);
+  return get_last_insn ();
+}
+
+/* A subroutine of emit_move_insn_1.  Generate a move from Y into X.
+   MODE is known to be MODE_CC.  Returns the last instruction emitted.  */
+
+static rtx
+emit_move_ccmode (enum machine_mode mode, rtx x, rtx y)
+{
+  rtx ret;
+
+  /* Assume all MODE_CC modes are equivalent; if we have movcc, use it.  */
+  if (mode != CCmode)
+    {
+      enum insn_code code = mov_optab->handlers[CCmode].insn_code;
+      if (code != CODE_FOR_nothing)
+       {
+         x = emit_move_change_mode (CCmode, mode, x, true);
+         y = emit_move_change_mode (CCmode, mode, y, true);
+         return emit_insn (GEN_FCN (code) (x, y));
        }
-      else
+    }
+
+  /* Otherwise, find the MODE_INT mode of the same width.  */
+  ret = emit_move_via_integer (mode, x, y);
+  gcc_assert (ret != NULL);
+  return ret;
+}
+
+/* A subroutine of emit_move_insn_1.  Generate a move from Y into X.
+   MODE is any multi-word or full-word mode that lacks a move_insn
+   pattern.  Note that you will get better code if you define such
+   patterns, even if they must turn into multiple assembler instructions.  */
+
+static rtx
+emit_move_multi_word (enum machine_mode mode, rtx x, rtx y)
+{
+  rtx last_insn = 0;
+  rtx seq, inner;
+  bool need_clobber;
+  int i;
+      
+  gcc_assert (GET_MODE_SIZE (mode) >= UNITS_PER_WORD);
+      
+  /* If X is a push on the stack, do the push now and replace
+     X with a reference to the stack pointer.  */
+  if (push_operand (x, mode))
+    x = emit_move_resolve_push (mode, x);
+
+  /* If we are in reload, see if either operand is a MEM whose address
+     is scheduled for replacement.  */
+  if (reload_in_progress && MEM_P (x)
+      && (inner = find_replacement (&XEXP (x, 0))) != XEXP (x, 0))
+    x = replace_equiv_address_nv (x, inner);
+  if (reload_in_progress && MEM_P (y)
+      && (inner = find_replacement (&XEXP (y, 0))) != XEXP (y, 0))
+    y = replace_equiv_address_nv (y, inner);
+
+  start_sequence ();
+
+  need_clobber = false;
+  for (i = 0;
+       i < (GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD;
+       i++)
+    {
+      rtx xpart = operand_subword (x, i, 1, mode);
+      rtx ypart = operand_subword (y, i, 1, mode);
+
+      /* If we can't get a part of Y, put Y into memory if it is a
+        constant.  Otherwise, force it into a register.  Then we must
+        be able to get a part of Y.  */
+      if (ypart == 0 && CONSTANT_P (y))
        {
-         x = gen_lowpart (tmode, x);
-         y = gen_lowpart (tmode, y);
+         y = force_const_mem (mode, y);
+         ypart = operand_subword (y, i, 1, mode);
        }
+      else if (ypart == 0)
+       ypart = operand_subword_force (y, i, mode);
 
-      insn_code = mov_optab->handlers[(int) tmode].insn_code;
-      return emit_insn (GEN_FCN (insn_code) (x, y));
+      gcc_assert (xpart && ypart);
+
+      need_clobber |= (GET_CODE (xpart) == SUBREG);
+
+      last_insn = emit_move_insn (xpart, ypart);
     }
 
+  seq = get_insns ();
+  end_sequence ();
+
+  /* Show the output dies here.  This is necessary for SUBREGs
+     of pseudos since we cannot track their lifetimes correctly;
+     hard regs shouldn't appear here except as return values.
+     We never want to emit such a clobber after reload.  */
+  if (x != y
+      && ! (reload_in_progress || reload_completed)
+      && need_clobber != 0)
+    emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
+
+  emit_insn (seq);
+
+  return last_insn;
+}
+
+/* Low level part of emit_move_insn.
+   Called just like emit_move_insn, but assumes X and Y
+   are basically valid.  */
+
+rtx
+emit_move_insn_1 (rtx x, rtx y)
+{
+  enum machine_mode mode = GET_MODE (x);
+  enum insn_code code;
+
+  gcc_assert ((unsigned int) mode < (unsigned int) MAX_MACHINE_MODE);
+
+  code = mov_optab->handlers[mode].insn_code;
+  if (code != CODE_FOR_nothing)
+    return emit_insn (GEN_FCN (code) (x, y));
+
+  /* Expand complex moves by moving real part and imag part.  */
+  if (COMPLEX_MODE_P (mode))
+    return emit_move_complex (mode, x, y);
+
+  if (GET_MODE_CLASS (mode) == MODE_CC)
+    return emit_move_ccmode (mode, x, y);
+
   /* Try using a move pattern for the corresponding integer mode.  This is
      only safe when simplify_subreg can convert MODE constants into integer
      constants.  At present, it can only do this reliably if the value
      fits within a HOST_WIDE_INT.  */
-  else if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
-          && (submode = int_mode_for_mode (mode)) != BLKmode
-          && mov_optab->handlers[submode].insn_code != CODE_FOR_nothing)
-    return emit_insn (GEN_FCN (mov_optab->handlers[submode].insn_code)
-                     (simplify_gen_subreg (submode, x, mode, 0),
-                      simplify_gen_subreg (submode, y, mode, 0)));
-
-  /* This will handle any multi-word or full-word mode that lacks a move_insn
-     pattern.  However, you will get better code if you define such patterns,
-     even if they must turn into multiple assembler instructions.  */
-  else
+  if (!CONSTANT_P (y) || GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
     {
-      rtx last_insn = 0;
-      rtx seq, inner;
-      int need_clobber;
-      int i;
-      
-      gcc_assert (GET_MODE_SIZE (mode) >= UNITS_PER_WORD);
-      
-#ifdef PUSH_ROUNDING
-
-      /* If X is a push on the stack, do the push now and replace
-        X with a reference to the stack pointer.  */
-      if (push_operand (x, GET_MODE (x)))
-       {
-         rtx temp;
-         enum rtx_code code;
+      rtx ret = emit_move_via_integer (mode, x, y);
+      if (ret)
+       return ret;
+    }
 
-         /* Do not use anti_adjust_stack, since we don't want to update
-            stack_pointer_delta.  */
-         temp = expand_binop (Pmode,
-#ifdef STACK_GROWS_DOWNWARD
-                              sub_optab,
-#else
-                              add_optab,
-#endif
-                              stack_pointer_rtx,
-                              GEN_INT
-                                (PUSH_ROUNDING
-                                 (GET_MODE_SIZE (GET_MODE (x)))),
-                              stack_pointer_rtx, 0, OPTAB_LIB_WIDEN);
-
-         if (temp != stack_pointer_rtx)
-           emit_move_insn (stack_pointer_rtx, temp);
-
-         code = GET_CODE (XEXP (x, 0));
-
-         /* Just hope that small offsets off SP are OK.  */
-         if (code == POST_INC)
-           temp = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
-                               GEN_INT (-((HOST_WIDE_INT)
-                                          GET_MODE_SIZE (GET_MODE (x)))));
-         else if (code == POST_DEC)
-           temp = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
-                               GEN_INT (GET_MODE_SIZE (GET_MODE (x))));
-         else
-           temp = stack_pointer_rtx;
+  return emit_move_multi_word (mode, x, y);
+}
 
-         x = change_address (x, VOIDmode, temp);
-       }
-#endif
+/* Generate code to copy Y into X.
+   Both Y and X must have the same mode, except that
+   Y can be a constant with VOIDmode.
+   This mode cannot be BLKmode; use emit_block_move for that.
 
-      /* If we are in reload, see if either operand is a MEM whose address
-        is scheduled for replacement.  */
-      if (reload_in_progress && MEM_P (x)
-         && (inner = find_replacement (&XEXP (x, 0))) != XEXP (x, 0))
-       x = replace_equiv_address_nv (x, inner);
-      if (reload_in_progress && MEM_P (y)
-         && (inner = find_replacement (&XEXP (y, 0))) != XEXP (y, 0))
-       y = replace_equiv_address_nv (y, inner);
+   Return the last instruction emitted.  */
 
-      start_sequence ();
+rtx
+emit_move_insn (rtx x, rtx y)
+{
+  enum machine_mode mode = GET_MODE (x);
+  rtx y_cst = NULL_RTX;
+  rtx last_insn, set;
 
-      need_clobber = 0;
-      for (i = 0;
-          i < (GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD;
-          i++)
-       {
-         rtx xpart = operand_subword (x, i, 1, mode);
-         rtx ypart = operand_subword (y, i, 1, mode);
+  gcc_assert (mode != BLKmode
+             && (GET_MODE (y) == mode || GET_MODE (y) == VOIDmode));
 
-         /* If we can't get a part of Y, put Y into memory if it is a
-            constant.  Otherwise, force it into a register.  If we still
-            can't get a part of Y, abort.  */
-         if (ypart == 0 && CONSTANT_P (y))
-           {
-             y = force_const_mem (mode, y);
-             ypart = operand_subword (y, i, 1, mode);
-           }
-         else if (ypart == 0)
-           ypart = operand_subword_force (y, i, mode);
+  if (CONSTANT_P (y))
+    {
+      if (optimize
+         && SCALAR_FLOAT_MODE_P (GET_MODE (x))
+         && (last_insn = compress_float_constant (x, y)))
+       return last_insn;
 
-         gcc_assert (xpart && ypart);
+      y_cst = y;
 
-         need_clobber |= (GET_CODE (xpart) == SUBREG);
+      if (!LEGITIMATE_CONSTANT_P (y))
+       {
+         y = force_const_mem (mode, y);
 
-         last_insn = emit_move_insn (xpart, ypart);
+         /* If the target's cannot_force_const_mem prevented the spill,
+            assume that the target's move expanders will also take care
+            of the non-legitimate constant.  */
+         if (!y)
+           y = y_cst;
        }
+    }
 
-      seq = get_insns ();
-      end_sequence ();
+  /* If X or Y are memory references, verify that their addresses are valid
+     for the machine.  */
+  if (MEM_P (x)
+      && ((! memory_address_p (GET_MODE (x), XEXP (x, 0))
+          && ! push_operand (x, GET_MODE (x)))
+         || (flag_force_addr
+             && CONSTANT_ADDRESS_P (XEXP (x, 0)))))
+    x = validize_mem (x);
 
-      /* Show the output dies here.  This is necessary for SUBREGs
-        of pseudos since we cannot track their lifetimes correctly;
-        hard regs shouldn't appear here except as return values.
-        We never want to emit such a clobber after reload.  */
-      if (x != y
-         && ! (reload_in_progress || reload_completed)
-         && need_clobber != 0)
-       emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
+  if (MEM_P (y)
+      && (! memory_address_p (GET_MODE (y), XEXP (y, 0))
+         || (flag_force_addr
+             && CONSTANT_ADDRESS_P (XEXP (y, 0)))))
+    y = validize_mem (y);
 
-      emit_insn (seq);
+  gcc_assert (mode != BLKmode);
 
-      return last_insn;
-    }
+  last_insn = emit_move_insn_1 (x, y);
+
+  if (y_cst && REG_P (x)
+      && (set = single_set (last_insn)) != NULL_RTX
+      && SET_DEST (set) == x
+      && ! rtx_equal_p (y_cst, SET_SRC (set)))
+    set_unique_reg_note (last_insn, REG_EQUAL, y_cst);
+
+  return last_insn;
 }
 
 /* If Y is representable exactly in a narrower mode, and the target can
@@ -2926,9 +3204,15 @@ compress_float_constant (rtx x, rtx y)
   enum machine_mode orig_srcmode = GET_MODE (y);
   enum machine_mode srcmode;
   REAL_VALUE_TYPE r;
+  int oldcost, newcost;
 
   REAL_VALUE_FROM_CONST_DOUBLE (r, y);
 
+  if (LEGITIMATE_CONSTANT_P (y))
+    oldcost = rtx_cost (y, SET);
+  else
+    oldcost = rtx_cost (force_const_mem (dstmode, y), SET);
+
   for (srcmode = GET_CLASS_NARROWEST_MODE (GET_MODE_CLASS (orig_srcmode));
        srcmode != orig_srcmode;
        srcmode = GET_MODE_WIDER_MODE (srcmode))
@@ -2953,12 +3237,23 @@ compress_float_constant (rtx x, rtx y)
             the extension.  */
          if (! (*insn_data[ic].operand[1].predicate) (trunc_y, srcmode))
            continue;
+         /* This is valid, but may not be cheaper than the original. */
+         newcost = rtx_cost (gen_rtx_FLOAT_EXTEND (dstmode, trunc_y), SET);
+         if (oldcost < newcost)
+           continue;
        }
       else if (float_extend_from_mem[dstmode][srcmode])
-       trunc_y = validize_mem (force_const_mem (srcmode, trunc_y));
+       {
+         trunc_y = force_const_mem (srcmode, trunc_y);
+         /* This is valid, but may not be cheaper than the original. */
+         newcost = rtx_cost (gen_rtx_FLOAT_EXTEND (dstmode, trunc_y), SET);
+         if (oldcost < newcost)
+           continue;
+         trunc_y = validize_mem (trunc_y);
+       }
       else
        continue;
-
       emit_unop_insn (ic, x, trunc_y, UNKNOWN);
       last_insn = get_last_insn ();
 
@@ -3128,9 +3423,8 @@ emit_single_push_insn (enum machine_mode mode, rtx x, tree type)
    ALIGN (in bits) is maximum alignment we can assume.
 
    If PARTIAL and REG are both nonzero, then copy that many of the first
-   words of X into registers starting with REG, and push the rest of X.
-   The amount of space pushed is decreased by PARTIAL words,
-   rounded *down* to a multiple of PARM_BOUNDARY.
+   bytes of X into registers starting with REG, and push the rest of X.
+   The amount of space pushed is decreased by PARTIAL bytes.
    REG must be a hard register in this case.
    If REG is zero but PARTIAL is not, take any all others actions for an
    argument partially in registers, but do not actually load any
@@ -3182,24 +3476,15 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
       /* Copy a block into the stack, entirely or partially.  */
 
       rtx temp;
-      int used = partial * UNITS_PER_WORD;
+      int used;
       int offset;
       int skip;
 
-      if (reg && GET_CODE (reg) == PARALLEL)
-       {
-         /* Use the size of the elt to compute offset.  */
-         rtx elt = XEXP (XVECEXP (reg, 0, 0), 0);
-         used = partial * GET_MODE_SIZE (GET_MODE (elt));
-         offset = used % (PARM_BOUNDARY / BITS_PER_UNIT);
-       }
-      else
-       offset = used % (PARM_BOUNDARY / BITS_PER_UNIT);
+      offset = partial % (PARM_BOUNDARY / BITS_PER_UNIT);
+      used = partial - offset;
 
       gcc_assert (size);
 
-      used -= offset;
-
       /* USED is now the # of bytes we need not copy to the stack
         because registers will take care of them.  */
 
@@ -3310,9 +3595,9 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
       int size = GET_MODE_SIZE (mode) / UNITS_PER_WORD;
       int i;
       int not_stack;
-      /* # words of start of argument
+      /* # bytes of start of argument
         that we must make space for but need not store.  */
-      int offset = partial % (PARM_BOUNDARY / BITS_PER_WORD);
+      int offset = partial % (PARM_BOUNDARY / BITS_PER_UNIT);
       int args_offset = INTVAL (args_so_far);
       int skip;
 
@@ -3330,8 +3615,9 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
        offset = 0;
 
       /* Now NOT_STACK gets the number of words that we don't need to
-        allocate on the stack.  */
-      not_stack = partial - offset;
+        allocate on the stack. Convert OFFSET to words too. */
+      not_stack = (partial - offset) / UNITS_PER_WORD;
+      offset /= UNITS_PER_WORD;
 
       /* If the partial register-part of the arg counts in its stack size,
         skip the part of stack space corresponding to the registers.
@@ -3415,31 +3701,187 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
       if (GET_CODE (reg) == PARALLEL)
        emit_group_load (reg, x, type, -1);
       else
-       move_block_to_reg (REGNO (reg), x, partial, mode);
+       {
+         gcc_assert (partial % UNITS_PER_WORD == 0);
+         move_block_to_reg (REGNO (reg), x, partial / UNITS_PER_WORD, mode);
+       }
     }
 
-  if (extra && args_addr == 0 && where_pad == stack_direction)
-    anti_adjust_stack (GEN_INT (extra));
+  if (extra && args_addr == 0 && where_pad == stack_direction)
+    anti_adjust_stack (GEN_INT (extra));
+
+  if (alignment_pad && args_addr == 0)
+    anti_adjust_stack (alignment_pad);
+}
+\f
+/* Return X if X can be used as a subtarget in a sequence of arithmetic
+   operations.  */
+
+static rtx
+get_subtarget (rtx x)
+{
+  return (optimize
+          || x == 0
+          /* Only registers can be subtargets.  */
+          || !REG_P (x)
+          /* Don't use hard regs to avoid extending their life.  */
+          || REGNO (x) < FIRST_PSEUDO_REGISTER
+         ? 0 : x);
+}
+
+/* A subroutine of expand_assignment.  Optimize FIELD op= VAL, where
+   FIELD is a bitfield.  Returns true if the optimization was successful,
+   and there's nothing else to do.  */
+
+static bool
+optimize_bitfield_assignment_op (unsigned HOST_WIDE_INT bitsize,
+                                unsigned HOST_WIDE_INT bitpos,
+                                enum machine_mode mode1, rtx str_rtx,
+                                tree to, tree src)
+{
+  enum machine_mode str_mode = GET_MODE (str_rtx);
+  unsigned int str_bitsize = GET_MODE_BITSIZE (str_mode);
+  tree op0, op1;
+  rtx value, result;
+  optab binop;
+
+  if (mode1 != VOIDmode
+      || bitsize >= BITS_PER_WORD
+      || str_bitsize > BITS_PER_WORD
+      || TREE_SIDE_EFFECTS (to)
+      || TREE_THIS_VOLATILE (to))
+    return false;
+
+  STRIP_NOPS (src);
+  if (!BINARY_CLASS_P (src)
+      || TREE_CODE (TREE_TYPE (src)) != INTEGER_TYPE)
+    return false;
+
+  op0 = TREE_OPERAND (src, 0);
+  op1 = TREE_OPERAND (src, 1);
+  STRIP_NOPS (op0);
+
+  if (!operand_equal_p (to, op0, 0))
+    return false;
+
+  if (MEM_P (str_rtx))
+    {
+      unsigned HOST_WIDE_INT offset1;
+
+      if (str_bitsize == 0 || str_bitsize > BITS_PER_WORD)
+       str_mode = word_mode;
+      str_mode = get_best_mode (bitsize, bitpos,
+                               MEM_ALIGN (str_rtx), str_mode, 0);
+      if (str_mode == VOIDmode)
+       return false;
+      str_bitsize = GET_MODE_BITSIZE (str_mode);
+
+      offset1 = bitpos;
+      bitpos %= str_bitsize;
+      offset1 = (offset1 - bitpos) / BITS_PER_UNIT;
+      str_rtx = adjust_address (str_rtx, str_mode, offset1);
+    }
+  else if (!REG_P (str_rtx) && GET_CODE (str_rtx) != SUBREG)
+    return false;
+
+  /* If the bit field covers the whole REG/MEM, store_field
+     will likely generate better code.  */
+  if (bitsize >= str_bitsize)
+    return false;
+
+  /* We can't handle fields split across multiple entities.  */
+  if (bitpos + bitsize > str_bitsize)
+    return false;
+
+  if (BYTES_BIG_ENDIAN)
+    bitpos = str_bitsize - bitpos - bitsize;
+
+  switch (TREE_CODE (src))
+    {
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+      /* For now, just optimize the case of the topmost bitfield
+        where we don't need to do any masking and also
+        1 bit bitfields where xor can be used.
+        We might win by one instruction for the other bitfields
+        too if insv/extv instructions aren't used, so that
+        can be added later.  */
+      if (bitpos + bitsize != str_bitsize
+         && (bitsize != 1 || TREE_CODE (op1) != INTEGER_CST))
+       break;
+
+      value = expand_expr (op1, NULL_RTX, str_mode, 0);
+      value = convert_modes (str_mode,
+                            TYPE_MODE (TREE_TYPE (op1)), value,
+                            TYPE_UNSIGNED (TREE_TYPE (op1)));
+
+      /* We may be accessing data outside the field, which means
+        we can alias adjacent data.  */
+      if (MEM_P (str_rtx))
+       {
+         str_rtx = shallow_copy_rtx (str_rtx);
+         set_mem_alias_set (str_rtx, 0);
+         set_mem_expr (str_rtx, 0);
+       }
+
+      binop = TREE_CODE (src) == PLUS_EXPR ? add_optab : sub_optab;
+      if (bitsize == 1 && bitpos + bitsize != str_bitsize)
+       {
+         value = expand_and (str_mode, value, const1_rtx, NULL);
+         binop = xor_optab;
+       }
+      value = expand_shift (LSHIFT_EXPR, str_mode, value,
+                           build_int_cst (NULL_TREE, bitpos),
+                           NULL_RTX, 1);
+      result = expand_binop (str_mode, binop, str_rtx,
+                            value, str_rtx, 1, OPTAB_WIDEN);
+      if (result != str_rtx)
+       emit_move_insn (str_rtx, result);
+      return true;
+
+    case BIT_IOR_EXPR:
+    case BIT_XOR_EXPR:
+      if (TREE_CODE (op1) != INTEGER_CST)
+       break;
+      value = expand_expr (op1, NULL_RTX, GET_MODE (str_rtx), 0);
+      value = convert_modes (GET_MODE (str_rtx),
+                            TYPE_MODE (TREE_TYPE (op1)), value,
+                            TYPE_UNSIGNED (TREE_TYPE (op1)));
+
+      /* We may be accessing data outside the field, which means
+        we can alias adjacent data.  */
+      if (MEM_P (str_rtx))
+       {
+         str_rtx = shallow_copy_rtx (str_rtx);
+         set_mem_alias_set (str_rtx, 0);
+         set_mem_expr (str_rtx, 0);
+       }
+
+      binop = TREE_CODE (src) == BIT_IOR_EXPR ? ior_optab : xor_optab;
+      if (bitpos + bitsize != GET_MODE_BITSIZE (GET_MODE (str_rtx)))
+       {
+         rtx mask = GEN_INT (((unsigned HOST_WIDE_INT) 1 << bitsize)
+                             - 1);
+         value = expand_and (GET_MODE (str_rtx), value, mask,
+                             NULL_RTX);
+       }
+      value = expand_shift (LSHIFT_EXPR, GET_MODE (str_rtx), value,
+                           build_int_cst (NULL_TREE, bitpos),
+                           NULL_RTX, 1);
+      result = expand_binop (GET_MODE (str_rtx), binop, str_rtx,
+                            value, str_rtx, 1, OPTAB_WIDEN);
+      if (result != str_rtx)
+       emit_move_insn (str_rtx, result);
+      return true;
 
-  if (alignment_pad && args_addr == 0)
-    anti_adjust_stack (alignment_pad);
-}
-\f
-/* Return X if X can be used as a subtarget in a sequence of arithmetic
-   operations.  */
+    default:
+      break;
+    }
 
-static rtx
-get_subtarget (rtx x)
-{
-  return (optimize
-          || x == 0
-          /* Only registers can be subtargets.  */
-          || !REG_P (x)
-          /* Don't use hard regs to avoid extending their life.  */
-          || REGNO (x) < FIRST_PSEUDO_REGISTER
-         ? 0 : x);
+  return false;
 }
 
+
 /* Expand an assignment that stores the value of FROM into TO.  */
 
 void
@@ -3461,14 +3903,11 @@ expand_assignment (tree to, tree from)
      Assignment of an array element at a constant index, and assignment of
      an array element in an unaligned packed structure field, has the same
      problem.  */
-
-  if (TREE_CODE (to) == COMPONENT_REF || TREE_CODE (to) == BIT_FIELD_REF
-      || TREE_CODE (to) == ARRAY_REF || TREE_CODE (to) == ARRAY_RANGE_REF
+  if (handled_component_p (to)
       || TREE_CODE (TREE_TYPE (to)) == ARRAY_TYPE)
     {
       enum machine_mode mode1;
       HOST_WIDE_INT bitsize, bitpos;
-      rtx orig_to_rtx;
       tree offset;
       int unsignedp;
       int volatilep = 0;
@@ -3476,12 +3915,12 @@ expand_assignment (tree to, tree from)
 
       push_temp_slots ();
       tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1,
-                                &unsignedp, &volatilep);
+                                &unsignedp, &volatilep, true);
 
       /* If we are going to use store_bit_field and extract_bit_field,
         make sure to_rtx will be safe for multiple use.  */
 
-      orig_to_rtx = to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, 0);
+      to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, 0);
 
       if (offset != 0)
        {
@@ -3516,153 +3955,50 @@ expand_assignment (tree to, tree from)
                                                                   offset));
        }
 
-      if (MEM_P (to_rtx))
-       {
-         /* If the field is at offset zero, we could have been given the
-            DECL_RTX of the parent struct.  Don't munge it.  */
-         to_rtx = shallow_copy_rtx (to_rtx);
-
-         set_mem_attributes_minus_bitpos (to_rtx, to, 0, bitpos);
-       }
-
-      /* Deal with volatile and readonly fields.  The former is only done
-        for MEM.  Also set MEM_KEEP_ALIAS_SET_P if needed.  */
-      if (volatilep && MEM_P (to_rtx))
-       {
-         if (to_rtx == orig_to_rtx)
-           to_rtx = copy_rtx (to_rtx);
-         MEM_VOLATILE_P (to_rtx) = 1;
-       }
-
-      if (MEM_P (to_rtx) && ! can_address_p (to))
+      /* Handle expand_expr of a complex value returning a CONCAT.  */
+      if (GET_CODE (to_rtx) == CONCAT)
        {
-         if (to_rtx == orig_to_rtx)
-           to_rtx = copy_rtx (to_rtx);
-         MEM_KEEP_ALIAS_SET_P (to_rtx) = 1;
+         if (TREE_CODE (TREE_TYPE (from)) == COMPLEX_TYPE)
+           {
+             gcc_assert (bitpos == 0);
+             result = store_expr (from, to_rtx, false);
+           }
+         else
+           {
+             gcc_assert (bitpos == 0 || bitpos == GET_MODE_BITSIZE (mode1));
+             result = store_expr (from, XEXP (to_rtx, bitpos != 0), false);
+           }
        }
-
-      /* Optimize bitfld op= val in certain cases.  */
-      while (mode1 == VOIDmode
-            && bitsize > 0 && bitsize < BITS_PER_WORD
-            && GET_MODE_BITSIZE (GET_MODE (to_rtx)) <= BITS_PER_WORD
-            && !TREE_SIDE_EFFECTS (to)
-            && !TREE_THIS_VOLATILE (to))
+      else
        {
-         tree src, op0, op1;
-         rtx value, str_rtx = to_rtx;
-         HOST_WIDE_INT bitpos1 = bitpos;
-         optab binop;
-
-         src = from;
-         STRIP_NOPS (src);
-         if (TREE_CODE (TREE_TYPE (src)) != INTEGER_TYPE
-             || !BINARY_CLASS_P (src))
-           break;
-
-         op0 = TREE_OPERAND (src, 0);
-         op1 = TREE_OPERAND (src, 1);
-         STRIP_NOPS (op0);
-
-         if (! operand_equal_p (to, op0, 0))
-           break;
-
-         if (MEM_P (str_rtx))
+         if (MEM_P (to_rtx))
            {
-             enum machine_mode mode = GET_MODE (str_rtx);
-             HOST_WIDE_INT offset1;
-
-             if (GET_MODE_BITSIZE (mode) == 0
-                 || GET_MODE_BITSIZE (mode) > BITS_PER_WORD)
-               mode = word_mode;
-             mode = get_best_mode (bitsize, bitpos1, MEM_ALIGN (str_rtx),
-                                   mode, 0);
-             if (mode == VOIDmode)
-               break;
-
-             offset1 = bitpos1;
-             bitpos1 %= GET_MODE_BITSIZE (mode);
-             offset1 = (offset1 - bitpos1) / BITS_PER_UNIT;
-             str_rtx = adjust_address (str_rtx, mode, offset1);
-           }
-         else if (!REG_P (str_rtx) && GET_CODE (str_rtx) != SUBREG)
-           break;
-
-         /* If the bit field covers the whole REG/MEM, store_field
-            will likely generate better code.  */
-         if (bitsize >= GET_MODE_BITSIZE (GET_MODE (str_rtx)))
-           break;
-
-         /* We can't handle fields split across multiple entities.  */
-         if (bitpos1 + bitsize > GET_MODE_BITSIZE (GET_MODE (str_rtx)))
-           break;
-
-         if (BYTES_BIG_ENDIAN)
-           bitpos1 = GET_MODE_BITSIZE (GET_MODE (str_rtx)) - bitpos1
-                     - bitsize;
+             /* If the field is at offset zero, we could have been given the
+                DECL_RTX of the parent struct.  Don't munge it.  */
+             to_rtx = shallow_copy_rtx (to_rtx);
 
-         /* Special case some bitfield op= exp.  */
-         switch (TREE_CODE (src))
-           {
-           case PLUS_EXPR:
-           case MINUS_EXPR:
-             /* For now, just optimize the case of the topmost bitfield
-                where we don't need to do any masking and also
-                1 bit bitfields where xor can be used.
-                We might win by one instruction for the other bitfields
-                too if insv/extv instructions aren't used, so that
-                can be added later.  */
-             if (bitpos1 + bitsize != GET_MODE_BITSIZE (GET_MODE (str_rtx))
-                 && (bitsize != 1 || TREE_CODE (op1) != INTEGER_CST))
-               break;
-             value = expand_expr (op1, NULL_RTX, GET_MODE (str_rtx), 0);
-             value = convert_modes (GET_MODE (str_rtx),
-                                    TYPE_MODE (TREE_TYPE (op1)), value,
-                                    TYPE_UNSIGNED (TREE_TYPE (op1)));
-
-             /* We may be accessing data outside the field, which means
-                we can alias adjacent data.  */
-             if (MEM_P (str_rtx))
-               {
-                 str_rtx = shallow_copy_rtx (str_rtx);
-                 set_mem_alias_set (str_rtx, 0);
-                 set_mem_expr (str_rtx, 0);
-               }
+             set_mem_attributes_minus_bitpos (to_rtx, to, 0, bitpos);
 
-             binop = TREE_CODE (src) == PLUS_EXPR ? add_optab : sub_optab;
-             if (bitsize == 1
-                 && bitpos1 + bitsize != GET_MODE_BITSIZE (GET_MODE (str_rtx)))
-               {
-                 value = expand_and (GET_MODE (str_rtx), value, const1_rtx,
-                                     NULL_RTX);
-                 binop = xor_optab;
-               }
-             value = expand_shift (LSHIFT_EXPR, GET_MODE (str_rtx), value,
-                                   build_int_cst (NULL_TREE, bitpos1),
-                                   NULL_RTX, 1);
-             result = expand_binop (GET_MODE (str_rtx), binop, str_rtx,
-                                    value, str_rtx, 1, OPTAB_WIDEN);
-             if (result != str_rtx)
-               emit_move_insn (str_rtx, result);
-             free_temp_slots ();
-             pop_temp_slots ();
-             return;
-
-           default:
-             break;
+             /* Deal with volatile and readonly fields.  The former is only
+                done for MEM.  Also set MEM_KEEP_ALIAS_SET_P if needed.  */
+             if (volatilep)
+               MEM_VOLATILE_P (to_rtx) = 1;
+             if (component_uses_parent_alias_set (to))
+               MEM_KEEP_ALIAS_SET_P (to_rtx) = 1;
            }
 
-         break;
+         if (optimize_bitfield_assignment_op (bitsize, bitpos, mode1,
+                                              to_rtx, to, from))
+           result = NULL;
+         else
+           result = store_field (to_rtx, bitsize, bitpos, mode1, from,
+                                 TREE_TYPE (tem), get_alias_set (to));
        }
 
-      result = store_field (to_rtx, bitsize, bitpos, mode1, from,
-                           TREE_TYPE (tem), get_alias_set (to));
-
-      preserve_temp_slots (result);
+      if (result)
+       preserve_temp_slots (result);
       free_temp_slots ();
       pop_temp_slots ();
-
-      /* If the value is meaningful, convert RESULT to the proper mode.
-        Otherwise, return nothing.  */
       return;
     }
 
@@ -3939,10 +4275,10 @@ store_expr (tree exp, rtx target, int call_param_p)
         but TARGET is not valid memory reference, TEMP will differ
         from TARGET although it is really the same location.  */
       && !(alt_rtl && rtx_equal_p (alt_rtl, target))
-      /* If there's nothing to copy, don't bother.  Don't call expr_size
-        unless necessary, because some front-ends (C++) expr_size-hook
-        aborts on objects that are not supposed to be bit-copied or
-        bit-initialized.  */
+      /* If there's nothing to copy, don't bother.  Don't call
+        expr_size unless necessary, because some front-ends (C++)
+        expr_size-hook must not be given objects that are not
+        supposed to be bit-copied or bit-initialized.  */
       && expr_size (exp) != const0_rtx)
     {
       if (GET_MODE (temp) != GET_MODE (target)
@@ -4022,7 +4358,7 @@ store_expr (tree exp, rtx target, int call_param_p)
                }
 
              if (size != const0_rtx)
-               clear_storage (target, size);
+               clear_storage (target, size, BLOCK_OP_NORMAL);
 
              if (label)
                emit_label (label);
@@ -4048,24 +4384,32 @@ store_expr (tree exp, rtx target, int call_param_p)
   return NULL_RTX;
 }
 \f
-/* Examine CTOR.  Discover how many scalar fields are set to nonzero
-   values and place it in *P_NZ_ELTS.  Discover how many scalar fields
-   are set to non-constant values and place it in  *P_NC_ELTS.  */
+/* Examine CTOR to discover:
+   * how many scalar fields are set to nonzero values,
+     and place it in *P_NZ_ELTS;
+   * how many scalar fields are set to non-constant values,
+     and place it in  *P_NC_ELTS; and
+   * 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.  */
 
 static void
 categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts,
-                           HOST_WIDE_INT *p_nc_elts)
+                           HOST_WIDE_INT *p_nc_elts,
+                           HOST_WIDE_INT *p_elt_count,
+                           bool *p_must_clear)
 {
-  HOST_WIDE_INT nz_elts, nc_elts;
-  tree list;
+  unsigned HOST_WIDE_INT idx;
+  HOST_WIDE_INT nz_elts, nc_elts, elt_count;
+  tree value, purpose;
 
   nz_elts = 0;
   nc_elts = 0;
+  elt_count = 0;
 
-  for (list = CONSTRUCTOR_ELTS (ctor); list; list = TREE_CHAIN (list))
+  FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), idx, purpose, value)
     {
-      tree value = TREE_VALUE (list);
-      tree purpose = TREE_PURPOSE (list);
       HOST_WIDE_INT mult;
 
       mult = 1;
@@ -4083,10 +4427,11 @@ categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts,
        {
        case CONSTRUCTOR:
          {
-           HOST_WIDE_INT nz = 0, nc = 0;
-           categorize_ctor_elements_1 (value, &nz, &nc);
+           HOST_WIDE_INT nz = 0, nc = 0, ic = 0;
+           categorize_ctor_elements_1 (value, &nz, &nc, &ic, p_must_clear);
            nz_elts += mult * nz;
            nc_elts += mult * nc;
+           elt_count += mult * ic;
          }
          break;
 
@@ -4094,48 +4439,104 @@ categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts,
        case REAL_CST:
          if (!initializer_zerop (value))
            nz_elts += mult;
+         elt_count += mult;
+         break;
+
+       case STRING_CST:
+         nz_elts += mult * TREE_STRING_LENGTH (value);
+         elt_count += mult * TREE_STRING_LENGTH (value);
          break;
+
        case COMPLEX_CST:
          if (!initializer_zerop (TREE_REALPART (value)))
            nz_elts += mult;
          if (!initializer_zerop (TREE_IMAGPART (value)))
            nz_elts += mult;
+         elt_count += mult;
          break;
+
        case VECTOR_CST:
          {
            tree v;
            for (v = TREE_VECTOR_CST_ELTS (value); v; v = TREE_CHAIN (v))
-             if (!initializer_zerop (TREE_VALUE (v)))
-               nz_elts += mult;
+             {
+               if (!initializer_zerop (TREE_VALUE (v)))
+                 nz_elts += mult;
+               elt_count += mult;
+             }
          }
          break;
 
        default:
          nz_elts += mult;
+         elt_count += mult;
          if (!initializer_constant_valid_p (value, TREE_TYPE (value)))
            nc_elts += mult;
          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;
+    }
+
   *p_nz_elts += nz_elts;
   *p_nc_elts += nc_elts;
+  *p_elt_count += elt_count;
 }
 
 void
 categorize_ctor_elements (tree ctor, HOST_WIDE_INT *p_nz_elts,
-                         HOST_WIDE_INT *p_nc_elts)
+                         HOST_WIDE_INT *p_nc_elts,
+                         HOST_WIDE_INT *p_elt_count,
+                         bool *p_must_clear)
 {
   *p_nz_elts = 0;
   *p_nc_elts = 0;
-  categorize_ctor_elements_1 (ctor, p_nz_elts, p_nc_elts);
+  *p_elt_count = 0;
+  *p_must_clear = false;
+  categorize_ctor_elements_1 (ctor, p_nz_elts, p_nc_elts, p_elt_count,
+                             p_must_clear);
 }
 
 /* Count the number of scalars in TYPE.  Return -1 on overflow or
-   variable-sized.  */
+   variable-sized.  If ALLOW_FLEXARR is true, don't count flexible
+   array member at the end of the structure.  */
 
 HOST_WIDE_INT
-count_type_elements (tree type)
+count_type_elements (tree type, bool allow_flexarr)
 {
   const HOST_WIDE_INT max = ~((HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT-1));
   switch (TREE_CODE (type))
@@ -4146,7 +4547,7 @@ count_type_elements (tree 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));
+           HOST_WIDE_INT m = count_type_elements (TREE_TYPE (type), false);
            if (n == 0)
              return 0;
            else if (max / n > m)
@@ -4163,9 +4564,23 @@ count_type_elements (tree type)
        for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f))
          if (TREE_CODE (f) == FIELD_DECL)
            {
-             t = count_type_elements (TREE_TYPE (f));
+             t = count_type_elements (TREE_TYPE (f), false);
              if (t < 0)
-               return -1;
+               {
+                 /* Check for structures with flexible array member.  */
+                 tree tf = TREE_TYPE (f);
+                 if (allow_flexarr
+                     && TREE_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;
            }
 
@@ -4201,8 +4616,6 @@ count_type_elements (tree type)
 
     case VOID_TYPE:
     case METHOD_TYPE:
-    case FILE_TYPE:
-    case SET_TYPE:
     case FUNCTION_TYPE:
     case LANG_TYPE:
     default:
@@ -4212,20 +4625,20 @@ count_type_elements (tree type)
 
 /* Return 1 if EXP contains mostly (3/4)  zeros.  */
 
-int
+static int
 mostly_zeros_p (tree exp)
 {
   if (TREE_CODE (exp) == CONSTRUCTOR)
 
     {
-      HOST_WIDE_INT nz_elts, nc_elts, elts;
+      HOST_WIDE_INT nz_elts, nc_elts, count, elts;
+      bool must_clear;
 
-      /* If there are no ranges of true bits, it is all zero.  */
-      if (TREE_TYPE (exp) && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
-       return CONSTRUCTOR_ELTS (exp) == NULL_TREE;
+      categorize_ctor_elements (exp, &nz_elts, &nc_elts, &count, &must_clear);
+      if (must_clear)
+       return 1;
 
-      categorize_ctor_elements (exp, &nz_elts, &nc_elts);
-      elts = count_type_elements (TREE_TYPE (exp));
+      elts = count_type_elements (TREE_TYPE (exp), false);
 
       return nz_elts < elts / 4;
     }
@@ -4304,7 +4717,8 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
     case UNION_TYPE:
     case QUAL_UNION_TYPE:
       {
-       tree elt;
+       unsigned HOST_WIDE_INT idx;
+       tree field, value;
 
        /* If size is zero or the target is already cleared, do nothing.  */
        if (size == 0 || cleared)
@@ -4315,7 +4729,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                 && ! CONSTRUCTOR_ELTS (exp))
          /* If the constructor is empty, clear the union.  */
          {
-           clear_storage (target, expr_size (exp));
+           clear_storage (target, expr_size (exp), BLOCK_OP_NORMAL);
            cleared = 1;
          }
 
@@ -4336,14 +4750,14 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
           register whose mode size isn't equal to SIZE since
           clear_storage can't handle this case.  */
        else if (size > 0
-                && ((list_length (CONSTRUCTOR_ELTS (exp))
+                && (((int)VEC_length (constructor_elt, CONSTRUCTOR_ELTS (exp))
                      != fields_length (type))
                     || mostly_zeros_p (exp))
                 && (!REG_P (target)
                     || ((HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (target))
                         == size)))
          {
-           clear_storage (target, GEN_INT (size));
+           clear_storage (target, GEN_INT (size), BLOCK_OP_NORMAL);
            cleared = 1;
          }
 
@@ -4352,11 +4766,8 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
 
        /* Store each element of the constructor into the
           corresponding field of TARGET.  */
-
-       for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt))
+       FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (exp), idx, field, value)
          {
-           tree field = TREE_PURPOSE (elt);
-           tree value = TREE_VALUE (elt);
            enum machine_mode mode;
            HOST_WIDE_INT bitsize;
            HOST_WIDE_INT bitpos = 0;
@@ -4439,9 +4850,9 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                
                if (BYTES_BIG_ENDIAN)
                  value
-                   = fold (build2 (LSHIFT_EXPR, type, value,
-                                   build_int_cst (NULL_TREE,
-                                                  BITS_PER_WORD - bitsize)));
+                  = fold_build2 (LSHIFT_EXPR, type, value,
+                                  build_int_cst (NULL_TREE,
+                                                 BITS_PER_WORD - bitsize));
                bitsize = BITS_PER_WORD;
                mode = word_mode;
              }
@@ -4462,8 +4873,8 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
       }
     case ARRAY_TYPE:
       {
-       tree elt;
-       int i;
+       tree value, index;
+       unsigned HOST_WIDE_INT i;
        int need_to_clear;
        tree domain;
        tree elttype = TREE_TYPE (type);
@@ -4493,18 +4904,20 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
          need_to_clear = 1;
        else
          {
+           unsigned HOST_WIDE_INT idx;
+           tree index, value;
            HOST_WIDE_INT count = 0, zero_count = 0;
            need_to_clear = ! const_bounds_p;
            
            /* This loop is a more accurate version of the loop in
               mostly_zeros_p (it handles RANGE_EXPR in an index).  It
               is also needed to check for missing elements.  */
-           for (elt = CONSTRUCTOR_ELTS (exp);
-                elt != NULL_TREE && ! need_to_clear;
-                elt = TREE_CHAIN (elt))
+           FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (exp), idx, index, value)
              {
-               tree index = TREE_PURPOSE (elt);
                HOST_WIDE_INT this_node_count;
+
+               if (need_to_clear)
+                 break;
                
                if (index != NULL_TREE && TREE_CODE (index) == RANGE_EXPR)
                  {
@@ -4525,7 +4938,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                  this_node_count = 1;
                
                count += this_node_count;
-               if (mostly_zeros_p (TREE_VALUE (elt)))
+               if (mostly_zeros_p (value))
                  zero_count += this_node_count;
              }
            
@@ -4543,7 +4956,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
            if (REG_P (target))
              emit_move_insn (target,  CONST0_RTX (GET_MODE (target)));
            else
-             clear_storage (target, GEN_INT (size));
+             clear_storage (target, GEN_INT (size), BLOCK_OP_NORMAL);
            cleared = 1;
          }
 
@@ -4554,16 +4967,12 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
        /* Store each element of the constructor into the
           corresponding element of TARGET, determined by counting the
           elements.  */
-       for (elt = CONSTRUCTOR_ELTS (exp), i = 0;
-            elt;
-            elt = TREE_CHAIN (elt), i++)
+       FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (exp), i, index, value)
          {
            enum machine_mode mode;
            HOST_WIDE_INT bitsize;
            HOST_WIDE_INT bitpos;
            int unsignedp;
-           tree value = TREE_VALUE (elt);
-           tree index = TREE_PURPOSE (elt);
            rtx xtarget = target;
            
            if (cleared && initializer_zerop (value))
@@ -4642,8 +5051,8 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                    /* Assign value to element index.  */
                    position
                      = convert (ssizetype,
-                                fold (build2 (MINUS_EXPR, TREE_TYPE (index),
-                                              index, TYPE_MIN_VALUE (domain))));
+                                fold_build2 (MINUS_EXPR, TREE_TYPE (index),
+                                             index, TYPE_MIN_VALUE (domain)));
                    position = size_binop (MULT_EXPR, position,
                                           convert (ssizetype,
                                                    TYPE_SIZE_UNIT (elttype)));
@@ -4685,10 +5094,10 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                
                if (minelt)
                  index = fold_convert (ssizetype,
-                                       fold (build2 (MINUS_EXPR,
-                                                     TREE_TYPE (index),
-                                                     index,
-                                                     TYPE_MIN_VALUE (domain))));
+                                       fold_build2 (MINUS_EXPR,
+                                                    TREE_TYPE (index),
+                                                    index,
+                                                    TYPE_MIN_VALUE (domain)));
                
                position = size_binop (MULT_EXPR, index,
                                       convert (ssizetype,
@@ -4723,7 +5132,8 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
 
     case VECTOR_TYPE:
       {
-       tree elt;
+       unsigned HOST_WIDE_INT idx;
+       constructor_elt *ce;
        int i;
        int need_to_clear;
        int icode = 0;
@@ -4732,7 +5142,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
        enum machine_mode eltmode = TYPE_MODE (elttype);
        HOST_WIDE_INT bitsize;
        HOST_WIDE_INT bitpos;
-       rtx *vector = NULL;
+       rtvec vector = NULL;
        unsigned n_elts;
        
        gcc_assert (eltmode != BLKmode);
@@ -4747,9 +5157,9 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
              {
                unsigned int i;
                
-               vector = alloca (n_elts);
+               vector = rtvec_alloc (n_elts);
                for (i = 0; i < n_elts; i++)
-                 vector [i] = CONST0_RTX (GET_MODE_INNER (mode));
+                 RTVEC_ELT (vector, i) = CONST0_RTX (GET_MODE_INNER (mode));
              }
          }
        
@@ -4763,18 +5173,17 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
        else
          {
            unsigned HOST_WIDE_INT count = 0, zero_count = 0;
+           tree value;
            
-           for (elt = CONSTRUCTOR_ELTS (exp);
-                elt != NULL_TREE;
-                elt = TREE_CHAIN (elt))
+           FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value)
              {
                int n_elts_here = tree_low_cst
                  (int_const_binop (TRUNC_DIV_EXPR,
-                                   TYPE_SIZE (TREE_TYPE (TREE_VALUE (elt))),
+                                   TYPE_SIZE (TREE_TYPE (value)),
                                    TYPE_SIZE (elttype), 0), 1);
                
                count += n_elts_here;
-               if (mostly_zeros_p (TREE_VALUE (elt)))
+               if (mostly_zeros_p (value))
                  zero_count += n_elts_here;
              }
 
@@ -4788,30 +5197,29 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
            if (REG_P (target))
              emit_move_insn (target,  CONST0_RTX (GET_MODE (target)));
            else
-             clear_storage (target, GEN_INT (size));
+             clear_storage (target, GEN_INT (size), BLOCK_OP_NORMAL);
            cleared = 1;
          }
        
+       /* Inform later passes that the old value is dead.  */
        if (!cleared && REG_P (target))
-         /* Inform later passes that the old value is dead.  */
-         emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
+         emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
 
         /* Store each element of the constructor into the corresponding
           element of TARGET, determined by counting the elements.  */
-       for (elt = CONSTRUCTOR_ELTS (exp), i = 0;
-            elt;
-            elt = TREE_CHAIN (elt), i += bitsize / elt_size)
+       for (idx = 0, i = 0;
+            VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (exp), idx, ce);
+            idx++, i += bitsize / elt_size)
          {
-           tree value = TREE_VALUE (elt);
-           tree index = TREE_PURPOSE (elt);
            HOST_WIDE_INT eltpos;
+           tree value = ce->value;
            
            bitsize = tree_low_cst (TYPE_SIZE (TREE_TYPE (value)), 1);
            if (cleared && initializer_zerop (value))
              continue;
            
-           if (index != 0)
-             eltpos = tree_low_cst (index, 1);
+           if (ce->index)
+             eltpos = tree_low_cst (ce->index, 1);
            else
              eltpos = i;
            
@@ -4820,7 +5228,8 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                /* Vector CONSTRUCTORs should only be built from smaller
                   vectors in the case of BLKmode vectors.  */
                gcc_assert (TREE_CODE (TREE_TYPE (value)) != VECTOR_TYPE);
-               vector[eltpos] = expand_expr (value, NULL_RTX, VOIDmode, 0);
+               RTVEC_ELT (vector, eltpos)
+                 = expand_expr (value, NULL_RTX, VOIDmode, 0);
              }
            else
              {
@@ -4838,188 +5247,10 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
        if (vector)
          emit_insn (GEN_FCN (icode)
                     (target,
-                     gen_rtx_PARALLEL (GET_MODE (target),
-                                       gen_rtvec_v (n_elts, vector))));
-       break;
-      }
-
-      /* Set constructor assignments.  */
-    case SET_TYPE:
-      {
-       tree elt = CONSTRUCTOR_ELTS (exp);
-       unsigned HOST_WIDE_INT nbytes = int_size_in_bytes (type), nbits;
-       tree domain = TYPE_DOMAIN (type);
-       tree domain_min, domain_max, bitlength;
-       
-       /* The default implementation strategy is to extract the
-          constant parts of the constructor, use that to initialize
-          the target, and then "or" in whatever non-constant ranges
-          we need in addition.
-
-          If a large set is all zero or all ones, it is probably
-          better to set it using memset.  Also, if a large set has
-          just a single range, it may also be better to first clear
-          all the first clear the set (using memset), and set the
-          bits we want.  */
-
-       /* Check for all zeros.  */
-       if (elt == NULL_TREE && size > 0)
-         {
-           if (!cleared)
-             clear_storage (target, GEN_INT (size));
-           return;
-         }
-       
-       domain_min = convert (sizetype, TYPE_MIN_VALUE (domain));
-       domain_max = convert (sizetype, TYPE_MAX_VALUE (domain));
-       bitlength = size_binop (PLUS_EXPR,
-                               size_diffop (domain_max, domain_min),
-                               ssize_int (1));
-       
-       nbits = tree_low_cst (bitlength, 1);
-
-        /* For "small" sets, or "medium-sized" (up to 32 bytes) sets
-          that are "complicated" (more than one range), initialize
-          (the constant parts) by copying from a constant.  */
-       if (GET_MODE (target) != BLKmode || nbits <= 2 * BITS_PER_WORD
-           || (nbytes <= 32 && TREE_CHAIN (elt) != NULL_TREE))
-         {
-           unsigned int set_word_size = TYPE_ALIGN (TREE_TYPE (exp));
-           enum machine_mode mode = mode_for_size (set_word_size, MODE_INT, 1);
-           char *bit_buffer = alloca (nbits);
-           HOST_WIDE_INT word = 0;
-           unsigned int bit_pos = 0;
-           unsigned int ibit = 0;
-           unsigned int offset = 0;  /* In bytes from beginning of set.  */
-           
-           elt = get_set_constructor_bits (exp, bit_buffer, nbits);
-           for (;;)
-             {
-               if (bit_buffer[ibit])
-                 {
-                   if (BYTES_BIG_ENDIAN)
-                     word |= (1 << (set_word_size - 1 - bit_pos));
-                   else
-                     word |= 1 << bit_pos;
-                 }
-               
-               bit_pos++;  ibit++;
-               if (bit_pos >= set_word_size || ibit == nbits)
-                 {
-                   if (word != 0 || ! cleared)
-                     {
-                       rtx datum = gen_int_mode (word, mode);
-                       rtx to_rtx;
-                       
-                       /* The assumption here is that it is safe to
-                          use XEXP if the set is multi-word, but not
-                          if it's single-word.  */
-                       if (MEM_P (target))
-                         to_rtx = adjust_address (target, mode, offset);
-                       else
-                         {
-                           gcc_assert (!offset);
-                           to_rtx = target;
-                         }
-                       emit_move_insn (to_rtx, datum);
-                     }
-                   
-                   if (ibit == nbits)
-                     break;
-                   word = 0;
-                   bit_pos = 0;
-                   offset += set_word_size / BITS_PER_UNIT;
-                 }
-             }
-         }
-       else if (!cleared)
-         /* Don't bother clearing storage if the set is all ones.  */
-         if (TREE_CHAIN (elt) != NULL_TREE
-             || (TREE_PURPOSE (elt) == NULL_TREE
-                 ? nbits != 1
-                 : ( ! host_integerp (TREE_VALUE (elt), 0)
-                     || ! host_integerp (TREE_PURPOSE (elt), 0)
-                     || (tree_low_cst (TREE_VALUE (elt), 0)
-                         - tree_low_cst (TREE_PURPOSE (elt), 0) + 1
-                         != (HOST_WIDE_INT) nbits))))
-           clear_storage (target, expr_size (exp));
-       
-       for (; elt != NULL_TREE; elt = TREE_CHAIN (elt))
-         {
-           /* Start of range of element or NULL.  */
-           tree startbit = TREE_PURPOSE (elt);
-           /* End of range of element, or element value.  */
-           tree endbit   = TREE_VALUE (elt);
-           HOST_WIDE_INT startb, endb;
-           rtx bitlength_rtx, startbit_rtx, endbit_rtx, targetx;
-           
-           bitlength_rtx = expand_expr (bitlength,
-                                        NULL_RTX, MEM, EXPAND_CONST_ADDRESS);
-           
-           /* Handle non-range tuple element like [ expr ].  */
-           if (startbit == NULL_TREE)
-             {
-               startbit = save_expr (endbit);
-               endbit = startbit;
-             }
-           
-           startbit = convert (sizetype, startbit);
-           endbit = convert (sizetype, endbit);
-           if (! integer_zerop (domain_min))
-             {
-               startbit = size_binop (MINUS_EXPR, startbit, domain_min);
-               endbit = size_binop (MINUS_EXPR, endbit, domain_min);
-             }
-           startbit_rtx = expand_expr (startbit, NULL_RTX, MEM,
-                                       EXPAND_CONST_ADDRESS);
-           endbit_rtx = expand_expr (endbit, NULL_RTX, MEM,
-                                     EXPAND_CONST_ADDRESS);
-           
-           if (REG_P (target))
-             {
-               targetx
-                 = assign_temp
-                 ((build_qualified_type (lang_hooks.types.type_for_mode
-                                         (GET_MODE (target), 0),
-                                         TYPE_QUAL_CONST)),
-                  0, 1, 1);
-               emit_move_insn (targetx, target);
-             }
-           
-           else
-             {
-               gcc_assert (MEM_P (target));
-               targetx = target;
-             }
-
-           /* Optimization:  If startbit and endbit are constants divisible
-              by BITS_PER_UNIT, call memset instead.  */
-           if (TREE_CODE (startbit) == INTEGER_CST
-               && TREE_CODE (endbit) == INTEGER_CST
-               && (startb = TREE_INT_CST_LOW (startbit)) % BITS_PER_UNIT == 0
-               && (endb = TREE_INT_CST_LOW (endbit) + 1) % BITS_PER_UNIT == 0)
-             {
-               emit_library_call (memset_libfunc, LCT_NORMAL,
-                                  VOIDmode, 3,
-                                  plus_constant (XEXP (targetx, 0),
-                                                 startb / BITS_PER_UNIT),
-                                  Pmode,
-                                  constm1_rtx, TYPE_MODE (integer_type_node),
-                                  GEN_INT ((endb - startb) / BITS_PER_UNIT),
-                                  TYPE_MODE (sizetype));
-             }
-           else
-             emit_library_call (setbits_libfunc, LCT_NORMAL,
-                                VOIDmode, 4, XEXP (targetx, 0),
-                                Pmode, bitlength_rtx, TYPE_MODE (sizetype),
-                                startbit_rtx, TYPE_MODE (sizetype),
-                                endbit_rtx, TYPE_MODE (sizetype));
-           
-           if (REG_P (target))
-             emit_move_insn (target, targetx);
-         }
+                     gen_rtx_PARALLEL (GET_MODE (target), vector)));
        break;
       }
+      
     default:
       gcc_unreachable ();
     }
@@ -5116,7 +5347,27 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
          && TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) == INTEGER_CST
          && compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)), bitsize) != 0))
     {
-      rtx temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
+      rtx temp;
+
+      /* If EXP is a NOP_EXPR of precision less than its mode, then that
+        implies a mask operation.  If the precision is the same size as
+        the field we're storing into, that mask is redundant.  This is
+        particularly common with bit field assignments generated by the
+        C front end.  */
+      if (TREE_CODE (exp) == NOP_EXPR)
+       {
+         tree type = TREE_TYPE (exp);
+         if (INTEGRAL_TYPE_P (type)
+             && TYPE_PRECISION (type) < GET_MODE_BITSIZE (TYPE_MODE (type))
+             && bitsize == TYPE_PRECISION (type))
+           {
+             type = TREE_TYPE (TREE_OPERAND (exp, 0));
+             if (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) >= bitsize)
+               exp = TREE_OPERAND (exp, 0);
+           }
+       }
+
+      temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
 
       /* If BITSIZE is narrower than the size of the type of EXP
         we will be narrowing TEMP.  Normally, what's wanted are the
@@ -5194,13 +5445,27 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
 
    If the field describes a variable-sized object, *PMODE is set to
    VOIDmode and *PBITSIZE is set to -1.  An access cannot be made in
-   this case, but the address of the object can be found.  */
+   this case, but the address of the object can be found.
+
+   If KEEP_ALIGNING is true and the target is STRICT_ALIGNMENT, we don't
+   look through nodes that serve as markers of a greater alignment than
+   the one that can be deduced from the expression.  These nodes make it
+   possible for front-ends to prevent temporaries from being created by
+   the middle-end on alignment considerations.  For that purpose, the
+   normal operating mode at high-level is to always pass FALSE so that
+   the ultimate containing object is really returned; moreover, the
+   associated predicate handled_component_p will always return TRUE
+   on these nodes, thus indicating that they are essentially handled
+   by get_inner_reference.  TRUE should only be passed when the caller
+   is scanning the expression in order to build another representation
+   and specifically knows how to handle these nodes; as such, this is
+   the normal operating mode in the RTL expanders.  */
 
 tree
 get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
                     HOST_WIDE_INT *pbitpos, tree *poffset,
                     enum machine_mode *pmode, int *punsignedp,
-                    int *pvolatilep)
+                    int *pvolatilep, bool keep_aligning)
 {
   tree size_tree = 0;
   enum machine_mode mode = VOIDmode;
@@ -5246,72 +5511,84 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
      and find the ultimate containing object.  */
   while (1)
     {
-      if (TREE_CODE (exp) == BIT_FIELD_REF)
-       bit_offset = size_binop (PLUS_EXPR, bit_offset, TREE_OPERAND (exp, 2));
-      else if (TREE_CODE (exp) == COMPONENT_REF)
+      switch (TREE_CODE (exp))
        {
-         tree field = TREE_OPERAND (exp, 1);
-         tree this_offset = component_ref_field_offset (exp);
+       case BIT_FIELD_REF:
+         bit_offset = size_binop (PLUS_EXPR, bit_offset,
+                                  TREE_OPERAND (exp, 2));
+         break;
 
-         /* If this field hasn't been filled in yet, don't go
-            past it.  This should only happen when folding expressions
-            made during type construction.  */
-         if (this_offset == 0)
-           break;
+       case COMPONENT_REF:
+         {
+           tree field = TREE_OPERAND (exp, 1);
+           tree this_offset = component_ref_field_offset (exp);
+
+           /* If this field hasn't been filled in yet, don't go past it.
+              This should only happen when folding expressions made during
+              type construction.  */
+           if (this_offset == 0)
+             break;
+
+           offset = size_binop (PLUS_EXPR, offset, this_offset);
+           bit_offset = size_binop (PLUS_EXPR, bit_offset,
+                                    DECL_FIELD_BIT_OFFSET (field));
+
+           /* ??? Right now we don't do anything with DECL_OFFSET_ALIGN.  */
+         }
+         break;
+
+       case ARRAY_REF:
+       case ARRAY_RANGE_REF:
+         {
+           tree index = TREE_OPERAND (exp, 1);
+           tree low_bound = array_ref_low_bound (exp);
+           tree unit_size = array_ref_element_size (exp);
+
+           /* We assume all arrays have sizes that are a multiple of a byte.
+              First subtract the lower bound, if any, in the type of the
+              index, then convert to sizetype and multiply by the size of
+              the array element.  */
+           if (! integer_zerop (low_bound))
+             index = fold_build2 (MINUS_EXPR, TREE_TYPE (index),
+                                  index, low_bound);
+
+           offset = size_binop (PLUS_EXPR, offset,
+                                size_binop (MULT_EXPR,
+                                            convert (sizetype, index),
+                                            unit_size));
+         }
+         break;
+
+       case REALPART_EXPR:
+         break;
 
-         offset = size_binop (PLUS_EXPR, offset, this_offset);
+       case IMAGPART_EXPR:
          bit_offset = size_binop (PLUS_EXPR, bit_offset,
-                                  DECL_FIELD_BIT_OFFSET (field));
+                                  bitsize_int (*pbitsize));
+         break;
 
-         /* ??? Right now we don't do anything with DECL_OFFSET_ALIGN.  */
-       }
+       case VIEW_CONVERT_EXPR:
+         if (keep_aligning && STRICT_ALIGNMENT
+             && (TYPE_ALIGN (TREE_TYPE (exp))
+              > TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (exp, 0))))
+             && (TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (exp, 0)))
+                 < BIGGEST_ALIGNMENT)
+             && (TYPE_ALIGN_OK (TREE_TYPE (exp))
+                 || TYPE_ALIGN_OK (TREE_TYPE (TREE_OPERAND (exp, 0)))))
+           goto done;
+         break;
 
-      else if (TREE_CODE (exp) == ARRAY_REF
-              || TREE_CODE (exp) == ARRAY_RANGE_REF)
-       {
-         tree index = TREE_OPERAND (exp, 1);
-         tree low_bound = array_ref_low_bound (exp);
-         tree unit_size = array_ref_element_size (exp);
-
-         /* We assume all arrays have sizes that are a multiple of a byte.
-            First subtract the lower bound, if any, in the type of the
-            index, then convert to sizetype and multiply by the size of the
-            array element.  */
-         if (! integer_zerop (low_bound))
-           index = fold (build2 (MINUS_EXPR, TREE_TYPE (index),
-                                 index, low_bound));
-
-         offset = size_binop (PLUS_EXPR, offset,
-                              size_binop (MULT_EXPR,
-                                          convert (sizetype, index),
-                                          unit_size));
+       default:
+         goto done;
        }
 
-      /* We can go inside most conversions: all NON_VALUE_EXPRs, all normal
-        conversions that don't change the mode, and all view conversions
-        except those that need to "step up" the alignment.  */
-      else if (TREE_CODE (exp) != NON_LVALUE_EXPR
-              && ! (TREE_CODE (exp) == VIEW_CONVERT_EXPR
-                    && ! ((TYPE_ALIGN (TREE_TYPE (exp))
-                           > TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (exp, 0))))
-                          && STRICT_ALIGNMENT
-                          && (TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (exp, 0)))
-                              < BIGGEST_ALIGNMENT)
-                          && (TYPE_ALIGN_OK (TREE_TYPE (exp))
-                              || TYPE_ALIGN_OK (TREE_TYPE
-                                                (TREE_OPERAND (exp, 0))))))
-              && ! ((TREE_CODE (exp) == NOP_EXPR
-                     || TREE_CODE (exp) == CONVERT_EXPR)
-                    && (TYPE_MODE (TREE_TYPE (exp))
-                        == TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))))
-       break;
-
       /* If any reference in the chain is volatile, the effect is volatile.  */
       if (TREE_THIS_VOLATILE (exp))
        *pvolatilep = 1;
 
       exp = TREE_OPERAND (exp, 0);
     }
+ done:
 
   /* If OFFSET is constant, see if we can return the whole thing as a
      constant bit position.  Otherwise, split it up.  */
@@ -5432,18 +5709,11 @@ handled_component_p (tree t)
     case COMPONENT_REF:
     case ARRAY_REF:
     case ARRAY_RANGE_REF:
-    case NON_LVALUE_EXPR:
     case VIEW_CONVERT_EXPR:
+    case REALPART_EXPR:
+    case IMAGPART_EXPR:
       return 1;
 
-    /* ??? Sure they are handled, but get_inner_reference may return
-       a different PBITSIZE, depending upon whether the expression is
-       wrapped up in a NOP_EXPR or not, e.g. for bitfields.  */
-    case NOP_EXPR:
-    case CONVERT_EXPR:
-      return (TYPE_MODE (TREE_TYPE (t))
-             == TYPE_MODE (TREE_TYPE (TREE_OPERAND (t, 0))));
-
     default:
       return 0;
     }
@@ -5747,7 +6017,7 @@ safe_from_p (rtx x, tree exp, int top_p)
       if (exp_rtl)
        break;
 
-      nops = first_rtl_op (TREE_CODE (exp));
+      nops = TREE_CODE_LENGTH (TREE_CODE (exp));
       for (i = 0; i < nops; i++)
        if (TREE_OPERAND (exp, i) != 0
            && ! safe_from_p (x, TREE_OPERAND (exp, i), 0))
@@ -5794,7 +6064,7 @@ safe_from_p (rtx x, tree exp, int top_p)
 /* Return the highest power of two that EXP is known to be a multiple of.
    This is used in updating alignment of MEMs in array references.  */
 
-static unsigned HOST_WIDE_INT
+unsigned HOST_WIDE_INT
 highest_pow2_factor (tree exp)
 {
   unsigned HOST_WIDE_INT c0, c1;
@@ -5895,7 +6165,7 @@ expand_var (tree var)
       ? !TREE_ASM_WRITTEN (var)
       : !DECL_RTL_SET_P (var))
     {
-      if (TREE_CODE (var) == VAR_DECL && DECL_VALUE_EXPR (var))
+      if (TREE_CODE (var) == VAR_DECL && DECL_HAS_VALUE_EXPR_P (var))
        /* Should be ignored.  */;
       else if (lang_hooks.expand_decl (var))
        /* OK.  */;
@@ -6007,7 +6277,7 @@ 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 (GET_CODE (result) == MEM);
+         gcc_assert (MEM_P (result));
          result = XEXP (result, 0);
 
          /* ??? Is this needed anymore?  */
@@ -6023,8 +6293,13 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
          return result;
        }
 
+      /* Pass FALSE as the last argument to get_inner_reference although
+        we are expanding to RTL.  The rationale is that we know how to
+        handle "aligning nodes" here: we can just bypass them because
+        they won't change the final object whose address will be returned
+        (they actually exist only for that purpose).  */
       inner = get_inner_reference (exp, &bitsize, &bitpos, &offset,
-                                  &mode1, &unsignedp, &volatilep);
+                                  &mode1, &unsignedp, &volatilep, false);
       break;
     }
 
@@ -6310,12 +6585,6 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
          expand_expr (TREE_OPERAND (exp, 1), const0_rtx, VOIDmode, modifier);
          return const0_rtx;
        }
-      else if ((code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)
-              && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 1)))
-       /* If the second operand has no side effects, just evaluate
-          the first.  */
-       return expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
-                           modifier);
       else if (code == BIT_FIELD_REF)
        {
          expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, modifier);
@@ -6327,18 +6596,6 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       target = 0;
     }
 
-  /* If will do cse, generate all results into pseudo registers
-     since 1) that allows cse to find more things
-     and 2) otherwise cse could produce an insn the machine
-     cannot support.  An exception is a CONSTRUCTOR into a multi-word
-     MEM: that's much more likely to be most efficient into the MEM.
-     Another is a CALL_EXPR which must return in memory.  */
-
-  if (! cse_not_expected && mode != BLKmode && target
-      && (!REG_P (target) || REGNO (target) < FIRST_PSEUDO_REGISTER)
-      && ! (code == CONSTRUCTOR && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
-      && ! (code == CALL_EXPR && aggregate_value_p (exp, exp)))
-    target = 0;
 
   switch (code)
     {
@@ -6477,8 +6734,9 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
          || GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (exp))) == MODE_VECTOR_FLOAT)
        return const_vector_from_tree (exp);
       else
-       return expand_expr (build1 (CONSTRUCTOR, TREE_TYPE (exp),
-                                   TREE_VECTOR_CST_ELTS (exp)),
+       return expand_expr (build_constructor_from_list
+                           (TREE_TYPE (exp),
+                            TREE_VECTOR_CST_ELTS (exp)),
                            ignore ? const0_rtx : target, tmode, modifier);
 
     case CONST_DECL:
@@ -6576,10 +6834,11 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
         subexpressions.  */
       if (ignore)
        {
-         tree elt;
+         unsigned HOST_WIDE_INT idx;
+         tree value;
 
-         for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt))
-           expand_expr (TREE_VALUE (elt), const0_rtx, VOIDmode, 0);
+         FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value)
+           expand_expr (value, const0_rtx, VOIDmode, 0);
 
          return const0_rtx;
        }
@@ -6642,11 +6901,6 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
     case INDIRECT_REF:
       {
        tree exp1 = TREE_OPERAND (exp, 0);
-       tree orig;
-
-       if (code == MISALIGNED_INDIRECT_REF
-           && !targetm.vectorize.misaligned_mem_ok (mode))
-         abort ();
 
        if (modifier != EXPAND_WRITE)
          {
@@ -6669,34 +6923,55 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
        temp = gen_rtx_MEM (mode, op0);
 
-       orig = REF_ORIGINAL (exp);
-       if (!orig)
-         orig = exp;
-       set_mem_attributes (temp, orig, 0);
+       set_mem_attributes (temp, exp, 0);
+
+       /* Resolve the misalignment now, so that we don't have to remember
+          to resolve it later.  Of course, this only works for reads.  */
+       /* ??? When we get around to supporting writes, we'll have to handle
+          this in store_expr directly.  The vectorizer isn't generating
+          those yet, however.  */
+       if (code == MISALIGNED_INDIRECT_REF)
+         {
+           int icode;
+           rtx reg, insn;
+
+           gcc_assert (modifier == EXPAND_NORMAL);
+
+           /* The vectorizer should have already checked the mode.  */
+           icode = movmisalign_optab->handlers[mode].insn_code;
+           gcc_assert (icode != CODE_FOR_nothing);
+
+           /* 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;
+         }
 
        return temp;
       }
 
-    case ARRAY_REF:
-
+    case TARGET_MEM_REF:
       {
-       tree array = TREE_OPERAND (exp, 0);
-       tree low_bound = array_ref_low_bound (exp);
-       tree index = convert (sizetype, TREE_OPERAND (exp, 1));
-       HOST_WIDE_INT i;
-
-       gcc_assert (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE);
+       struct mem_address addr;
 
-       /* Optimize the special-case of a zero lower bound.
+       get_address_description (exp, &addr);
+       op0 = addr_for_mem_ref (&addr, true);
+       op0 = memory_address (mode, op0);
+       temp = gen_rtx_MEM (mode, op0);
+       set_mem_attributes (temp, TMR_ORIGINAL (exp), 0);
+      }
+      return temp;
 
-          We convert the low_bound to sizetype to avoid some problems
-          with constant folding.  (E.g. suppose the lower bound is 1,
-          and its mode is QI.  Without the conversion,  (ARRAY
-          +(INDEX-(unsigned char)1)) becomes ((ARRAY+(-(unsigned char)1))
-          +INDEX), which becomes (ARRAY+255+INDEX).  Oops!)  */
+    case ARRAY_REF:
 
-       if (! integer_zerop (low_bound))
-         index = size_diffop (index, convert (sizetype, low_bound));
+      {
+       tree array = TREE_OPERAND (exp, 0);
+       tree index = TREE_OPERAND (exp, 1);
 
        /* Fold an expression like: "foo"[2].
           This is not done in fold so it won't happen inside &.
@@ -6723,21 +6998,19 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
            && modifier != EXPAND_MEMORY
            && TREE_CODE (array) == CONSTRUCTOR
            && ! TREE_SIDE_EFFECTS (array)
-           && TREE_CODE (index) == INTEGER_CST
-           && 0 > compare_tree_int (index,
-                                    list_length (CONSTRUCTOR_ELTS
-                                                 (TREE_OPERAND (exp, 0)))))
+           && TREE_CODE (index) == INTEGER_CST)
          {
-           tree elem;
-
-           for (elem = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)),
-                i = TREE_INT_CST_LOW (index);
-                elem != 0 && i != 0; i--, elem = TREE_CHAIN (elem))
-             ;
+           unsigned HOST_WIDE_INT ix;
+           tree field, value;
 
-           if (elem)
-             return expand_expr (fold (TREE_VALUE (elem)), target, tmode,
-                                 modifier);
+           FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (array), ix,
+                                     field, value)
+             if (tree_int_cst_equal (field, index))
+               {
+                 if (!TREE_SIDE_EFFECTS (value))
+                   return expand_expr (fold (value), target, tmode, modifier);
+                 break;
+               }
          }
 
        else if (optimize >= 1
@@ -6755,17 +7028,18 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
                if (TREE_CODE (init) == CONSTRUCTOR)
                  {
-                   tree elem;
+                   unsigned HOST_WIDE_INT ix;
+                   tree field, value;
 
-                   for (elem = CONSTRUCTOR_ELTS (init);
-                        (elem
-                         && !tree_int_cst_equal (TREE_PURPOSE (elem), index));
-                        elem = TREE_CHAIN (elem))
-                     ;
-
-                   if (elem && !TREE_SIDE_EFFECTS (TREE_VALUE (elem)))
-                     return expand_expr (fold (TREE_VALUE (elem)), target,
-                                         tmode, modifier);
+                   FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), ix,
+                                             field, value)
+                     if (tree_int_cst_equal (field, index))
+                       {
+                         if (!TREE_SIDE_EFFECTS (value))
+                           return expand_expr (fold (value), target, tmode,
+                                               modifier);
+                         break;
+                       }
                  }
                else if (TREE_CODE (init) == STRING_CST
                         && 0 > compare_tree_int (index,
@@ -6789,11 +7063,12 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
         appropriate field if it is present.  */
       if (TREE_CODE (TREE_OPERAND (exp, 0)) == CONSTRUCTOR)
        {
-         tree elt;
+         unsigned HOST_WIDE_INT idx;
+         tree field, value;
 
-         for (elt = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)); elt;
-              elt = TREE_CHAIN (elt))
-           if (TREE_PURPOSE (elt) == TREE_OPERAND (exp, 1)
+         FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)),
+                                   idx, field, value)
+           if (field == TREE_OPERAND (exp, 1)
                /* We can normally use the value of the field in the
                   CONSTRUCTOR.  However, if this is a bitfield in
                   an integral mode that we can fit in a HOST_WIDE_INT,
@@ -6801,24 +7076,21 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                   since this is done implicitly by the constructor.  If
                   the bitfield does not meet either of those conditions,
                   we can't do this optimization.  */
-               && (! DECL_BIT_FIELD (TREE_PURPOSE (elt))
-                   || ((GET_MODE_CLASS (DECL_MODE (TREE_PURPOSE (elt)))
-                        == MODE_INT)
-                       && (GET_MODE_BITSIZE (DECL_MODE (TREE_PURPOSE (elt)))
+               && (! DECL_BIT_FIELD (field)
+                   || ((GET_MODE_CLASS (DECL_MODE (field)) == MODE_INT)
+                       && (GET_MODE_BITSIZE (DECL_MODE (field))
                            <= HOST_BITS_PER_WIDE_INT))))
              {
-               if (DECL_BIT_FIELD (TREE_PURPOSE (elt))
+               if (DECL_BIT_FIELD (field)
                    && modifier == EXPAND_STACK_PARM)
                  target = 0;
-               op0 = expand_expr (TREE_VALUE (elt), target, tmode, modifier);
-               if (DECL_BIT_FIELD (TREE_PURPOSE (elt)))
+               op0 = expand_expr (value, target, tmode, modifier);
+               if (DECL_BIT_FIELD (field))
                  {
-                   HOST_WIDE_INT bitsize
-                     = TREE_INT_CST_LOW (DECL_SIZE (TREE_PURPOSE (elt)));
-                   enum machine_mode imode
-                     = TYPE_MODE (TREE_TYPE (TREE_PURPOSE (elt)));
+                   HOST_WIDE_INT bitsize = TREE_INT_CST_LOW (DECL_SIZE (field));
+                   enum machine_mode imode = TYPE_MODE (TREE_TYPE (field));
 
-                   if (TYPE_UNSIGNED (TREE_TYPE (TREE_PURPOSE (elt))))
+                   if (TYPE_UNSIGNED (TREE_TYPE (field)))
                      {
                        op1 = GEN_INT (((HOST_WIDE_INT) 1 << bitsize) - 1);
                        op0 = expand_and (imode, op0, op1, target);
@@ -6850,7 +7122,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
        tree offset;
        int volatilep = 0;
        tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
-                                       &mode1, &unsignedp, &volatilep);
+                                       &mode1, &unsignedp, &volatilep, true);
        rtx orig_op0;
 
        /* If we got back the original object, something is wrong.  Perhaps
@@ -7196,36 +7468,39 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
        }
 
       op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, modifier);
-      op0 = REDUCE_BIT_FIELD (op0);
       if (GET_MODE (op0) == mode)
-       return op0;
+       ;
 
       /* If OP0 is a constant, just convert it into the proper mode.  */
-      if (CONSTANT_P (op0))
+      else if (CONSTANT_P (op0))
        {
          tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
          enum machine_mode inner_mode = TYPE_MODE (inner_type);
 
          if (modifier == EXPAND_INITIALIZER)
-           return simplify_gen_subreg (mode, op0, inner_mode,
-                                       subreg_lowpart_offset (mode,
-                                                              inner_mode));
+           op0 = simplify_gen_subreg (mode, op0, inner_mode,
+                                      subreg_lowpart_offset (mode,
+                                                             inner_mode));
          else
-           return convert_modes (mode, inner_mode, op0,
-                                 TYPE_UNSIGNED (inner_type));
+           op0=  convert_modes (mode, inner_mode, op0,
+                                TYPE_UNSIGNED (inner_type));
        }
 
-      if (modifier == EXPAND_INITIALIZER)
-       return gen_rtx_fmt_e (unsignedp ? ZERO_EXTEND : SIGN_EXTEND, mode, op0);
+      else if (modifier == EXPAND_INITIALIZER)
+       op0 = gen_rtx_fmt_e (unsignedp ? ZERO_EXTEND : SIGN_EXTEND, mode, op0);
 
-      if (target == 0)
-       return
-         convert_to_mode (mode, op0,
-                          TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
+      else if (target == 0)
+       op0 = convert_to_mode (mode, op0,
+                              TYPE_UNSIGNED (TREE_TYPE
+                                             (TREE_OPERAND (exp, 0))));
       else
-       convert_move (target, op0,
-                     TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
-      return target;
+       {
+         convert_move (target, op0,
+                       TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
+         op0 = target;
+       }
+
+      return REDUCE_BIT_FIELD (op0);
 
     case VIEW_CONVERT_EXPR:
       op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, modifier);
@@ -7527,7 +7802,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
          optab other_optab = zextend_p ? smul_widen_optab : umul_widen_optab;
          this_optab = zextend_p ? umul_widen_optab : smul_widen_optab;
 
-         if (mode == GET_MODE_WIDER_MODE (innermode))
+         if (mode == GET_MODE_2XWIDER_MODE (innermode))
            {
              if (this_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
                {
@@ -7586,18 +7861,6 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       return expand_divmod (0, code, mode, op0, op1, target, unsignedp);
 
     case RDIV_EXPR:
-      /* Emit a/b as a*(1/b).  Later we may manage CSE the reciprocal saving
-         expensive divide.  If not, combine will rebuild the original
-         computation.  */
-      if (flag_unsafe_math_optimizations && optimize && !optimize_size
-         && TREE_CODE (type) == REAL_TYPE
-         && !real_onep (TREE_OPERAND (exp, 0)))
-        return expand_expr (build2 (MULT_EXPR, type, TREE_OPERAND (exp, 0),
-                                   build2 (RDIV_EXPR, type,
-                                           build_real (type, dconst1),
-                                           TREE_OPERAND (exp, 1))),
-                           target, tmode, modifier);
-
       goto binop;
 
     case TRUNC_MOD_EXPR:
@@ -7687,21 +7950,67 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       /* At this point, a MEM target is no longer useful; we will get better
         code without it.  */
 
-      if (MEM_P (target))
+      if (! REG_P (target))
        target = gen_reg_rtx (mode);
 
       /* If op1 was placed in target, swap op0 and op1.  */
       if (target != op0 && target == op1)
        {
-         rtx tem = op0;
+         temp = op0;
          op0 = op1;
-         op1 = tem;
+         op1 = temp;
        }
 
+      /* We generate better code and avoid problems with op1 mentioning
+        target by forcing op1 into a pseudo if it isn't a constant.  */
+      if (! CONSTANT_P (op1))
+       op1 = force_reg (mode, op1);
+
+#ifdef HAVE_conditional_move
+      /* Use a conditional move if possible.  */
+      if (can_conditionally_move_p (mode))
+       {
+         enum rtx_code comparison_code;
+         rtx insn;
+
+         if (code == MAX_EXPR)
+           comparison_code = unsignedp ? GEU : GE;
+         else
+           comparison_code = unsignedp ? LEU : LE;
+
+         /* ??? Same problem as in expmed.c: emit_conditional_move
+            forces a stack adjustment via compare_from_rtx, and we
+            lose the stack adjustment if the sequence we are about
+            to create is discarded.  */
+         do_pending_stack_adjust ();
+
+         start_sequence ();
+
+         /* Try to emit the conditional move.  */
+         insn = emit_conditional_move (target, comparison_code,
+                                       op0, op1, mode,
+                                       op0, op1, mode,
+                                       unsignedp);
+
+         /* If we could do the conditional move, emit the sequence,
+            and return.  */
+         if (insn)
+           {
+             rtx seq = get_insns ();
+             end_sequence ();
+             emit_insn (seq);
+             return target;
+           }
+
+         /* Otherwise discard the sequence and fall back to code with
+            branches.  */
+         end_sequence ();
+       }
+#endif
       if (target != op0)
        emit_move_insn (target, op0);
 
-      op0 = gen_label_rtx ();
+      temp = gen_label_rtx ();
 
       /* If this mode is an integer too wide to compare properly,
         compare word by word.  Rely on cse to optimize constant cases.  */
@@ -7710,18 +8019,18 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
        {
          if (code == MAX_EXPR)
            do_jump_by_parts_greater_rtx (mode, unsignedp, target, op1,
-                                         NULL_RTX, op0);
+                                         NULL_RTX, temp);
          else
            do_jump_by_parts_greater_rtx (mode, unsignedp, op1, target,
-                                         NULL_RTX, op0);
+                                         NULL_RTX, temp);
        }
       else
        {
          do_compare_rtx_and_jump (target, op1, code == MAX_EXPR ? GE : LE,
-                                  unsignedp, mode, NULL_RTX, NULL_RTX, op0);
+                                  unsignedp, mode, NULL_RTX, NULL_RTX, temp);
        }
       emit_move_insn (target, op1);
-      emit_label (op0);
+      emit_label (temp);
       return target;
 
     case BIT_NOT_EXPR:
@@ -7881,21 +8190,10 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       return const0_rtx;
 
     case COND_EXPR:
-      /* If it's void, we don't need to worry about computing a value.  */
-      if (VOID_TYPE_P (TREE_TYPE (exp)))
-       {
-         tree pred = TREE_OPERAND (exp, 0);
-         tree then_ = TREE_OPERAND (exp, 1);
-         tree else_ = TREE_OPERAND (exp, 2);
-
-         gcc_assert (TREE_CODE (then_) == GOTO_EXPR
-                     && TREE_CODE (GOTO_DESTINATION (then_)) == LABEL_DECL
-                     && TREE_CODE (else_) == GOTO_EXPR
-                     && TREE_CODE (GOTO_DESTINATION (else_)) == LABEL_DECL);
-
-         jumpif (pred, label_rtx (GOTO_DESTINATION (then_)));
-         return expand_expr (else_, const0_rtx, VOIDmode, 0);
-       }
+      /* A COND_EXPR with its type being VOID_TYPE represents a
+        conditional jump and is handled in
+        expand_gimple_cond_expr.  */
+      gcc_assert (!VOID_TYPE_P (TREE_TYPE (exp)));
 
         /* Note that COND_EXPRs whose type is a structure or union
         are required to be constructed to contain assignments of
@@ -7999,47 +8297,27 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
     case ADDR_EXPR:
       return expand_expr_addr_expr (exp, target, tmode, modifier);
 
-    /* COMPLEX type for Extended Pascal & Fortran  */
     case COMPLEX_EXPR:
-      {
-       enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
-       rtx insns;
-
-       /* Get the rtx code of the operands.  */
-       op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
-       op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
-
-       if (! target)
-         target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
-
-       start_sequence ();
-
-       /* Move the real (op0) and imaginary (op1) parts to their location.  */
-       emit_move_insn (gen_realpart (mode, target), op0);
-       emit_move_insn (gen_imagpart (mode, target), op1);
+      /* Get the rtx code of the operands.  */
+      op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
+      op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
 
-       insns = get_insns ();
-       end_sequence ();
+      if (!target)
+       target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
 
-       /* Complex construction should appear as a single unit.  */
-       /* If TARGET is a CONCAT, we got insns like RD = RS, ID = IS,
-          each with a separate pseudo as destination.
-          It's not correct for flow to treat them as a unit.  */
-       if (GET_CODE (target) != CONCAT)
-         emit_no_conflict_block (insns, target, op0, op1, NULL_RTX);
-       else
-         emit_insn (insns);
+      /* Move the real (op0) and imaginary (op1) parts to their location.  */
+      write_complex_part (target, op0, false);
+      write_complex_part (target, op1, true);
 
-       return target;
-      }
+      return target;
 
     case REALPART_EXPR:
       op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
-      return gen_realpart (mode, op0);
+      return read_complex_part (op0, false);
 
     case IMAGPART_EXPR:
       op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
-      return gen_imagpart (mode, op0);
+      return read_complex_part (op0, true);
 
     case RESX_EXPR:
       expand_resx_expr (exp);
@@ -8067,8 +8345,6 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
     case POSTDECREMENT_EXPR:
     case LOOP_EXPR:
     case EXIT_EXPR:
-    case LABELED_BLOCK_EXPR:
-    case EXIT_BLOCK_EXPR:
     case TRUTH_ANDIF_EXPR:
     case TRUTH_ORIF_EXPR:
       /* Lowered by gimplify.c.  */
@@ -8115,11 +8391,27 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
         op2 = expand_expr (oprnd2, NULL_RTX, VOIDmode, 0);
         temp = expand_ternary_op (mode, this_optab, op0, op1, op2, 
                                  target, unsignedp);
-        if (temp == 0)
-          abort ();
+        gcc_assert (temp);
         return temp;
       }
 
+    case REDUC_MAX_EXPR:
+    case REDUC_MIN_EXPR:
+    case REDUC_PLUS_EXPR:
+      {
+        op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
+        this_optab = optab_for_tree_code (code, type);
+        temp = expand_unop (mode, this_optab, op0, target, unsignedp);
+        gcc_assert (temp);
+        return temp;
+      }
+
+    case VEC_LSHIFT_EXPR:
+    case VEC_RSHIFT_EXPR:
+      {
+       target = expand_vec_shift_expr (exp, target);
+       return target;
+      }
 
     default:
       return lang_hooks.expand_expr (exp, original_target, tmode,
@@ -8501,8 +8793,7 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
       if ((code == LT && integer_zerop (arg1))
          || (! only_cheap && code == GE && integer_zerop (arg1)))
        ;
-      else if (BRANCH_COST >= 0
-              && ! only_cheap && (code == NE || code == EQ)
+      else if (! only_cheap && (code == NE || code == EQ)
               && TREE_CODE (type) != REAL_TYPE
               && ((abs_optab->handlers[(int) operand_mode].insn_code
                    != CODE_FOR_nothing)
@@ -8746,9 +9037,9 @@ try_tablejump (tree index_type, tree index_expr, tree minval, tree range,
   if (! HAVE_tablejump)
     return 0;
 
-  index_expr = fold (build2 (MINUS_EXPR, index_type,
-                            convert (index_type, index_expr),
-                            convert (index_type, minval)));
+  index_expr = fold_build2 (MINUS_EXPR, index_type,
+                           convert (index_type, index_expr),
+                           convert (index_type, minval));
   index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
   do_pending_stack_adjust ();