OSDN Git Service

2008-06-15 Mark Shinwell <shinwell@codesourcery.com>
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index bfc6b68..2357170 100644 (file)
@@ -1,12 +1,13 @@
 /* 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, 2006, 2007
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -15,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 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.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -52,6 +52,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "tree-flow.h"
 #include "target.h"
 #include "timevar.h"
+#include "df.h"
+#include "diagnostic.h"
 
 /* Decide whether a function's arguments should be processed
    from first to last or from last to first.
@@ -125,8 +127,7 @@ static unsigned HOST_WIDE_INT move_by_pieces_ninsns (unsigned HOST_WIDE_INT,
 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 bool emit_block_move_via_movmem (rtx, rtx, rtx, unsigned, unsigned, HOST_WIDE_INT);
 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,22 +135,19 @@ 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 tree clear_storage_libcall_fn (int);
 static rtx compress_float_constant (rtx, rtx);
 static rtx get_subtarget (rtx);
 static void store_constructor_field (rtx, unsigned HOST_WIDE_INT,
                                     HOST_WIDE_INT, enum machine_mode,
-                                    tree, tree, int, int);
+                                    tree, tree, int, alias_set_type);
 static void store_constructor (tree, rtx, int, HOST_WIDE_INT);
 static rtx store_field (rtx, HOST_WIDE_INT, HOST_WIDE_INT, enum machine_mode,
-                       tree, tree, int);
+                       tree, tree, alias_set_type, bool);
 
-static unsigned HOST_WIDE_INT highest_pow2_factor (tree);
-static unsigned HOST_WIDE_INT highest_pow2_factor_for_target (tree, tree);
+static unsigned HOST_WIDE_INT highest_pow2_factor_for_target (const_tree, const_tree);
 
-static int is_aligning_offset (tree, tree);
+static int is_aligning_offset (const_tree, const_tree);
 static void expand_operands (tree, tree, rtx, rtx*, rtx*,
                             enum expand_modifier);
 static rtx reduce_to_bit_field_precision (rtx, rtx, 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
@@ -188,8 +187,15 @@ static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
 #endif
 
 /* This macro is used to determine whether store_by_pieces should be
-   called to "memset" storage with byte values other than zero, or
-   to "memcpy" storage when the source is a constant string.  */
+   called to "memset" storage with byte values other than zero.  */
+#ifndef SET_BY_PIECES_P
+#define SET_BY_PIECES_P(SIZE, ALIGN) \
+  (move_by_pieces_ninsns (SIZE, ALIGN, STORE_MAX_PIECES + 1) \
+   < (unsigned int) SET_RATIO)
+#endif
+
+/* This macro is used to determine whether store_by_pieces should be
+   called to "memcpy" storage when the source is a constant string.  */
 #ifndef STORE_BY_PIECES_P
 #define STORE_BY_PIECES_P(SIZE, ALIGN) \
   (move_by_pieces_ninsns (SIZE, ALIGN, STORE_MAX_PIECES + 1) \
@@ -199,25 +205,51 @@ 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
 #define SLOW_UNALIGNED_ACCESS(MODE, ALIGN) STRICT_ALIGNMENT
 #endif
 \f
-/* This is run once per compilation to set up which modes can be used
-   directly in memory and to initialize the block move optab.  */
+/* This is run to set up which modes can be used
+   directly in memory and to initialize the block move optab.  It is run
+   at the beginning of compilation and when the target is reinitialized.  */
 
 void
-init_expr_once (void)
+init_expr_target (void)
 {
   rtx insn, pat;
   enum machine_mode mode;
@@ -260,7 +292,7 @@ init_expr_once (void)
            if (! HARD_REGNO_MODE_OK (regno, mode))
              continue;
 
-           REGNO (reg) = regno;
+           SET_REGNO (reg, regno);
 
            SET_SRC (pat) = mem;
            SET_DEST (pat) = reg;
@@ -312,11 +344,12 @@ init_expr_once (void)
 void
 init_expr (void)
 {
-  cfun->expr = ggc_alloc_cleared (sizeof (struct expr_status));
+  memset (&crtl->expr, 0, sizeof (crtl->expr));
 }
 \f
 /* Copy data from FROM to TO, where the machine modes are not the same.
-   Both modes may be integer, or both may be floating.
+   Both modes may be integer, or both may be floating, or both may be
+   fixed-point.
    UNSIGNEDP should be nonzero if FROM is an unsigned type.
    This causes zero-extension instead of sign-extension.  */
 
@@ -325,8 +358,8 @@ convert_move (rtx to, rtx from, int unsignedp)
 {
   enum machine_mode to_mode = GET_MODE (to);
   enum machine_mode from_mode = GET_MODE (from);
-  int to_real = GET_MODE_CLASS (to_mode) == MODE_FLOAT;
-  int from_real = GET_MODE_CLASS (from_mode) == MODE_FLOAT;
+  int to_real = SCALAR_FLOAT_MODE_P (to_mode);
+  int from_real = SCALAR_FLOAT_MODE_P (from_mode);
   enum insn_code code;
   rtx libcall;
 
@@ -336,6 +369,8 @@ convert_move (rtx to, rtx from, int unsignedp)
 
 
   gcc_assert (to_real == from_real);
+  gcc_assert (to_mode != BLKmode);
+  gcc_assert (from_mode != BLKmode);
 
   /* If the source and destination are already the same, then there's
      nothing to do.  */
@@ -386,17 +421,22 @@ convert_move (rtx to, rtx from, int unsignedp)
       rtx value, insns;
       convert_optab tab;
 
-      gcc_assert (GET_MODE_PRECISION (from_mode)
-                 != GET_MODE_PRECISION (to_mode));
-      
-      if (GET_MODE_PRECISION (from_mode) < GET_MODE_PRECISION (to_mode))
+      gcc_assert ((GET_MODE_PRECISION (from_mode)
+                  != GET_MODE_PRECISION (to_mode))
+                 || (DECIMAL_FLOAT_MODE_P (from_mode)
+                     != DECIMAL_FLOAT_MODE_P (to_mode)));
+
+      if (GET_MODE_PRECISION (from_mode) == GET_MODE_PRECISION (to_mode))
+       /* Conversion between decimal float and binary float, same size.  */
+       tab = DECIMAL_FLOAT_MODE_P (from_mode) ? trunc_optab : sext_optab;
+      else if (GET_MODE_PRECISION (from_mode) < GET_MODE_PRECISION (to_mode))
        tab = sext_optab;
       else
        tab = trunc_optab;
 
       /* Try converting directly if the insn is supported.  */
 
-      code = tab->handlers[to_mode][from_mode].insn_code;
+      code = convert_optab_handler (tab, to_mode, from_mode)->insn_code;
       if (code != CODE_FOR_nothing)
        {
          emit_unop_insn (code, to, from,
@@ -405,7 +445,7 @@ convert_move (rtx to, rtx from, int unsignedp)
        }
 
       /* Otherwise use a libcall.  */
-      libcall = tab->handlers[to_mode][from_mode].libfunc;
+      libcall = convert_optab_libfunc (tab, to_mode, from_mode);
 
       /* Is this conversion implemented yet?  */
       gcc_assert (libcall);
@@ -430,30 +470,54 @@ convert_move (rtx to, rtx from, int unsignedp)
       enum machine_mode full_mode
        = smallest_mode_for_size (GET_MODE_BITSIZE (to_mode), MODE_INT);
 
-      gcc_assert (trunc_optab->handlers[to_mode][full_mode].insn_code
+      gcc_assert (convert_optab_handler (trunc_optab, to_mode, full_mode)->insn_code
                  != CODE_FOR_nothing);
 
       if (full_mode != from_mode)
        from = convert_to_mode (full_mode, from, unsignedp);
-      emit_unop_insn (trunc_optab->handlers[to_mode][full_mode].insn_code,
+      emit_unop_insn (convert_optab_handler (trunc_optab, to_mode, full_mode)->insn_code,
                      to, from, UNKNOWN);
       return;
     }
   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
+      gcc_assert (convert_optab_handler (sext_optab, 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 (convert_optab_handler (sext_optab, full_mode, from_mode)->insn_code,
+                         to, from, UNKNOWN);
+         return;
+       }
+
+      new_from = gen_reg_rtx (full_mode);
+      emit_unop_insn (convert_optab_handler (sext_optab, full_mode, from_mode)->insn_code,
+                     new_from, from, UNKNOWN);
 
       /* else proceed to integer conversions below.  */
       from_mode = full_mode;
+      from = new_from;
+    }
+
+   /* Make sure both are fixed-point modes or both are not.  */
+   gcc_assert (ALL_SCALAR_FIXED_POINT_MODE_P (from_mode) ==
+              ALL_SCALAR_FIXED_POINT_MODE_P (to_mode));
+   if (ALL_SCALAR_FIXED_POINT_MODE_P (from_mode))
+    {
+      /* If we widen from_mode to to_mode and they are in the same class,
+        we won't saturate the result.
+        Otherwise, always saturate the result to play safe.  */
+      if (GET_MODE_CLASS (from_mode) == GET_MODE_CLASS (to_mode)
+         && GET_MODE_SIZE (from_mode) < GET_MODE_SIZE (to_mode))
+       expand_fixed_convert (to, from, 0, 0);
+      else
+       expand_fixed_convert (to, from, 0, 1);
+      return;
     }
 
   /* Now both modes are integers.  */
@@ -488,15 +552,15 @@ convert_move (rtx to, rtx from, int unsignedp)
               && ((code = can_extend_p (to_mode, word_mode, unsignedp))
                   != CODE_FOR_nothing))
        {
+         rtx word_to = gen_reg_rtx (word_mode);
          if (REG_P (to))
            {
              if (reg_overlap_mentioned_p (to, from))
                from = force_reg (from_mode, from);
-             emit_insn (gen_rtx_CLOBBER (VOIDmode, to));
+             emit_clobber (to);
            }
-         convert_move (gen_lowpart (word_mode, to), from, unsignedp);
-         emit_unop_insn (code, to,
-                         gen_lowpart (word_mode, to), equiv_code);
+         convert_move (word_to, from, unsignedp);
+         emit_unop_insn (code, to, word_to, equiv_code);
          return;
        }
 
@@ -561,8 +625,7 @@ convert_move (rtx to, rtx from, int unsignedp)
       insns = get_insns ();
       end_sequence ();
 
-      emit_no_conflict_block (insns, to, from, NULL_RTX,
-                             gen_rtx_fmt_e (equiv_code, to_mode, copy_rtx (from)));
+      emit_insn (insns);
       return;
     }
 
@@ -610,9 +673,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;
        }
@@ -655,9 +715,9 @@ convert_move (rtx to, rtx from, int unsignedp)
     }
 
   /* Support special truncate insns for certain modes.  */
-  if (trunc_optab->handlers[to_mode][from_mode].insn_code != CODE_FOR_nothing)
+  if (convert_optab_handler (trunc_optab, to_mode, from_mode)->insn_code != CODE_FOR_nothing)
     {
-      emit_unop_insn (trunc_optab->handlers[to_mode][from_mode].insn_code,
+      emit_unop_insn (convert_optab_handler (trunc_optab, to_mode, from_mode)->insn_code,
                      to, from, UNKNOWN);
       return;
     }
@@ -949,7 +1009,7 @@ move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len,
       if (mode == VOIDmode)
        break;
 
-      icode = mov_optab->handlers[(int) mode].insn_code;
+      icode = optab_handler (mov_optab, mode)->insn_code;
       if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode))
        move_by_pieces_1 (GEN_FCN (icode), mode, &data);
 
@@ -1029,7 +1089,7 @@ move_by_pieces_ninsns (unsigned HOST_WIDE_INT l, unsigned int align,
       if (mode == VOIDmode)
        break;
 
-      icode = mov_optab->handlers[(int) mode].insn_code;
+      icode = optab_handler (mov_optab, mode)->insn_code;
       if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode))
        n_insns += l / GET_MODE_SIZE (mode), l %= GET_MODE_SIZE (mode);
 
@@ -1114,7 +1174,8 @@ move_by_pieces_1 (rtx (*genfun) (rtx, ...), enum machine_mode mode,
    0 otherwise.  */
 
 rtx
-emit_block_move (rtx x, rtx y, rtx size, enum block_op_methods method)
+emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method,
+                      unsigned int expected_align, HOST_WIDE_INT expected_size)
 {
   bool may_use_call;
   rtx retval = 0;
@@ -1123,6 +1184,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;
 
@@ -1168,10 +1230,12 @@ emit_block_move (rtx x, rtx y, rtx size, enum block_op_methods method)
 
   if (GET_CODE (size) == CONST_INT && MOVE_BY_PIECES_P (INTVAL (size), align))
     move_by_pieces (x, y, INTVAL (size), align, 0);
-  else if (emit_block_move_via_movmem (x, y, size, align))
+  else if (emit_block_move_via_movmem (x, y, size, align,
+                                      expected_align, expected_size))
     ;
   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);
 
@@ -1181,6 +1245,12 @@ emit_block_move (rtx x, rtx y, rtx size, enum block_op_methods method)
   return retval;
 }
 
+rtx
+emit_block_move (rtx x, rtx y, rtx size, enum block_op_methods method)
+{
+  return emit_block_move_hints (x, y, size, method, 0, -1);
+}
+
 /* A subroutine of emit_block_move.  Returns true if calling the
    block move libcall will not clobber any parameters which may have
    already been placed on the stack.  */
@@ -1188,19 +1258,21 @@ emit_block_move (rtx x, rtx y, rtx size, enum block_op_methods method)
 static bool
 block_move_libcall_safe_for_call_parm (void)
 {
+#if defined (REG_PARM_STACK_SPACE)
+  tree fn;
+#endif
+
   /* If arguments are pushed on the stack, then they're safe.  */
   if (PUSH_ARGS)
     return true;
 
   /* If registers go on the stack anyway, any argument is sure to clobber
      an outgoing argument.  */
-#if defined (REG_PARM_STACK_SPACE) && defined (OUTGOING_REG_PARM_STACK_SPACE)
-  {
-    tree fn = emit_block_move_libcall_fn (false);
-    (void) fn;
-    if (REG_PARM_STACK_SPACE (fn) != 0)
-      return false;
-  }
+#if defined (REG_PARM_STACK_SPACE)
+  fn = emit_block_move_libcall_fn (false);
+  if (OUTGOING_REG_PARM_STACK_SPACE ((!fn ? NULL_TREE : TREE_TYPE (fn)))
+      && REG_PARM_STACK_SPACE (fn) != 0)
+    return false;
 #endif
 
   /* If any argument goes in memory, then it might clobber an outgoing
@@ -1219,8 +1291,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);
       }
@@ -1232,12 +1303,16 @@ block_move_libcall_safe_for_call_parm (void)
    return true if successful.  */
 
 static bool
-emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align)
+emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align,
+                           unsigned int expected_align, HOST_WIDE_INT expected_size)
 {
   rtx opalign = GEN_INT (align / BITS_PER_UNIT);
   int save_volatile_ok = volatile_ok;
   enum machine_mode mode;
 
+  if (expected_align < align)
+    expected_align = align;
+
   /* Since this is a move insn, we don't care about volatility.  */
   volatile_ok = 1;
 
@@ -1281,7 +1356,12 @@ emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align)
             that it doesn't fail the expansion because it thinks
             emitting the libcall would be more efficient.  */
 
-         pat = GEN_FCN ((int) code) (x, y, op2, opalign);
+         if (insn_data[(int) code].n_operands == 4)
+           pat = GEN_FCN ((int) code) (x, y, op2, opalign);
+         else
+           pat = GEN_FCN ((int) code) (x, y, op2, opalign,
+                                       GEN_INT (expected_align),
+                                       GEN_INT (expected_size));
          if (pat)
            {
              emit_insn (pat);
@@ -1300,11 +1380,11 @@ emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align)
 /* A subroutine of emit_block_move.  Expand a call to memcpy.
    Return the return value from memcpy, 0 otherwise.  */
 
-static rtx
-emit_block_move_via_libcall (rtx dst, rtx src, rtx size)
+rtx
+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;
+  tree call_expr, fn, src_tree, dst_tree, size_tree;
   enum machine_mode size_mode;
   rtx retval;
 
@@ -1335,16 +1415,10 @@ emit_block_move_via_libcall (rtx dst, rtx src, rtx size)
   size_tree = make_tree (sizetype, size);
 
   fn = emit_block_move_libcall_fn (true);
-  arg_list = tree_cons (NULL_TREE, size_tree, NULL_TREE);
-  arg_list = tree_cons (NULL_TREE, src_tree, arg_list);
-  arg_list = tree_cons (NULL_TREE, dst_tree, arg_list);
-
-  /* Now we have to build up the CALL_EXPR itself.  */
-  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 = build_call_expr (fn, 3, dst_tree, src_tree, size_tree);
+  CALL_EXPR_TAILCALL (call_expr) = tailcall;
 
-  retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
+  retval = expand_normal (call_expr);
 
   return retval;
 }
@@ -1372,6 +1446,8 @@ init_block_move_fn (const char *asmspec)
       TREE_PUBLIC (fn) = 1;
       DECL_ARTIFICIAL (fn) = 1;
       TREE_NOTHROW (fn) = 1;
+      DECL_VISIBILITY (fn) = VISIBILITY_DEFAULT;
+      DECL_VISIBILITY_SPECIFIED (fn) = 1;
 
       block_move_fn = fn;
     }
@@ -1650,6 +1726,11 @@ emit_group_load_1 (rtx *tmps, rtx dst, rtx orig_src, tree type, 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));
@@ -1696,8 +1777,25 @@ emit_group_load_1 (rtx *tmps, rtx dst, rtx orig_src, tree type, int ssize)
       else if (CONSTANT_P (src) && GET_MODE (dst) != BLKmode
                && XVECLEN (dst, 0) > 1)
         tmps[i] = simplify_gen_subreg (mode, src, GET_MODE(dst), bytepos);
-      else if (CONSTANT_P (src)
-              || (REG_P (src) && GET_MODE (src) == mode))
+      else if (CONSTANT_P (src))
+       {
+         HOST_WIDE_INT len = (HOST_WIDE_INT) bytelen;
+
+         if (len == ssize)
+           tmps[i] = src;
+         else
+           {
+             rtx first, second;
+
+             gcc_assert (2 * len == ssize);
+             split_double (src, &first, &second);
+             if (i)
+               tmps[i] = second;
+             else
+               tmps[i] = first;
+           }
+       }
+      else if (REG_P (src) && GET_MODE (src) == mode)
        tmps[i] = src;
       else
        tmps[i] = extract_bit_field (src, bytelen * BITS_PER_UNIT,
@@ -1813,7 +1911,7 @@ void
 emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
 {
   rtx *tmps, dst;
-  int start, i;
+  int start, finish, i;
   enum machine_mode m = GET_MODE (orig_dst);
 
   gcc_assert (GET_CODE (src) == PARALLEL);
@@ -1839,15 +1937,21 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
     start = 0;
   else
     start = 1;
+  finish = XVECLEN (src, 0);
 
-  tmps = alloca (sizeof (rtx) * XVECLEN (src, 0));
+  tmps = alloca (sizeof (rtx) * finish);
 
   /* Copy the (probable) hard regs into pseudos.  */
-  for (i = start; i < XVECLEN (src, 0); i++)
+  for (i = start; i < finish; i++)
     {
       rtx reg = XEXP (XVECEXP (src, 0, i), 0);
-      tmps[i] = gen_reg_rtx (GET_MODE (reg));
-      emit_move_insn (tmps[i], reg);
+      if (!REG_P (reg) || REGNO (reg) < FIRST_PSEUDO_REGISTER)
+       {
+         tmps[i] = gen_reg_rtx (GET_MODE (reg));
+         emit_move_insn (tmps[i], reg);
+       }
+      else
+       tmps[i] = reg;
     }
 
   /* If we won't be storing directly into memory, protect the real destination
@@ -1874,13 +1978,62 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
     }
   else if (!MEM_P (dst) && GET_CODE (dst) != CONCAT)
     {
-      dst = gen_reg_rtx (GET_MODE (orig_dst));
+      enum machine_mode outer = GET_MODE (dst);
+      enum machine_mode inner;
+      HOST_WIDE_INT bytepos;
+      bool done = false;
+      rtx temp;
+
+      if (!REG_P (dst) || REGNO (dst) < FIRST_PSEUDO_REGISTER)
+       dst = gen_reg_rtx (outer);
+
       /* Make life a bit easier for combine.  */
-      emit_move_insn (dst, CONST0_RTX (GET_MODE (orig_dst)));
+      /* If the first element of the vector is the low part
+        of the destination mode, use a paradoxical subreg to
+        initialize the destination.  */
+      if (start < finish)
+       {
+         inner = GET_MODE (tmps[start]);
+         bytepos = subreg_lowpart_offset (inner, outer);
+         if (INTVAL (XEXP (XVECEXP (src, 0, start), 1)) == bytepos)
+           {
+             temp = simplify_gen_subreg (outer, tmps[start],
+                                         inner, 0);
+             if (temp)
+               {
+                 emit_move_insn (dst, temp);
+                 done = true;
+                 start++;
+               }
+           }
+       }
+
+      /* If the first element wasn't the low part, try the last.  */
+      if (!done
+         && start < finish - 1)
+       {
+         inner = GET_MODE (tmps[finish - 1]);
+         bytepos = subreg_lowpart_offset (inner, outer);
+         if (INTVAL (XEXP (XVECEXP (src, 0, finish - 1), 1)) == bytepos)
+           {
+             temp = simplify_gen_subreg (outer, tmps[finish - 1],
+                                         inner, 0);
+             if (temp)
+               {
+                 emit_move_insn (dst, temp);
+                 done = true;
+                 finish--;
+               }
+           }
+       }
+
+      /* Otherwise, simply initialize the result to zero.  */
+      if (!done)
+        emit_move_insn (dst, CONST0_RTX (outer));
     }
 
   /* Process the pieces.  */
-  for (i = start; i < XVECLEN (src, 0); i++)
+  for (i = start; i < finish; i++)
     {
       HOST_WIDE_INT bytepos = INTVAL (XEXP (XVECEXP (src, 0, i), 1));
       enum machine_mode mode = GET_MODE (tmps[i]);
@@ -1963,6 +2116,7 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
   rtx src = NULL, dst = NULL;
   unsigned HOST_WIDE_INT bitsize = MIN (TYPE_ALIGN (type), BITS_PER_WORD);
   unsigned HOST_WIDE_INT bitpos, xbitpos, padding_correction = 0;
+  enum machine_mode copy_mode;
 
   if (tgtblk == 0)
     {
@@ -1996,11 +2150,23 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
     padding_correction
       = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD) * BITS_PER_UNIT));
 
-  /* Copy the structure BITSIZE bites at a time.
+  /* Copy the structure BITSIZE bits at a time.  If the target lives in
+     memory, take care of not reading/writing past its end by selecting
+     a copy mode suited to BITSIZE.  This should always be possible given
+     how it is computed.
 
      We could probably emit more efficient code for machines which do not use
      strict alignment, but it doesn't seem worth the effort at the current
      time.  */
+
+  copy_mode = word_mode;
+  if (MEM_P (tgtblk))
+    {
+      enum machine_mode mem_mode = mode_for_size (bitsize, MODE_INT, 1);
+      if (mem_mode != BLKmode)
+       copy_mode = mem_mode;
+    }
+
   for (bitpos = 0, xbitpos = padding_correction;
        bitpos < bytes * BITS_PER_UNIT;
        bitpos += bitsize, xbitpos += bitsize)
@@ -2019,11 +2185,11 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
        dst = operand_subword (tgtblk, bitpos / BITS_PER_WORD, 1, BLKmode);
 
       /* Use xbitpos for the source extraction (right justified) and
-        xbitpos for the destination store (left justified).  */
-      store_bit_field (dst, bitsize, bitpos % BITS_PER_WORD, word_mode,
+        bitpos for the destination store (left justified).  */
+      store_bit_field (dst, bitsize, bitpos % BITS_PER_WORD, copy_mode,
                       extract_bit_field (src, bitsize,
                                          xbitpos % BITS_PER_WORD, 1,
-                                         NULL_RTX, word_mode, word_mode));
+                                         NULL_RTX, copy_mode, copy_mode));
     }
 
   return tgtblk;
@@ -2036,7 +2202,7 @@ void
 use_reg (rtx *call_fusage, rtx reg)
 {
   gcc_assert (REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER);
-  
+
   *call_fusage
     = gen_rtx_EXPR_LIST (VOIDmode,
                         gen_rtx_USE (VOIDmode, reg), *call_fusage);
@@ -2081,13 +2247,14 @@ use_group_regs (rtx *call_fusage, rtx regs)
 /* Determine whether the LEN bytes generated by CONSTFUN can be
    stored to memory using several move instructions.  CONSTFUNDATA is
    a pointer which will be passed as argument in every CONSTFUN call.
-   ALIGN is maximum alignment we can assume.  Return nonzero if a
-   call to store_by_pieces should succeed.  */
+   ALIGN is maximum alignment we can assume.  MEMSETP is true if this is
+   a memset operation and false if it's a copy of a constant string.
+   Return nonzero if a call to store_by_pieces should succeed.  */
 
 int
 can_store_by_pieces (unsigned HOST_WIDE_INT len,
                     rtx (*constfun) (void *, HOST_WIDE_INT, enum machine_mode),
-                    void *constfundata, unsigned int align)
+                    void *constfundata, unsigned int align, bool memsetp)
 {
   unsigned HOST_WIDE_INT l;
   unsigned int max_size;
@@ -2100,7 +2267,9 @@ can_store_by_pieces (unsigned HOST_WIDE_INT len,
   if (len == 0)
     return 1;
 
-  if (! STORE_BY_PIECES_P (len, align))
+  if (! (memsetp 
+        ? SET_BY_PIECES_P (len, align)
+        : STORE_BY_PIECES_P (len, align)))
     return 0;
 
   tmode = mode_for_size (STORE_MAX_PIECES * BITS_PER_UNIT, MODE_INT, 1);
@@ -2140,7 +2309,7 @@ can_store_by_pieces (unsigned HOST_WIDE_INT len,
          if (mode == VOIDmode)
            break;
 
-         icode = mov_optab->handlers[(int) mode].insn_code;
+         icode = optab_handler (mov_optab, mode)->insn_code;
          if (icode != CODE_FOR_nothing
              && align >= GET_MODE_ALIGNMENT (mode))
            {
@@ -2175,7 +2344,8 @@ can_store_by_pieces (unsigned HOST_WIDE_INT len,
 /* Generate several move instructions to store LEN bytes generated by
    CONSTFUN to block TO.  (A MEM rtx with BLKmode).  CONSTFUNDATA is a
    pointer which will be passed as argument in every CONSTFUN call.
-   ALIGN is maximum alignment we can assume.
+   ALIGN is maximum alignment we can assume.  MEMSETP is true if this is
+   a memset operation and false if it's a copy of a constant string.
    If ENDP is 0 return to, if ENDP is 1 return memory at the end ala
    mempcpy, and if ENDP is 2 return memory the end minus one byte ala
    stpcpy.  */
@@ -2183,7 +2353,7 @@ can_store_by_pieces (unsigned HOST_WIDE_INT len,
 rtx
 store_by_pieces (rtx to, unsigned HOST_WIDE_INT len,
                 rtx (*constfun) (void *, HOST_WIDE_INT, enum machine_mode),
-                void *constfundata, unsigned int align, int endp)
+                void *constfundata, unsigned int align, bool memsetp, int endp)
 {
   struct store_by_pieces data;
 
@@ -2193,7 +2363,9 @@ store_by_pieces (rtx to, unsigned HOST_WIDE_INT len,
       return to;
     }
 
-  gcc_assert (STORE_BY_PIECES_P (len, align));
+  gcc_assert (memsetp
+             ? SET_BY_PIECES_P (len, align)
+             : STORE_BY_PIECES_P (len, align));
   data.constfun = constfun;
   data.constfundata = constfundata;
   data.len = len;
@@ -2344,7 +2516,7 @@ store_by_pieces_1 (struct store_by_pieces *data ATTRIBUTE_UNUSED,
       if (mode == VOIDmode)
        break;
 
-      icode = mov_optab->handlers[(int) mode].insn_code;
+      icode = optab_handler (mov_optab, mode)->insn_code;
       if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode))
        store_by_pieces_2 (GEN_FCN (icode), mode, data);
 
@@ -2398,97 +2570,71 @@ store_by_pieces_2 (rtx (*genfun) (rtx, ...), enum machine_mode mode,
    its length in bytes.  */
 
 rtx
-clear_storage (rtx object, rtx size)
+clear_storage_hints (rtx object, rtx size, enum block_op_methods method,
+                    unsigned int expected_align, HOST_WIDE_INT expected_size)
 {
-  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,
+                                  expected_align, expected_size))
+    ;
+  else
+    return set_storage_via_libcall (object, size, const0_rtx,
+                                   method == BLOCK_OP_TAILCALL);
+
+  return NULL;
+}
+
+rtx
+clear_storage (rtx object, rtx size, enum block_op_methods method)
+{
+  return clear_storage_hints (object, size, method, 0, -1);
 }
 
+
 /* 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)
+rtx
+set_storage_via_libcall (rtx object, rtx size, rtx val, bool tailcall)
 {
-  tree call_expr, arg_list, fn, object_tree, size_tree;
+  tree call_expr, fn, object_tree, size_tree, val_tree;
   enum machine_mode size_mode;
   rtx retval;
 
@@ -2508,24 +2654,22 @@ clear_storage_via_libcall (rtx object, rtx size)
      for returning pointers, we could end up generating incorrect code.  */
 
   object_tree = make_tree (ptr_type_node, object);
+  if (GET_CODE (val) != CONST_INT)
+    val = convert_to_mode (TYPE_MODE (integer_type_node), val, 1);
   size_tree = make_tree (sizetype, size);
+  val_tree = make_tree (integer_type_node, val);
 
   fn = clear_storage_libcall_fn (true);
-  arg_list = tree_cons (NULL_TREE, size_tree, NULL_TREE);
-  arg_list = tree_cons (NULL_TREE, integer_zero_node, arg_list);
-  arg_list = tree_cons (NULL_TREE, object_tree, arg_list);
-
-  /* Now we have to build up the CALL_EXPR itself.  */
-  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 = build_call_expr (fn, 3,
+                              object_tree, integer_zero_node, size_tree);
+  CALL_EXPR_TAILCALL (call_expr) = tailcall;
 
-  retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
+  retval = expand_normal (call_expr);
 
   return retval;
 }
 
-/* A subroutine of clear_storage_via_libcall.  Create the tree node
+/* A subroutine of set_storage_via_libcall.  Create the tree node
    for the function we use for block clears.  The first time FOR_CALL
    is true, we call assemble_external.  */
 
@@ -2548,6 +2692,8 @@ init_block_clear_fn (const char *asmspec)
       TREE_PUBLIC (fn) = 1;
       DECL_ARTIFICIAL (fn) = 1;
       TREE_NOTHROW (fn) = 1;
+      DECL_VISIBILITY (fn) = VISIBILITY_DEFAULT;
+      DECL_VISIBILITY_SPECIFIED (fn) = 1;
 
       block_clear_fn = fn;
     }
@@ -2574,6 +2720,82 @@ clear_storage_libcall_fn (int for_call)
   return block_clear_fn;
 }
 \f
+/* Expand a setmem pattern; return true if successful.  */
+
+bool
+set_storage_via_setmem (rtx object, rtx size, rtx val, unsigned int align,
+                       unsigned int expected_align, HOST_WIDE_INT expected_size)
+{
+  /* 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;
+
+  if (expected_align < align)
+    expected_align = align;
+
+  for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
+       mode = GET_MODE_WIDER_MODE (mode))
+    {
+      enum insn_code code = setmem_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[3].predicate) == 0
+             || (*pred) (opalign, VOIDmode)))
+       {
+         rtx opsize, opchar;
+         enum machine_mode char_mode;
+         rtx last = get_last_insn ();
+         rtx pat;
+
+         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);
+           }
+
+         if (insn_data[(int) code].n_operands == 4)
+           pat = GEN_FCN ((int) code) (object, opsize, opchar, opalign);
+         else
+           pat = GEN_FCN ((int) code) (object, opsize, opchar, opalign,
+                                       GEN_INT (expected_align),
+                                       GEN_INT (expected_size));
+         if (pat)
+           {
+             emit_insn (pat);
+             return true;
+           }
+         else
+           delete_insns_since (last);
+       }
+    }
+
+  return false;
+}
+
+\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.  */
 
@@ -2594,6 +2816,19 @@ write_complex_part (rtx cplx, rtx val, bool imag_p)
   imode = GET_MODE_INNER (cmode);
   ibitsize = GET_MODE_BITSIZE (imode);
 
+  /* 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
@@ -2603,13 +2838,9 @@ write_complex_part (rtx cplx, rtx val, bool imag_p)
         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.  */
-      || (GET_CODE (cplx) == REG
+      || (REG_P (cplx)
          && REGNO (cplx) < FIRST_PSEUDO_REGISTER
-         && hard_regno_nregs[REGNO (cplx)][cmode] % 2 == 0)
-      /* For MEMs we always try to make a "subreg", that is to adjust
-        the MEM, because store_bit_field may generate overly
-        convoluted RTL for sub-word fields.  */
-      || MEM_P (cplx))
+         && hard_regno_nregs[REGNO (cplx)][cmode] % 2 == 0))
     {
       rtx part = simplify_gen_subreg (imode, cplx, cmode,
                                      imag_p ? GET_MODE_SIZE (imode) : 0);
@@ -2654,6 +2885,15 @@ read_complex_part (rtx cplx, bool imag_p)
        }
     }
 
+  /* 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
@@ -2663,13 +2903,9 @@ read_complex_part (rtx cplx, bool imag_p)
         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.  */
-      || (GET_CODE (cplx) == REG
+      || (REG_P (cplx)
          && REGNO (cplx) < FIRST_PSEUDO_REGISTER
-         && hard_regno_nregs[REGNO (cplx)][cmode] % 2 == 0)
-      /* For MEMs we always try to make a "subreg", that is to adjust
-        the MEM, because extract_bit_field may generate overly
-        convoluted RTL for sub-word fields.  */
-      || MEM_P (cplx))
+         && hard_regno_nregs[REGNO (cplx)][cmode] % 2 == 0))
     {
       rtx ret = simplify_gen_subreg (imode, cplx, cmode,
                                     imag_p ? GET_MODE_SIZE (imode) : 0);
@@ -2684,64 +2920,59 @@ read_complex_part (rtx cplx, bool imag_p)
                            true, NULL_RTX, imode, imode);
 }
 \f
-/* A subroutine of emit_move_via_alt_mode.  Yet another lowpart generator.
+/* 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.  */
+   represented in NEW_MODE.  If FORCE is true, this will never happen, as
+   we'll force-create a SUBREG if needed.  */
 
 static rtx
 emit_move_change_mode (enum machine_mode new_mode,
-                      enum machine_mode old_mode, rtx x)
+                      enum machine_mode old_mode, rtx x, bool force)
 {
   rtx ret;
 
-  if (reload_in_progress && MEM_P (x))
+  if (push_operand (x, GET_MODE (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.  */
-
-      ret = adjust_address_nv (x, new_mode, 0);
-      copy_replacements (x, ret);
+      ret = gen_rtx_MEM (new_mode, XEXP (x, 0));
+      MEM_COPY_ATTRIBUTES (ret, x);
+    }
+  else if (MEM_P (x))
+    {
+      /* We don't have to worry about changing the address since the
+        size in bytes is supposed to be the same.  */
+      if (reload_in_progress)
+       {
+         /* Copy the MEM to change the mode and move any
+            substitutions from the old MEM to the new one.  */
+         ret = adjust_address_nv (x, new_mode, 0);
+         copy_replacements (x, ret);
+       }
+      else
+       ret = adjust_address (x, new_mode, 0);
     }
   else
     {
-      /* Note that we do want simplify_subreg's behaviour of validating
+      /* 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.  */
-      ret = simplify_subreg (new_mode, x, old_mode, 0);
+      /* 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
+       ret = simplify_subreg (new_mode, x, old_mode, 0);
     }
 
   return ret;
 }
 
 /* A subroutine of emit_move_insn_1.  Generate a move from Y into X using
-   ALT_MODE instead of the operand's natural mode, MODE.  CODE is the insn
-   code for the move in ALT_MODE, and is known to be valid.  Returns the
-   instruction emitted, or NULL if X or Y cannot be represented in ALT_MODE.  */
-
-static rtx
-emit_move_via_alt_mode (enum machine_mode alt_mode, enum machine_mode mode,
-                       enum insn_code code, rtx x, rtx y)
-{
-  x = emit_move_change_mode (alt_mode, mode, x);
-  if (x == NULL_RTX)
-    return NULL_RTX;
-  y = emit_move_change_mode (alt_mode, mode, y);
-  if (y == NULL_RTX)
-    return NULL_RTX;
-  return emit_insn (GEN_FCN (code) (x, y));
-}
-
-/* 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.  */
 
 static rtx
-emit_move_via_integer (enum machine_mode mode, rtx x, rtx y)
+emit_move_via_integer (enum machine_mode mode, rtx x, rtx y, bool force)
 {
   enum machine_mode imode;
   enum insn_code code;
@@ -2752,11 +2983,17 @@ emit_move_via_integer (enum machine_mode mode, rtx x, rtx y)
     return NULL_RTX;
 
   /* The target must support moves in this mode.  */
-  code = mov_optab->handlers[imode].insn_code;
+  code = optab_handler (mov_optab, imode)->insn_code;
   if (code == CODE_FOR_nothing)
     return NULL_RTX;
 
-  return emit_move_via_alt_mode (imode, mode, code, x, y);
+  x = emit_move_change_mode (imode, mode, x, force);
+  if (x == NULL_RTX)
+    return NULL_RTX;
+  y = emit_move_change_mode (imode, mode, y, force);
+  if (y == NULL_RTX)
+    return NULL_RTX;
+  return emit_insn (GEN_FCN (code) (x, y));
 }
 
 /* A subroutine of emit_move_insn_1.  X is a push_operand in MODE.
@@ -2775,6 +3012,19 @@ emit_move_resolve_push (enum machine_mode mode, rtx x)
 #endif
   if (code == PRE_DEC || code == POST_DEC)
     adjust = -adjust;
+  else if (code == PRE_MODIFY || code == POST_MODIFY)
+    {
+      rtx expr = XEXP (XEXP (x, 0), 1);
+      HOST_WIDE_INT val;
+
+      gcc_assert (GET_CODE (expr) == PLUS || GET_CODE (expr) == MINUS);
+      gcc_assert (GET_CODE (XEXP (expr, 1)) == CONST_INT);
+      val = INTVAL (XEXP (expr, 1));
+      if (GET_CODE (expr) == MINUS)
+       val = -val;
+      gcc_assert (adjust == val || adjust == -val);
+      adjust = val;
+    }
 
   /* Do not use anti_adjust_stack, since we don't want to update
      stack_pointer_delta.  */
@@ -2788,13 +3038,13 @@ emit_move_resolve_push (enum machine_mode mode, rtx x)
     {
     case PRE_INC:
     case PRE_DEC:
+    case PRE_MODIFY:
       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));
+    case POST_MODIFY:
+      temp = plus_constant (stack_pointer_rtx, -adjust);
       break;
     default:
       gcc_unreachable ();
@@ -2807,7 +3057,7 @@ emit_move_resolve_push (enum machine_mode mode, rtx x)
    X is known to satisfy push_operand, and MODE is known to be complex.
    Returns the last instruction emitted.  */
 
-static rtx
+rtx
 emit_move_complex_push (enum machine_mode mode, rtx x, rtx y)
 {
   enum machine_mode submode = GET_MODE_INNER (mode);
@@ -2847,6 +3097,25 @@ emit_move_complex_push (enum machine_mode mode, rtx x, rtx y)
                         read_complex_part (y, !imag_first));
 }
 
+/* A subroutine of emit_move_complex.  Perform the move from Y to X
+   via two moves of the parts.  Returns the last instruction emitted.  */
+
+rtx
+emit_move_complex_parts (rtx x, rtx 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.  */
+  if (!reload_completed && !reload_in_progress
+      && REG_P (x) && !reg_overlap_mentioned_p (x, y))
+    emit_clobber (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 complex.  Returns the last instruction emitted.  */
 
@@ -2860,19 +3129,14 @@ emit_move_complex (enum machine_mode mode, rtx x, rtx y)
   if (push_operand (x, mode))
     return emit_move_complex_push (mode, x, y);
 
-  /* For memory to memory moves, optimial behaviour can be had with the
-     existing block move logic.  */
-  if (MEM_P (x) && MEM_P (y))
-    {
-      emit_block_move (x, y, GEN_INT (GET_MODE_SIZE (mode)),
-                      BLOCK_OP_NO_LIBCALL);
-      return get_last_insn ();
-    }
-
   /* 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
+      && optab_handler (mov_optab, GET_MODE_INNER (mode))->insn_code != CODE_FOR_nothing)
+    try_int = false;
   /* Not possible if the values are inherently not adjacent.  */
-  if (GET_CODE (x) == CONCAT || GET_CODE (y) == CONCAT)
+  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))
@@ -2890,21 +3154,23 @@ emit_move_complex (enum machine_mode mode, rtx x, rtx y)
 
   if (try_int)
     {
-      rtx ret = emit_move_via_integer (mode, x, y);
+      rtx ret;
+
+      /* For memory to memory moves, optimal behavior can be had with the
+        existing block move logic.  */
+      if (MEM_P (x) && MEM_P (y))
+       {
+         emit_block_move (x, y, GEN_INT (GET_MODE_SIZE (mode)),
+                          BLOCK_OP_NO_LIBCALL);
+         return get_last_insn ();
+       }
+
+      ret = emit_move_via_integer (mode, x, y, true);
       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 ();
+  return emit_move_complex_parts (x, y);
 }
 
 /* A subroutine of emit_move_insn_1.  Generate a move from Y into X.
@@ -2918,19 +3184,55 @@ emit_move_ccmode (enum machine_mode mode, rtx x, rtx y)
   /* 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;
+      enum insn_code code = optab_handler (mov_optab, CCmode)->insn_code;
       if (code != CODE_FOR_nothing)
-       return emit_move_via_alt_mode (CCmode, mode, code, x, y);
+       {
+         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));
+       }
     }
 
   /* Otherwise, find the MODE_INT mode of the same width.  */
-  ret = emit_move_via_integer (mode, x, y);
+  ret = emit_move_via_integer (mode, x, y, false);
   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
+/* Return true if word I of OP lies entirely in the
+   undefined bits of a paradoxical subreg.  */
+
+static bool
+undefined_operand_subword_p (const_rtx op, int i)
+{
+  enum machine_mode innermode, innermostmode;
+  int offset;
+  if (GET_CODE (op) != SUBREG)
+    return false;
+  innermode = GET_MODE (op);
+  innermostmode = GET_MODE (SUBREG_REG (op));
+  offset = i * UNITS_PER_WORD + SUBREG_BYTE (op);
+  /* The SUBREG_BYTE represents offset, as if the value were stored in
+     memory, except for a paradoxical subreg where we define
+     SUBREG_BYTE to be 0; undo this exception as in
+     simplify_subreg.  */
+  if (SUBREG_BYTE (op) == 0
+      && GET_MODE_SIZE (innermostmode) < GET_MODE_SIZE (innermode))
+    {
+      int difference = (GET_MODE_SIZE (innermostmode) - GET_MODE_SIZE (innermode));
+      if (WORDS_BIG_ENDIAN)
+       offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
+      if (BYTES_BIG_ENDIAN)
+       offset += difference % UNITS_PER_WORD;
+    }
+  if (offset >= GET_MODE_SIZE (innermostmode)
+      || offset <= -GET_MODE_SIZE (word_mode))
+    return true;
+  return false;
+}
+
+/* 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.  */
 
@@ -2941,9 +3243,9 @@ emit_move_multi_word (enum machine_mode mode, rtx x, rtx y)
   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))
@@ -2966,14 +3268,21 @@ emit_move_multi_word (enum machine_mode mode, rtx x, rtx y)
        i++)
     {
       rtx xpart = operand_subword (x, i, 1, mode);
-      rtx ypart = operand_subword (y, i, 1, mode);
+      rtx ypart;
+
+      /* Do not generate code for a move if it would come entirely
+        from the undefined bits of a paradoxical subreg.  */
+      if (undefined_operand_subword_p (y, i))
+       continue;
+
+      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.  If we still
-        can't get a part of Y, abort.  */
+        constant.  Otherwise, force it into a register.  Then we must
+        be able to get a part of Y.  */
       if (ypart == 0 && CONSTANT_P (y))
        {
-         y = force_const_mem (mode, y);
+         y = use_anchored_address (force_const_mem (mode, y));
          ypart = operand_subword (y, i, 1, mode);
        }
       else if (ypart == 0)
@@ -2996,7 +3305,7 @@ emit_move_multi_word (enum machine_mode mode, rtx x, rtx y)
   if (x != y
       && ! (reload_in_progress || reload_completed)
       && need_clobber != 0)
-    emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
+    emit_clobber (x);
 
   emit_insn (seq);
 
@@ -3015,7 +3324,7 @@ emit_move_insn_1 (rtx x, rtx y)
 
   gcc_assert ((unsigned int) mode < (unsigned int) MAX_MACHINE_MODE);
 
-  code = mov_optab->handlers[mode].insn_code;
+  code = optab_handler (mov_optab, mode)->insn_code;
   if (code != CODE_FOR_nothing)
     return emit_insn (GEN_FCN (code) (x, y));
 
@@ -3023,6 +3332,18 @@ emit_move_insn_1 (rtx x, rtx y)
   if (COMPLEX_MODE_P (mode))
     return emit_move_complex (mode, x, y);
 
+  if (GET_MODE_CLASS (mode) == MODE_DECIMAL_FLOAT
+      || ALL_FIXED_POINT_MODE_P (mode))
+    {
+      rtx result = emit_move_via_integer (mode, x, y, true);
+
+      /* If we can't find an integer mode, use multi words.  */
+      if (result)
+       return result;
+      else
+       return emit_move_multi_word (mode, x, y);
+    }
+
   if (GET_MODE_CLASS (mode) == MODE_CC)
     return emit_move_ccmode (mode, x, y);
 
@@ -3032,7 +3353,7 @@ emit_move_insn_1 (rtx x, rtx y)
      fits within a HOST_WIDE_INT.  */
   if (!CONSTANT_P (y) || GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
     {
-      rtx ret = emit_move_via_integer (mode, x, y);
+      rtx ret = emit_move_via_integer (mode, x, y, false);
       if (ret)
        return ret;
     }
@@ -3075,22 +3396,20 @@ emit_move_insn (rtx x, rtx y)
             of the non-legitimate constant.  */
          if (!y)
            y = y_cst;
+         else
+           y = use_anchored_address (y);
        }
     }
 
   /* 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)))))
+      && (! memory_address_p (GET_MODE (x), XEXP (x, 0))
+         && ! push_operand (x, GET_MODE (x))))
     x = validize_mem (x);
 
   if (MEM_P (y)
-      && (! memory_address_p (GET_MODE (y), XEXP (y, 0))
-         || (flag_force_addr
-             && CONSTANT_ADDRESS_P (XEXP (y, 0)))))
+      && ! memory_address_p (GET_MODE (y), XEXP (y, 0)))
     y = validize_mem (y);
 
   gcc_assert (mode != BLKmode);
@@ -3117,9 +3436,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))
@@ -3144,12 +3469,27 @@ 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;
 
+      /* For CSE's benefit, force the compressed constant pool entry
+        into a new pseudo.  This constant may be used in different modes,
+        and if not, combine will put things back together for us.  */
+      trunc_y = force_reg (srcmode, trunc_y);
       emit_unop_insn (ic, x, trunc_y, UNKNOWN);
       last_insn = get_last_insn ();
 
@@ -3233,7 +3573,7 @@ emit_single_push_insn (enum machine_mode mode, rtx x, tree type)
   stack_pointer_delta += PUSH_ROUNDING (GET_MODE_SIZE (mode));
   /* If there is push pattern, use it.  Otherwise try old way of throwing
      MEM representing push operation to move expander.  */
-  icode = push_optab->handlers[(int) mode].insn_code;
+  icode = optab_handler (push_optab, mode)->insn_code;
   if (icode != CODE_FOR_nothing)
     {
       if (((pred = insn_data[(int) icode].operand[0].predicate)
@@ -3319,9 +3659,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
@@ -3368,29 +3707,35 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
 
   xinner = x;
 
-  if (mode == BLKmode)
+  if (mode == BLKmode
+      || (STRICT_ALIGNMENT && align < GET_MODE_ALIGNMENT (mode)))
     {
       /* 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)
+      offset = partial % (PARM_BOUNDARY / BITS_PER_UNIT);
+      used = partial - offset;
+
+      if (mode != BLKmode)
        {
-         /* 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);
+         /* A value is to be stored in an insufficiently aligned
+            stack slot; copy via a suitably aligned slot if
+            necessary.  */
+         size = GEN_INT (GET_MODE_SIZE (mode));
+         if (!MEM_P (xinner))
+           {
+             temp = assign_temp (type, 0, 1, 1);
+             emit_move_insn (temp, xinner);
+             xinner = temp;
+           }
        }
-      else
-       offset = used % (PARM_BOUNDARY / BITS_PER_UNIT);
 
       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.  */
 
@@ -3501,9 +3846,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;
 
@@ -3521,8 +3866,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.
@@ -3606,7 +3952,10 @@ 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)
@@ -3712,7 +4061,7 @@ optimize_bitfield_assignment_op (unsigned HOST_WIDE_INT bitsize,
          && (bitsize != 1 || TREE_CODE (op1) != INTEGER_CST))
        break;
 
-      value = expand_expr (op1, NULL_RTX, str_mode, 0);
+      value = expand_expr (op1, NULL_RTX, str_mode, EXPAND_NORMAL);
       value = convert_modes (str_mode,
                             TYPE_MODE (TREE_TYPE (op1)), value,
                             TYPE_UNSIGNED (TREE_TYPE (op1)));
@@ -3741,6 +4090,41 @@ optimize_bitfield_assignment_op (unsigned HOST_WIDE_INT bitsize,
        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), EXPAND_NORMAL);
+      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;
+
     default:
       break;
     }
@@ -3749,22 +4133,26 @@ optimize_bitfield_assignment_op (unsigned HOST_WIDE_INT bitsize,
 }
 
 
-/* Expand an assignment that stores the value of FROM into TO.  */
+/* Expand an assignment that stores the value of FROM into TO.  If NONTEMPORAL
+   is true, try generating a nontemporal store.  */
 
 void
-expand_assignment (tree to, tree from)
+expand_assignment (tree to, tree from, bool nontemporal)
 {
   rtx to_rtx = 0;
   rtx result;
 
   /* Don't crash if the lhs of the assignment was erroneous.  */
-
   if (TREE_CODE (to) == ERROR_MARK)
     {
-      result = expand_expr (from, NULL_RTX, VOIDmode, 0);
+      result = expand_normal (from);
       return;
     }
 
+  /* Optimize away no-op moves without side-effects.  */
+  if (operand_equal_p (to, from, 0))
+    return;
+
   /* Assignment of a structure component needs special treatment
      if the structure component's rtx is not simply a MEM.
      Assignment of an array element at a constant index, and assignment of
@@ -3775,7 +4163,6 @@ expand_assignment (tree to, tree from)
     {
       enum machine_mode mode1;
       HOST_WIDE_INT bitsize, bitpos;
-      rtx orig_to_rtx;
       tree offset;
       int unsignedp;
       int volatilep = 0;
@@ -3783,19 +4170,27 @@ 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_normal (tem);
 
       if (offset != 0)
        {
-         rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
+         rtx offset_rtx;
 
-         gcc_assert (MEM_P (to_rtx));
+         if (!MEM_P (to_rtx))
+           {
+             /* We can get constant negative offsets into arrays with broken
+                user code.  Translate this to a trap instead of ICEing.  */
+             gcc_assert (TREE_CODE (offset) == INTEGER_CST);
+             expand_builtin_trap ();
+             to_rtx = gen_rtx_MEM (BLKmode, const0_rtx);
+           }
 
+         offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
 #ifdef POINTERS_EXTEND_UNSIGNED
          if (GET_MODE (offset_rtx) != Pmode)
            offset_rtx = convert_to_mode (Pmode, offset_rtx, 0);
@@ -3829,12 +4224,13 @@ expand_assignment (tree to, tree from)
          if (TREE_CODE (TREE_TYPE (from)) == COMPLEX_TYPE)
            {
              gcc_assert (bitpos == 0);
-             result = store_expr (from, to_rtx, false);
+             result = store_expr (from, to_rtx, false, nontemporal);
            }
          else
            {
              gcc_assert (bitpos == 0 || bitpos == GET_MODE_BITSIZE (mode1));
-             result = store_expr (from, XEXP (to_rtx, bitpos != 0), false);
+             result = store_expr (from, XEXP (to_rtx, bitpos != 0), false,
+                                  nontemporal);
            }
        }
       else
@@ -3860,7 +4256,8 @@ expand_assignment (tree to, tree from)
            result = NULL;
          else
            result = store_field (to_rtx, bitsize, bitpos, mode1, from,
-                                 TREE_TYPE (tem), get_alias_set (to));
+                                 TREE_TYPE (tem), get_alias_set (to),
+                                 nontemporal);
        }
 
       if (result)
@@ -3888,7 +4285,7 @@ expand_assignment (tree to, tree from)
       rtx value;
 
       push_temp_slots ();
-      value = expand_expr (from, NULL_RTX, VOIDmode, 0);
+      value = expand_normal (from);
       if (to_rtx == 0)
        to_rtx = expand_expr (to, NULL_RTX, VOIDmode, EXPAND_WRITE);
 
@@ -3924,7 +4321,7 @@ expand_assignment (tree to, tree from)
       rtx temp;
 
       push_temp_slots ();
-      temp = expand_expr (from, 0, GET_MODE (to_rtx), 0);
+      temp = expand_expr (from, NULL_RTX, GET_MODE (to_rtx), EXPAND_NORMAL);
 
       if (GET_CODE (to_rtx) == PARALLEL)
        emit_group_load (to_rtx, temp, TREE_TYPE (from),
@@ -3942,14 +4339,14 @@ expand_assignment (tree to, tree from)
      the place the value is being stored, use a safe function when copying
      a value through a pointer into a structure value return block.  */
   if (TREE_CODE (to) == RESULT_DECL && TREE_CODE (from) == INDIRECT_REF
-      && current_function_returns_struct
-      && !current_function_returns_pcc_struct)
+      && cfun->returns_struct
+      && !cfun->returns_pcc_struct)
     {
       rtx from_rtx, size;
 
       push_temp_slots ();
       size = expr_size (from);
-      from_rtx = expand_expr (from, NULL_RTX, VOIDmode, 0);
+      from_rtx = expand_normal (from);
 
       emit_library_call (memmove_libfunc, LCT_NORMAL,
                         VOIDmode, 3, XEXP (to_rtx, 0), Pmode,
@@ -3967,13 +4364,46 @@ expand_assignment (tree to, tree from)
   /* Compute FROM and store the value in the rtx we got.  */
 
   push_temp_slots ();
-  result = store_expr (from, to_rtx, 0);
+  result = store_expr (from, to_rtx, 0, nontemporal);
   preserve_temp_slots (result);
   free_temp_slots ();
   pop_temp_slots ();
   return;
 }
 
+/* Emits nontemporal store insn that moves FROM to TO.  Returns true if this
+   succeeded, false otherwise.  */
+
+static bool
+emit_storent_insn (rtx to, rtx from)
+{
+  enum machine_mode mode = GET_MODE (to), imode;
+  enum insn_code code = optab_handler (storent_optab, mode)->insn_code;
+  rtx pattern;
+
+  if (code == CODE_FOR_nothing)
+    return false;
+
+  imode = insn_data[code].operand[0].mode;
+  if (!insn_data[code].operand[0].predicate (to, imode))
+    return false;
+
+  imode = insn_data[code].operand[1].mode;
+  if (!insn_data[code].operand[1].predicate (from, imode))
+    {
+      from = copy_to_mode_reg (imode, from);
+      if (!insn_data[code].operand[1].predicate (from, imode))
+       return false;
+    }
+
+  pattern = GEN_FCN (code) (to, from);
+  if (pattern == NULL_RTX)
+    return false;
+
+  emit_insn (pattern);
+  return true;
+}
+
 /* Generate code for computing expression EXP,
    and storing the value into TARGET.
 
@@ -3985,10 +4415,12 @@ expand_assignment (tree to, tree from)
    be more thorough?
 
    If CALL_PARAM_P is nonzero, this is a store into a call param on the
-   stack, and block moves may need to be treated specially.  */
+   stack, and block moves may need to be treated specially.
+   If NONTEMPORAL is true, try using a nontemporal store instruction.  */
 
 rtx
-store_expr (tree exp, rtx target, int call_param_p)
+store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
 {
   rtx temp;
   rtx alt_rtl = NULL_RTX;
@@ -4000,7 +4432,7 @@ store_expr (tree exp, rtx target, int call_param_p)
         branch and an rvalue in the other. Here, we resolve attempts to
         store the throw expression's nonexistent result.  */
       gcc_assert (!call_param_p);
-      expand_expr (exp, const0_rtx, VOIDmode, 0);
+      expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL);
       return NULL_RTX;
     }
   if (TREE_CODE (exp) == COMPOUND_EXPR)
@@ -4009,7 +4441,8 @@ store_expr (tree exp, rtx target, int call_param_p)
         part.  */
       expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
                   call_param_p ? EXPAND_STACK_PARM : EXPAND_NORMAL);
-      return store_expr (TREE_OPERAND (exp, 1), target, call_param_p);
+      return store_expr (TREE_OPERAND (exp, 1), target, call_param_p,
+                        nontemporal);
     }
   else if (TREE_CODE (exp) == COND_EXPR && GET_MODE (target) == BLKmode)
     {
@@ -4023,11 +4456,13 @@ store_expr (tree exp, rtx target, int call_param_p)
       do_pending_stack_adjust ();
       NO_DEFER_POP;
       jumpifnot (TREE_OPERAND (exp, 0), lab1);
-      store_expr (TREE_OPERAND (exp, 1), target, call_param_p);
+      store_expr (TREE_OPERAND (exp, 1), target, call_param_p,
+                 nontemporal);
       emit_jump_insn (gen_jump (lab2));
       emit_barrier ();
       emit_label (lab1);
-      store_expr (TREE_OPERAND (exp, 2), target, call_param_p);
+      store_expr (TREE_OPERAND (exp, 2), target, call_param_p,
+                 nontemporal);
       emit_label (lab2);
       OK_DEFER_POP;
 
@@ -4049,20 +4484,29 @@ store_expr (tree exp, rtx target, int call_param_p)
         converting modes.  */
       if (INTEGRAL_TYPE_P (TREE_TYPE (exp))
          && TREE_TYPE (TREE_TYPE (exp)) == 0
-         && (!lang_hooks.reduce_bit_field_operations
-             || (GET_MODE_PRECISION (GET_MODE (target))
-                 == TYPE_PRECISION (TREE_TYPE (exp)))))
+         && GET_MODE_PRECISION (GET_MODE (target))
+            == TYPE_PRECISION (TREE_TYPE (exp)))
        {
          if (TYPE_UNSIGNED (TREE_TYPE (exp))
              != SUBREG_PROMOTED_UNSIGNED_P (target))
-           exp = convert
-             (lang_hooks.types.signed_or_unsigned_type
-              (SUBREG_PROMOTED_UNSIGNED_P (target), TREE_TYPE (exp)), exp);
+           {
+             /* Some types, e.g. Fortran's logical*4, won't have a signed
+                version, so use the mode instead.  */
+             tree ntype
+               = (signed_or_unsigned_type_for
+                  (SUBREG_PROMOTED_UNSIGNED_P (target), TREE_TYPE (exp)));
+             if (ntype == NULL)
+               ntype = lang_hooks.types.type_for_mode
+                 (TYPE_MODE (TREE_TYPE (exp)),
+                  SUBREG_PROMOTED_UNSIGNED_P (target));
+
+             exp = fold_convert (ntype, exp);
+           }
 
-         exp = convert (lang_hooks.types.type_for_mode
-                        (GET_MODE (SUBREG_REG (target)),
-                         SUBREG_PROMOTED_UNSIGNED_P (target)),
-                        exp);
+         exp = fold_convert (lang_hooks.types.type_for_mode
+                               (GET_MODE (SUBREG_REG (target)),
+                                SUBREG_PROMOTED_UNSIGNED_P (target)),
+                             exp);
 
          inner_target = SUBREG_REG (target);
        }
@@ -4086,9 +4530,57 @@ store_expr (tree exp, rtx target, int call_param_p)
 
       return NULL_RTX;
     }
+  else if (TREE_CODE (exp) == STRING_CST
+          && !nontemporal && !call_param_p
+          && TREE_STRING_LENGTH (exp) > 0
+          && TYPE_MODE (TREE_TYPE (exp)) == BLKmode)
+    {
+      /* Optimize initialization of an array with a STRING_CST.  */
+      HOST_WIDE_INT exp_len, str_copy_len;
+      rtx dest_mem;
+
+      exp_len = int_expr_size (exp);
+      if (exp_len <= 0)
+       goto normal_expr;
+
+      str_copy_len = strlen (TREE_STRING_POINTER (exp));
+      if (str_copy_len < TREE_STRING_LENGTH (exp) - 1)
+       goto normal_expr;
+
+      str_copy_len = TREE_STRING_LENGTH (exp);
+      if ((STORE_MAX_PIECES & (STORE_MAX_PIECES - 1)) == 0)
+       {
+         str_copy_len += STORE_MAX_PIECES - 1;
+         str_copy_len &= ~(STORE_MAX_PIECES - 1);
+       }
+      str_copy_len = MIN (str_copy_len, exp_len);
+      if (!can_store_by_pieces (str_copy_len, builtin_strncpy_read_str,
+                               (void *) TREE_STRING_POINTER (exp),
+                               MEM_ALIGN (target), false))
+       goto normal_expr;
+
+      dest_mem = target;
+
+      dest_mem = store_by_pieces (dest_mem,
+                                 str_copy_len, builtin_strncpy_read_str,
+                                 (void *) TREE_STRING_POINTER (exp),
+                                 MEM_ALIGN (target), false,
+                                 exp_len > str_copy_len ? 1 : 0);
+      if (exp_len > str_copy_len)
+       clear_storage (adjust_address (dest_mem, BLKmode, 0),
+                      GEN_INT (exp_len - str_copy_len),
+                      BLOCK_OP_NORMAL);
+      return NULL_RTX;
+    }
   else
     {
-      temp = expand_expr_real (exp, target, GET_MODE (target),
+      rtx tmp_target;
+
+  normal_expr:
+      /* If we want to use a nontemporal store, force the value to
+        register first.  */
+      tmp_target = nontemporal ? NULL_RTX : target;
+      temp = expand_expr_real (exp, tmp_target, GET_MODE (target),
                               (call_param_p
                                ? EXPAND_STACK_PARM : EXPAND_NORMAL),
                               &alt_rtl);
@@ -4143,10 +4635,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)
@@ -4161,6 +4653,12 @@ store_expr (tree exp, rtx target, int call_param_p)
              temp = convert_to_mode (GET_MODE (target), temp, unsignedp);
              emit_move_insn (target, temp);
            }
+         else if (GET_MODE (target) == BLKmode
+                  || GET_MODE (temp) == BLKmode)
+           emit_block_move (target, temp, expr_size (exp),
+                            (call_param_p
+                             ? BLOCK_OP_CALL_PARM
+                             : BLOCK_OP_NORMAL));
          else
            convert_move (target, temp, unsignedp);
        }
@@ -4226,7 +4724,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);
@@ -4241,6 +4739,11 @@ store_expr (tree exp, rtx target, int call_param_p)
        emit_block_move (target, temp, expr_size (exp),
                         (call_param_p
                          ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
+      else if (nontemporal
+              && emit_storent_insn (target, temp))
+       /* If we managed to emit a nontemporal store, there is nothing else to
+          do.  */
+       ;
       else
        {
          temp = force_operand (temp, target);
@@ -4252,30 +4755,28 @@ store_expr (tree exp, rtx target, int call_param_p)
   return NULL_RTX;
 }
 \f
-/* 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.  */
+/* Helper for categorize_ctor_elements.  Identical interface.  */
 
-static void
-categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts,
-                           HOST_WIDE_INT *p_nc_elts,
-                           HOST_WIDE_INT *p_elt_count)
+static bool
+categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
+                           HOST_WIDE_INT *p_elt_count,
+                           bool *p_must_clear)
 {
-  HOST_WIDE_INT nz_elts, nc_elts, elt_count;
-  tree list;
+  unsigned HOST_WIDE_INT idx;
+  HOST_WIDE_INT nz_elts, elt_count;
+  tree value, purpose;
+
+  /* Whether CTOR is a valid constant initializer, in accordance with what
+     initializer_constant_valid_p does.  If inferred from the constructor
+     elements, true until proven otherwise.  */
+  bool const_from_elts_p = constructor_static_from_elts_p (ctor);
+  bool const_p = const_from_elts_p ? true : TREE_STATIC (ctor);
 
   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;
@@ -4293,16 +4794,22 @@ categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts,
        {
        case CONSTRUCTOR:
          {
-           HOST_WIDE_INT nz = 0, nc = 0, count = 0;
-           categorize_ctor_elements_1 (value, &nz, &nc, &count);
+           HOST_WIDE_INT nz = 0, ic = 0;
+
+           bool const_elt_p
+             = categorize_ctor_elements_1 (value, &nz, &ic, p_must_clear);
+
            nz_elts += mult * nz;
-           nc_elts += mult * nc;
-           elt_count += mult * count;
+           elt_count += mult * ic;
+
+           if (const_from_elts_p && const_p)
+             const_p = const_elt_p;
          }
          break;
 
        case INTEGER_CST:
        case REAL_CST:
+       case FIXED_CST:
          if (!initializer_zerop (value))
            nz_elts += mult;
          elt_count += mult;
@@ -4336,33 +4843,86 @@ categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts,
        default:
          nz_elts += mult;
          elt_count += mult;
-         if (!initializer_constant_valid_p (value, TREE_TYPE (value)))
-           nc_elts += mult;
+
+         if (const_from_elts_p && const_p)
+           const_p = initializer_constant_valid_p (value, TREE_TYPE (value))
+                     != NULL_TREE;
          break;
        }
     }
 
+  if (!*p_must_clear
+      && (TREE_CODE (TREE_TYPE (ctor)) == UNION_TYPE
+         || TREE_CODE (TREE_TYPE (ctor)) == QUAL_UNION_TYPE))
+    {
+      tree init_sub_type;
+      bool clear_this = true;
+
+      if (!VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (ctor)))
+       {
+         /* We don't expect more than one element of the union to be
+            initialized.  Not sure what we should do otherwise... */
+          gcc_assert (VEC_length (constructor_elt, CONSTRUCTOR_ELTS (ctor))
+                     == 1);
+
+          init_sub_type = TREE_TYPE (VEC_index (constructor_elt,
+                                               CONSTRUCTOR_ELTS (ctor),
+                                               0)->value);
+
+         /* ??? We could look at each element of the union, and find the
+            largest element.  Which would avoid comparing the size of the
+            initialized element against any tail padding in the union.
+            Doesn't seem worth the effort...  */
+         if (simple_cst_equal (TYPE_SIZE (TREE_TYPE (ctor)),
+                               TYPE_SIZE (init_sub_type)) == 1)
+           {
+             /* And now we have to find out if the element itself is fully
+                constructed.  E.g. for union { struct { int a, b; } s; } u
+                = { .s = { .a = 1 } }.  */
+             if (elt_count == count_type_elements (init_sub_type, false))
+               clear_this = false;
+           }
+       }
+
+      *p_must_clear = clear_this;
+    }
+
   *p_nz_elts += nz_elts;
-  *p_nc_elts += nc_elts;
   *p_elt_count += elt_count;
+
+  return const_p;
 }
 
-void
-categorize_ctor_elements (tree ctor, HOST_WIDE_INT *p_nz_elts,
-                         HOST_WIDE_INT *p_nc_elts,
-                         HOST_WIDE_INT *p_elt_count)
+/* Examine CTOR to discover:
+   * how many scalar fields are set to nonzero values,
+     and place it in *P_NZ_ELTS;
+   * how many scalar fields in total are in CTOR,
+     and place it in *P_ELT_COUNT.
+   * if a type is a union, and the initializer from the constructor
+     is not the largest element in the union, then set *p_must_clear.
+
+   Return whether or not CTOR is a valid static constant initializer, the same
+   as "initializer_constant_valid_p (CTOR, TREE_TYPE (CTOR)) != 0".  */
+
+bool
+categorize_ctor_elements (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
+                         HOST_WIDE_INT *p_elt_count,
+                         bool *p_must_clear)
 {
   *p_nz_elts = 0;
-  *p_nc_elts = 0;
   *p_elt_count = 0;
-  categorize_ctor_elements_1 (ctor, p_nz_elts, p_nc_elts, p_elt_count);
+  *p_must_clear = false;
+
+  return
+    categorize_ctor_elements_1 (ctor, p_nz_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 (const_tree type, bool allow_flexarr)
 {
   const HOST_WIDE_INT max = ~((HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT-1));
   switch (TREE_CODE (type))
@@ -4373,7 +4933,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)
@@ -4390,9 +4950,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;
            }
 
@@ -4401,14 +4975,7 @@ count_type_elements (tree type)
 
     case UNION_TYPE:
     case QUAL_UNION_TYPE:
-      {
-       /* Ho hum.  How in the world do we guess here?  Clearly it isn't
-          right to count the fields.  Guess based on the number of words.  */
-        HOST_WIDE_INT n = int_size_in_bytes (type);
-       if (n < 0)
-         return -1;
-       return n / UNITS_PER_WORD;
-      }
+      return -1;
 
     case COMPLEX_TYPE:
       return 2;
@@ -4418,9 +4985,9 @@ count_type_elements (tree type)
 
     case INTEGER_TYPE:
     case REAL_TYPE:
+    case FIXED_POINT_TYPE:
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
-    case CHAR_TYPE:
     case POINTER_TYPE:
     case OFFSET_TYPE:
     case REFERENCE_TYPE:
@@ -4428,7 +4995,6 @@ count_type_elements (tree type)
 
     case VOID_TYPE:
     case METHOD_TYPE:
-    case FILE_TYPE:
     case FUNCTION_TYPE:
     case LANG_TYPE:
     default:
@@ -4439,21 +5005,43 @@ count_type_elements (tree type)
 /* Return 1 if EXP contains mostly (3/4)  zeros.  */
 
 static int
-mostly_zeros_p (tree exp)
+mostly_zeros_p (const_tree exp)
 {
   if (TREE_CODE (exp) == CONSTRUCTOR)
 
     {
-      HOST_WIDE_INT nz_elts, nc_elts, count, elts;
+      HOST_WIDE_INT nz_elts, count, elts;
+      bool must_clear;
 
-      categorize_ctor_elements (exp, &nz_elts, &nc_elts, &count);
-      elts = count_type_elements (TREE_TYPE (exp));
+      categorize_ctor_elements (exp, &nz_elts, &count, &must_clear);
+      if (must_clear)
+       return 1;
+
+      elts = count_type_elements (TREE_TYPE (exp), false);
 
       return nz_elts < elts / 4;
     }
 
   return initializer_zerop (exp);
 }
+
+/* Return 1 if EXP contains all zeros.  */
+
+static int
+all_zeros_p (const_tree exp)
+{
+  if (TREE_CODE (exp) == CONSTRUCTOR)
+
+    {
+      HOST_WIDE_INT nz_elts, count;
+      bool must_clear;
+
+      categorize_ctor_elements (exp, &nz_elts, &count, &must_clear);
+      return nz_elts == 0;
+    }
+
+  return initializer_zerop (exp);
+}
 \f
 /* Helper function for store_constructor.
    TARGET, BITSIZE, BITPOS, MODE, EXP are as for store_field.
@@ -4469,7 +5057,8 @@ mostly_zeros_p (tree exp)
 static void
 store_constructor_field (rtx target, unsigned HOST_WIDE_INT bitsize,
                         HOST_WIDE_INT bitpos, enum machine_mode mode,
-                        tree exp, tree type, int cleared, int alias_set)
+                        tree exp, tree type, int cleared,
+                        alias_set_type alias_set)
 {
   if (TREE_CODE (exp) == CONSTRUCTOR
       /* We can only call store_constructor recursively if the size and
@@ -4501,7 +5090,7 @@ store_constructor_field (rtx target, unsigned HOST_WIDE_INT bitsize,
       store_constructor (exp, target, cleared, bitsize / BITS_PER_UNIT);
     }
   else
-    store_field (target, bitsize, bitpos, mode, exp, type, alias_set);
+    store_field (target, bitsize, bitpos, mode, exp, type, alias_set, false);
 }
 
 /* Store the value of constructor EXP into the rtx TARGET.
@@ -4526,7 +5115,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)
@@ -4537,7 +5127,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;
          }
 
@@ -4558,50 +5148,47 @@ 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;
          }
 
-       if (cleared)
-         emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
+       if (REG_P (target) && !cleared)
+         emit_clobber (target);
 
        /* 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;
            tree offset;
            rtx to_rtx = target;
-           
+
            /* Just ignore missing fields.  We cleared the whole
               structure, above, if any fields are missing.  */
            if (field == 0)
              continue;
-           
+
            if (cleared && initializer_zerop (value))
              continue;
-           
+
            if (host_integerp (DECL_SIZE (field), 1))
              bitsize = tree_low_cst (DECL_SIZE (field), 1);
            else
              bitsize = -1;
-           
+
            mode = DECL_MODE (field);
            if (DECL_BIT_FIELD (field))
              mode = VOIDmode;
-           
+
            offset = DECL_FIELD_OFFSET (field);
            if (host_integerp (offset, 0)
                && host_integerp (bit_position (field), 0))
@@ -4611,19 +5198,19 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
              }
            else
              bitpos = tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 0);
-           
+
            if (offset)
              {
                rtx offset_rtx;
-               
+
                offset
                  = SUBSTITUTE_PLACEHOLDER_IN_EXPR (offset,
                                                    make_tree (TREE_TYPE (exp),
                                                               target));
 
-               offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
+               offset_rtx = expand_normal (offset);
                gcc_assert (MEM_P (to_rtx));
-               
+
 #ifdef POINTERS_EXTEND_UNSIGNED
                if (GET_MODE (offset_rtx) != Pmode)
                  offset_rtx = convert_to_mode (Pmode, offset_rtx, 0);
@@ -4651,19 +5238,19 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                && bitpos + BITS_PER_WORD <= exp_size * BITS_PER_UNIT)
              {
                tree type = TREE_TYPE (value);
-               
+
                if (TYPE_PRECISION (type) < BITS_PER_WORD)
                  {
                    type = lang_hooks.types.type_for_size
                      (BITS_PER_WORD, TYPE_UNSIGNED (type));
-                   value = convert (type, value);
+                   value = fold_convert (type, value);
                  }
-               
+
                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 (type,
+                                                 BITS_PER_WORD - bitsize));
                bitsize = BITS_PER_WORD;
                mode = word_mode;
              }
@@ -4675,7 +5262,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                to_rtx = copy_rtx (to_rtx);
                MEM_KEEP_ALIAS_SET_P (to_rtx) = 1;
              }
-           
+
            store_constructor_field (to_rtx, bitsize, bitpos, mode,
                                     value, type, cleared,
                                     get_alias_set (TREE_TYPE (field)));
@@ -4684,8 +5271,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);
@@ -4715,42 +5302,44 @@ 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)
                  {
                    tree lo_index = TREE_OPERAND (index, 0);
                    tree hi_index = TREE_OPERAND (index, 1);
-                   
+
                    if (! host_integerp (lo_index, 1)
                        || ! host_integerp (hi_index, 1))
                      {
                        need_to_clear = 1;
                        break;
                      }
-                   
+
                    this_node_count = (tree_low_cst (hi_index, 1)
                                       - tree_low_cst (lo_index, 1) + 1);
                  }
                else
                  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;
              }
-           
+
            /* Clear the entire array first if there are any missing
               elements, or if the incidence of zero elements is >=
               75%.  */
@@ -4759,38 +5348,34 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                    || 4 * zero_count >= 3 * count))
              need_to_clear = 1;
          }
-       
+
        if (need_to_clear && size > 0)
          {
            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;
          }
 
        if (!cleared && REG_P (target))
          /* Inform later passes that the old value is dead.  */
-         emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
+         emit_clobber (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++)
+       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))
              continue;
-           
+
            unsignedp = TYPE_UNSIGNED (elttype);
            mode = TYPE_MODE (elttype);
            if (mode == BLKmode)
@@ -4799,7 +5384,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                         : -1);
            else
              bitsize = GET_MODE_BITSIZE (mode);
-           
+
            if (index != NULL_TREE && TREE_CODE (index) == RANGE_EXPR)
              {
                tree lo_index = TREE_OPERAND (index, 0);
@@ -4807,7 +5392,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                rtx index_r, pos_rtx;
                HOST_WIDE_INT lo, hi, count;
                tree position;
-               
+
                /* If the range is constant and "small", unroll the loop.  */
                if (const_bounds_p
                    && host_integerp (lo_index, 0)
@@ -4825,7 +5410,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                    for (; lo <= hi; lo++)
                      {
                        bitpos = lo * tree_low_cst (TYPE_SIZE (elttype), 0);
-                       
+
                        if (MEM_P (target)
                            && !MEM_KEEP_ALIAS_SET_P (target)
                            && TREE_CODE (type) == ARRAY_TYPE
@@ -4834,7 +5419,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                            target = copy_rtx (target);
                            MEM_KEEP_ALIAS_SET_P (target) = 1;
                          }
-                       
+
                        store_constructor_field
                          (target, bitsize, bitpos, mode, value, type, cleared,
                           get_alias_set (elttype));
@@ -4845,32 +5430,36 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                    rtx loop_start = gen_label_rtx ();
                    rtx loop_end = gen_label_rtx ();
                    tree exit_cond;
-                   
-                   expand_expr (hi_index, NULL_RTX, VOIDmode, 0);
+
+                   expand_normal (hi_index);
                    unsignedp = TYPE_UNSIGNED (domain);
-                   
+
                    index = build_decl (VAR_DECL, NULL_TREE, domain);
-                   
+
                    index_r
                      = gen_reg_rtx (promote_mode (domain, DECL_MODE (index),
                                                   &unsignedp, 0));
                    SET_DECL_RTL (index, index_r);
-                   store_expr (lo_index, index_r, 0);
-                   
+                   store_expr (lo_index, index_r, 0, false);
+
                    /* Build the head of the loop.  */
                    do_pending_stack_adjust ();
                    emit_label (loop_start);
 
                    /* Assign value to element index.  */
-                   position
-                     = convert (ssizetype,
-                                fold (build2 (MINUS_EXPR, TREE_TYPE (index),
-                                              index, TYPE_MIN_VALUE (domain))));
-                   position = size_binop (MULT_EXPR, position,
-                                          convert (ssizetype,
-                                                   TYPE_SIZE_UNIT (elttype)));
-                   
-                   pos_rtx = expand_expr (position, 0, VOIDmode, 0);
+                   position =
+                     fold_convert (ssizetype,
+                                   fold_build2 (MINUS_EXPR,
+                                                TREE_TYPE (index),
+                                                index,
+                                                TYPE_MIN_VALUE (domain)));
+
+                   position =
+                       size_binop (MULT_EXPR, position,
+                                   fold_convert (ssizetype,
+                                                 TYPE_SIZE_UNIT (elttype)));
+
+                   pos_rtx = expand_normal (position);
                    xtarget = offset_address (target, pos_rtx,
                                              highest_pow2_factor (position));
                    xtarget = adjust_address (xtarget, mode, 0);
@@ -4878,21 +5467,22 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                      store_constructor (value, xtarget, cleared,
                                         bitsize / BITS_PER_UNIT);
                    else
-                     store_expr (value, xtarget, 0);
+                     store_expr (value, xtarget, 0, false);
 
                    /* Generate a conditional jump to exit the loop.  */
                    exit_cond = build2 (LT_EXPR, integer_type_node,
                                        index, hi_index);
                    jumpif (exit_cond, loop_end);
-                   
+
                    /* Update the loop counter, and jump to the head of
                       the loop.  */
                    expand_assignment (index,
                                       build2 (PLUS_EXPR, TREE_TYPE (index),
-                                              index, integer_one_node));
-                   
+                                              index, integer_one_node),
+                                      false);
+
                    emit_jump (loop_start);
-                   
+
                    /* Build the end of the loop.  */
                    emit_label (loop_end);
                  }
@@ -4901,25 +5491,26 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                     || ! host_integerp (TYPE_SIZE (elttype), 1))
              {
                tree position;
-               
+
                if (index == 0)
                  index = ssize_int (1);
-               
+
                if (minelt)
                  index = fold_convert (ssizetype,
-                                       fold (build2 (MINUS_EXPR,
-                                                     TREE_TYPE (index),
-                                                     index,
-                                                     TYPE_MIN_VALUE (domain))));
-               
-               position = size_binop (MULT_EXPR, index,
-                                      convert (ssizetype,
-                                               TYPE_SIZE_UNIT (elttype)));
+                                       fold_build2 (MINUS_EXPR,
+                                                    TREE_TYPE (index),
+                                                    index,
+                                                    TYPE_MIN_VALUE (domain)));
+
+               position =
+                 size_binop (MULT_EXPR, index,
+                             fold_convert (ssizetype,
+                                           TYPE_SIZE_UNIT (elttype)));
                xtarget = offset_address (target,
-                                         expand_expr (position, 0, VOIDmode, 0),
+                                         expand_normal (position),
                                          highest_pow2_factor (position));
                xtarget = adjust_address (xtarget, mode, 0);
-               store_expr (value, xtarget, 0);
+               store_expr (value, xtarget, 0, false);
              }
            else
              {
@@ -4928,7 +5519,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                            * tree_low_cst (TYPE_SIZE (elttype), 1));
                else
                  bitpos = (i * tree_low_cst (TYPE_SIZE (elttype), 1));
-               
+
                if (MEM_P (target) && !MEM_KEEP_ALIAS_SET_P (target)
                    && TREE_CODE (type) == ARRAY_TYPE
                    && TYPE_NONALIASED_COMPONENT (type))
@@ -4945,7 +5536,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;
@@ -4954,27 +5546,27 @@ 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);
-       
+
        n_elts = TYPE_VECTOR_SUBPARTS (type);
        if (REG_P (target) && VECTOR_MODE_P (GET_MODE (target)))
          {
            enum machine_mode mode = GET_MODE (target);
-           
-           icode = (int) vec_init_optab->handlers[mode].insn_code;
+
+           icode = (int) optab_handler (vec_init_optab, mode)->insn_code;
            if (icode != CODE_FOR_nothing)
              {
                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));
              }
          }
-       
+
        /* If the constructor has fewer elements than the vector,
           clear the whole array first.  Similarly if this is static
           constructor of a non-BLKmode object.  */
@@ -4985,18 +5577,17 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
        else
          {
            unsigned HOST_WIDE_INT count = 0, zero_count = 0;
-           
-           for (elt = CONSTRUCTOR_ELTS (exp);
-                elt != NULL_TREE;
-                elt = TREE_CHAIN (elt))
+           tree value;
+
+           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;
              }
 
@@ -5004,45 +5595,45 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
               or if the incidence of zero elements is >= 75%.  */
            need_to_clear = (count < n_elts || 4 * zero_count >= 3 * count);
          }
-       
+
        if (need_to_clear && size > 0 && !vector)
          {
            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;
          }
-       
-       if (!cleared && REG_P (target))
-         /* Inform later passes that the old value is dead.  */
-         emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
+
+       /* Inform later passes that the old value is dead.  */
+       if (!cleared && !vector && REG_P (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;
-           
+
            if (vector)
              {
                /* 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_normal (value);
              }
            else
              {
@@ -5056,15 +5647,14 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                                         cleared, get_alias_set (elttype));
              }
          }
-       
+
        if (vector)
          emit_insn (GEN_FCN (icode)
                     (target,
-                     gen_rtx_PARALLEL (GET_MODE (target),
-                                       gen_rtvec_v (n_elts, vector))));
+                     gen_rtx_PARALLEL (GET_MODE (target), vector)));
        break;
       }
-      
+
     default:
       gcc_unreachable ();
     }
@@ -5082,11 +5672,14 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
 
    ALIAS_SET is the alias set for the destination.  This value will
    (in general) be different from that for TARGET, since TARGET is a
-   reference to the containing structure.  */
+   reference to the containing structure.
+   
+   If NONTEMPORAL is true, try generating a nontemporal store.  */
 
 static rtx
 store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
-            enum machine_mode mode, tree exp, tree type, int alias_set)
+            enum machine_mode mode, tree exp, tree type,
+            alias_set_type alias_set, bool nontemporal)
 {
   HOST_WIDE_INT width_mask = 0;
 
@@ -5096,7 +5689,7 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
   /* If we have nothing to store, do nothing unless the expression has
      side-effects.  */
   if (bitsize == 0)
-    return expand_expr (exp, const0_rtx, VOIDmode, 0);
+    return expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL);
   else if (bitsize >= 0 && bitsize < HOST_BITS_PER_WIDE_INT)
     width_mask = ((HOST_WIDE_INT) 1 << bitsize) - 1;
 
@@ -5121,7 +5714,8 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
       if (bitsize != (HOST_WIDE_INT) GET_MODE_BITSIZE (GET_MODE (target)))
        emit_move_insn (object, target);
 
-      store_field (blk_object, bitsize, bitpos, mode, exp, type, alias_set);
+      store_field (blk_object, bitsize, bitpos, mode, exp, type, alias_set,
+                  nontemporal);
 
       emit_move_insn (target, object);
 
@@ -5134,7 +5728,7 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
       /* We're storing into a struct containing a single __complex.  */
 
       gcc_assert (!bitpos);
-      return store_expr (exp, target, 0);
+      return store_expr (exp, target, 0, nontemporal);
     }
 
   /* If the structure is in a register or if the component
@@ -5161,7 +5755,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_normal (exp);
 
       /* If BITSIZE is narrower than the size of the type of EXP
         we will be narrowing TEMP.  Normally, what's wanted are the
@@ -5181,13 +5795,19 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
          && mode != TYPE_MODE (TREE_TYPE (exp)))
        temp = convert_modes (mode, TYPE_MODE (TREE_TYPE (exp)), temp, 1);
 
-      /* If the modes of TARGET and TEMP are both BLKmode, both
+      /* If the modes of TEMP and TARGET are both BLKmode, both
         must be in memory and BITPOS must be aligned on a byte
-        boundary.  If so, we simply do a block copy.  */
-      if (GET_MODE (target) == BLKmode && GET_MODE (temp) == BLKmode)
+        boundary.  If so, we simply do a block copy.  Likewise
+        for a BLKmode-like TARGET.  */
+      if (GET_MODE (temp) == BLKmode
+         && (GET_MODE (target) == BLKmode
+             || (MEM_P (target)
+                 && GET_MODE_CLASS (GET_MODE (target)) == MODE_INT
+                 && (bitpos % BITS_PER_UNIT) == 0
+                 && (bitsize % BITS_PER_UNIT) == 0)))
        {
          gcc_assert (MEM_P (target) && MEM_P (temp)
-                     && !(bitpos % BITS_PER_UNIT));
+                     && (bitpos % BITS_PER_UNIT) == 0);
 
          target = adjust_address (target, VOIDmode, bitpos / BITS_PER_UNIT);
          emit_block_move (target, temp,
@@ -5215,7 +5835,7 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
       if (!MEM_KEEP_ALIAS_SET_P (to_rtx) && MEM_ALIAS_SET (to_rtx) != 0)
        set_mem_alias_set (to_rtx, alias_set);
 
-      return store_expr (exp, to_rtx, 0);
+      return store_expr (exp, to_rtx, 0, nontemporal);
     }
 }
 \f
@@ -5233,40 +5853,64 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
    If any of the extraction expressions is volatile,
    we store 1 in *PVOLATILEP.  Otherwise we don't change that.
 
-   If the field is a bit-field, *PMODE is set to VOIDmode.  Otherwise, it
-   is a mode that can be used to access the field.  In that case, *PBITSIZE
-   is redundant.
+   If the field is a non-BLKmode bit-field, *PMODE is set to VOIDmode.
+   Otherwise, it is a mode that can be used to access the field.
 
    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.  */
+   BLKmode and *PBITSIZE is set to -1.  An access cannot be made in
+   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;
+  bool blkmode_bitfield = false;
   tree offset = size_zero_node;
   tree bit_offset = bitsize_zero_node;
-  tree tem;
 
   /* First get the mode, signedness, and size.  We do this from just the
      outermost expression.  */
   if (TREE_CODE (exp) == COMPONENT_REF)
     {
-      size_tree = DECL_SIZE (TREE_OPERAND (exp, 1));
-      if (! DECL_BIT_FIELD (TREE_OPERAND (exp, 1)))
-       mode = DECL_MODE (TREE_OPERAND (exp, 1));
+      tree field = TREE_OPERAND (exp, 1);
+      size_tree = DECL_SIZE (field);
+      if (!DECL_BIT_FIELD (field))
+       mode = DECL_MODE (field);
+      else if (DECL_MODE (field) == BLKmode)
+       blkmode_bitfield = true;
 
-      *punsignedp = DECL_UNSIGNED (TREE_OPERAND (exp, 1));
+      *punsignedp = DECL_UNSIGNED (field);
     }
   else if (TREE_CODE (exp) == BIT_FIELD_REF)
     {
       size_tree = TREE_OPERAND (exp, 1);
-      *punsignedp = BIT_FIELD_REF_UNSIGNED (exp);
+      *punsignedp = (! INTEGRAL_TYPE_P (TREE_TYPE (exp))
+                    || TYPE_UNSIGNED (TREE_TYPE (exp)));
+
+      /* For vector types, with the correct size of access, use the mode of
+        inner type.  */
+      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == VECTOR_TYPE
+         && TREE_TYPE (exp) == TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0)))
+         && tree_int_cst_equal (size_tree, TYPE_SIZE (TREE_TYPE (exp))))
+        mode = TYPE_MODE (TREE_TYPE (exp));
     }
   else
     {
@@ -5329,12 +5973,12 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
               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));
+             index = fold_build2 (MINUS_EXPR, TREE_TYPE (index),
+                                  index, low_bound);
 
            offset = size_binop (PLUS_EXPR, offset,
                                 size_binop (MULT_EXPR,
-                                            convert (sizetype, index),
+                                            fold_convert (sizetype, index),
                                             unit_size));
          }
          break;
@@ -5347,14 +5991,10 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
                                   bitsize_int (*pbitsize));
          break;
 
-       /* 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.  */
-
        case VIEW_CONVERT_EXPR:
-         if ((TYPE_ALIGN (TREE_TYPE (exp))
+         if (keep_aligning && STRICT_ALIGNMENT
+             && (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))
@@ -5375,20 +6015,80 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
  done:
 
   /* If OFFSET is constant, see if we can return the whole thing as a
-     constant bit position.  Otherwise, split it up.  */
-  if (host_integerp (offset, 0)
-      && 0 != (tem = size_binop (MULT_EXPR, convert (bitsizetype, offset),
-                                bitsize_unit_node))
-      && 0 != (tem = size_binop (PLUS_EXPR, tem, bit_offset))
-      && host_integerp (tem, 0))
-    *pbitpos = tree_low_cst (tem, 0), *poffset = 0;
+     constant bit position.  Make sure to handle overflow during
+     this conversion.  */
+  if (host_integerp (offset, 0))
+    {
+      double_int tem = double_int_mul (tree_to_double_int (offset),
+                                      uhwi_to_double_int (BITS_PER_UNIT));
+      tem = double_int_add (tem, tree_to_double_int (bit_offset));
+      if (double_int_fits_in_shwi_p (tem))
+       {
+         *pbitpos = double_int_to_shwi (tem);
+         *poffset = offset = NULL_TREE;
+       }
+    }
+
+  /* Otherwise, split it up.  */
+  if (offset)
+    {
+      *pbitpos = tree_low_cst (bit_offset, 0);
+      *poffset = offset;
+    }
+
+  /* We can use BLKmode for a byte-aligned BLKmode bitfield.  */
+  if (mode == VOIDmode
+      && blkmode_bitfield
+      && (*pbitpos % BITS_PER_UNIT) == 0
+      && (*pbitsize % BITS_PER_UNIT) == 0)
+    *pmode = BLKmode;
   else
-    *pbitpos = tree_low_cst (bit_offset, 0), *poffset = offset;
+    *pmode = mode;
 
-  *pmode = mode;
   return exp;
 }
 
+/* Given an expression EXP that may be a COMPONENT_REF or an ARRAY_REF,
+   look for whether EXP or any nested component-refs within EXP is marked
+   as PACKED.  */
+
+bool
+contains_packed_reference (const_tree exp)
+{
+  bool packed_p = false;
+
+  while (1)
+    {
+      switch (TREE_CODE (exp))
+       {
+       case COMPONENT_REF:
+         {
+           tree field = TREE_OPERAND (exp, 1);
+           packed_p = DECL_PACKED (field) 
+                      || TYPE_PACKED (TREE_TYPE (field))
+                      || TYPE_PACKED (TREE_TYPE (exp));
+           if (packed_p)
+             goto done;
+         }
+         break;
+
+       case BIT_FIELD_REF:
+       case ARRAY_REF:
+       case ARRAY_RANGE_REF:
+       case REALPART_EXPR:
+       case IMAGPART_EXPR:
+       case VIEW_CONVERT_EXPR:
+         break;
+
+       default:
+         goto done;
+       }
+      exp = TREE_OPERAND (exp, 0);
+    }
+ done:
+  return packed_p;
+}
+
 /* Return a tree of sizetype representing the size, in bytes, of the element
    of EXP, an ARRAY_REF.  */
 
@@ -5485,7 +6185,7 @@ component_ref_field_offset (tree exp)
 /* Return 1 if T is an expression that get_inner_reference handles.  */
 
 int
-handled_component_p (tree t)
+handled_component_p (const_tree t)
 {
   switch (TREE_CODE (t))
     {
@@ -5523,12 +6223,13 @@ force_operand (rtx value, rtx target)
       && !REG_P (SUBREG_REG (value))
       && !MEM_P (SUBREG_REG (value)))
     {
-      value = simplify_gen_subreg (GET_MODE (value),
-                                  force_reg (GET_MODE (SUBREG_REG (value)),
-                                             force_operand (SUBREG_REG (value),
-                                                            NULL_RTX)),
-                                  GET_MODE (SUBREG_REG (value)),
-                                  SUBREG_BYTE (value));
+      value
+       = simplify_gen_subreg (GET_MODE (value),
+                              force_reg (GET_MODE (SUBREG_REG (value)),
+                                         force_operand (SUBREG_REG (value),
+                                                        NULL_RTX)),
+                              GET_MODE (SUBREG_REG (value)),
+                              SUBREG_BYTE (value));
       code = GET_CODE (value);
     }
 
@@ -5545,15 +6246,6 @@ force_operand (rtx value, rtx target)
       return subtarget;
     }
 
-  if (code == ZERO_EXTEND || code == SIGN_EXTEND)
-    {
-      if (!target)
-       target = gen_reg_rtx (GET_MODE (value));
-      convert_move (target, force_operand (XEXP (value, 0), NULL),
-                   code == ZERO_EXTEND);
-      return target;
-    }
-
   if (ARITHMETIC_P (value))
     {
       op2 = XEXP (value, 1);
@@ -5601,23 +6293,18 @@ force_operand (rtx value, rtx target)
                                  FLOAT_MODE_P (GET_MODE (value))
                                  ? RDIV_EXPR : TRUNC_DIV_EXPR,
                                  GET_MODE (value), op1, op2, target, 0);
-         break;
        case MOD:
          return expand_divmod (1, TRUNC_MOD_EXPR, GET_MODE (value), op1, op2,
                                target, 0);
-         break;
        case UDIV:
          return expand_divmod (0, TRUNC_DIV_EXPR, GET_MODE (value), op1, op2,
                                target, 1);
-         break;
        case UMOD:
          return expand_divmod (1, TRUNC_MOD_EXPR, GET_MODE (value), op1, op2,
                                target, 1);
-         break;
        case ASHIFTRT:
          return expand_simple_binop (GET_MODE (value), code, op1, op2,
                                      target, 0, OPTAB_LIB_WIDEN);
-         break;
        default:
          return expand_simple_binop (GET_MODE (value), code, op1, op2,
                                      target, 1, OPTAB_LIB_WIDEN);
@@ -5625,8 +6312,32 @@ force_operand (rtx value, rtx target)
     }
   if (UNARY_P (value))
     {
-      op1 = force_operand (XEXP (value, 0), NULL_RTX);
-      return expand_simple_unop (GET_MODE (value), code, op1, target, 0);
+      if (!target)
+       target = gen_reg_rtx (GET_MODE (value));
+      op1 = force_operand (XEXP (value, 0), NULL_RTX);
+      switch (code)
+       {
+       case ZERO_EXTEND:
+       case SIGN_EXTEND:
+       case TRUNCATE:
+       case FLOAT_EXTEND:
+       case FLOAT_TRUNCATE:
+         convert_move (target, op1, code == ZERO_EXTEND);
+         return target;
+
+       case FIX:
+       case UNSIGNED_FIX:
+         expand_fix (target, op1, code == UNSIGNED_FIX);
+         return target;
+
+       case FLOAT:
+       case UNSIGNED_FLOAT:
+         expand_float (target, op1, code == UNSIGNED_FLOAT);
+         return target;
+
+       default:
+         return expand_simple_unop (GET_MODE (value), code, op1, target, 0);
+       }
     }
 
 #ifdef INSN_SCHEDULING
@@ -5656,7 +6367,7 @@ force_operand (rtx value, rtx target)
    searches for optimization opportunities.  */
 
 int
-safe_from_p (rtx x, tree exp, int top_p)
+safe_from_p (const_rtx x, tree exp, int top_p)
 {
   rtx exp_rtl = 0;
   int i, nops;
@@ -5715,6 +6426,19 @@ safe_from_p (rtx x, tree exp, int top_p)
                return safe_from_p (x, exp, 0);
            }
        }
+      else if (TREE_CODE (exp) == CONSTRUCTOR)
+       {
+         constructor_elt *ce;
+         unsigned HOST_WIDE_INT idx;
+
+         for (idx = 0;
+              VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (exp), idx, ce);
+              idx++)
+           if ((ce->index != NULL_TREE && !safe_from_p (x, ce->index, 0))
+               || !safe_from_p (x, ce->value, 0))
+             return 0;
+         return 1;
+       }
       else if (TREE_CODE (exp) == ERROR_MARK)
        return 1;       /* An already-visited SAVE_EXPR? */
       else
@@ -5739,6 +6463,7 @@ safe_from_p (rtx x, tree exp, int top_p)
 
     case tcc_expression:
     case tcc_reference:
+    case tcc_vl_exp:
       /* Now do code-specific tests.  EXP_RTL is set to any rtx we find in
         the expression.  If it is set, we conflict iff we are that rtx or
         both are in memory.  Otherwise, we check all operands of the
@@ -5801,23 +6526,20 @@ safe_from_p (rtx x, tree exp, int top_p)
       if (exp_rtl)
        break;
 
-      nops = TREE_CODE_LENGTH (TREE_CODE (exp));
+      nops = TREE_OPERAND_LENGTH (exp);
       for (i = 0; i < nops; i++)
        if (TREE_OPERAND (exp, i) != 0
            && ! safe_from_p (x, TREE_OPERAND (exp, i), 0))
          return 0;
 
-      /* If this is a language-specific tree code, it may require
-        special handling.  */
-      if ((unsigned int) TREE_CODE (exp)
-         >= (unsigned int) LAST_AND_UNUSED_TREE_CODE
-         && !lang_hooks.safe_from_p (x, exp))
-       return 0;
       break;
 
     case tcc_type:
       /* Should never get a type here.  */
       gcc_unreachable ();
+
+    case tcc_gimple_stmt:
+      gcc_unreachable ();
     }
 
   /* If we have an rtl, find any enclosed object.  Then see if we conflict
@@ -5848,8 +6570,8 @@ 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
-highest_pow2_factor (tree exp)
+unsigned HOST_WIDE_INT
+highest_pow2_factor (const_tree exp)
 {
   unsigned HOST_WIDE_INT c0, c1;
 
@@ -5862,7 +6584,7 @@ highest_pow2_factor (tree exp)
         a MIN_EXPR, or a MAX_EXPR.  If the constant overflows, we have an
         erroneous program, so return BIGGEST_ALIGNMENT to avoid any
         later ICE.  */
-      if (TREE_CONSTANT_OVERFLOW (exp))
+      if (TREE_OVERFLOW (exp))
        return BIGGEST_ALIGNMENT;
       else
        {
@@ -5895,7 +6617,14 @@ highest_pow2_factor (tree exp)
        }
       break;
 
-    case NON_LVALUE_EXPR:  case NOP_EXPR:  case CONVERT_EXPR:
+    case BIT_AND_EXPR:
+      /* The highest power of two of a bit-and expression is the maximum of
+        that of its operands.  We typically get here for a complex LHS and
+        a constant negative power of two on the RHS to force an explicit
+        alignment, so don't bother looking at the LHS.  */
+      return highest_pow2_factor (TREE_OPERAND (exp, 1));
+
+    CASE_CONVERT:
     case SAVE_EXPR:
       return highest_pow2_factor (TREE_OPERAND (exp, 0));
 
@@ -5920,7 +6649,7 @@ highest_pow2_factor (tree exp)
    the structure gives the alignment.  */
 
 static unsigned HOST_WIDE_INT
-highest_pow2_factor_for_target (tree target, tree exp)
+highest_pow2_factor_for_target (const_tree target, const_tree exp)
 {
   unsigned HOST_WIDE_INT target_align, factor;
 
@@ -5932,39 +6661,19 @@ highest_pow2_factor_for_target (tree target, tree exp)
   return MAX (factor, target_align);
 }
 \f
-/* Expands variable VAR.  */
+/* Return &VAR expression for emulated thread local VAR.  */
 
-void
-expand_var (tree var)
+static tree
+emutls_var_address (tree var)
 {
-  if (DECL_EXTERNAL (var))
-    return;
-
-  if (TREE_STATIC (var))
-    /* If this is an inlined copy of a static local variable,
-       look up the original decl.  */
-    var = DECL_ORIGIN (var);
-
-  if (TREE_STATIC (var)
-      ? !TREE_ASM_WRITTEN (var)
-      : !DECL_RTL_SET_P (var))
-    {
-      if (TREE_CODE (var) == VAR_DECL && DECL_VALUE_EXPR (var))
-       /* Should be ignored.  */;
-      else if (lang_hooks.expand_decl (var))
-       /* OK.  */;
-      else if (TREE_CODE (var) == VAR_DECL && !TREE_STATIC (var))
-       expand_decl (var);
-      else if (TREE_CODE (var) == VAR_DECL && TREE_STATIC (var))
-       rest_of_decl_compilation (var, 0, 0);
-      else
-       /* No expansion needed.  */
-       gcc_assert (TREE_CODE (var) == TYPE_DECL
-                   || TREE_CODE (var) == CONST_DECL
-                   || TREE_CODE (var) == FUNCTION_DECL
-                   || TREE_CODE (var) == LABEL_DECL);
-    }
+  tree emuvar = emutls_decl (var);
+  tree fn = built_in_decls [BUILT_IN_EMUTLS_GET_ADDRESS];
+  tree arg = build_fold_addr_expr_with_type (emuvar, ptr_type_node);
+  tree arglist = build_tree_list (NULL_TREE, arg);
+  tree call = build_function_call_expr (fn, arglist);
+  return fold_convert (build_pointer_type (TREE_TYPE (var)), call);
 }
+\f
 
 /* Subroutine of expand_expr.  Expand the two operands of a binary
    expression EXP0 and EXP1 placing the results in OP0 and OP1.
@@ -5994,6 +6703,20 @@ expand_operands (tree exp0, tree exp1, rtx target, rtx *op0, rtx *op1,
 }
 
 \f
+/* Return a MEM that contains constant EXP.  DEFER is as for
+   output_constant_def and MODIFIER is as for expand_expr.  */
+
+static rtx
+expand_expr_constant (tree exp, int defer, enum expand_modifier modifier)
+{
+  rtx mem;
+
+  mem = output_constant_def (exp, defer);
+  if (modifier != EXPAND_INITIALIZER)
+    mem = use_anchored_address (mem);
+  return mem;
+}
+
 /* A subroutine of expand_expr_addr_expr.  Evaluate the address of EXP.
    The TARGET, TMODE and MODIFIER arguments are as for expand_expr.  */
 
@@ -6013,16 +6736,15 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
   /* ??? This should be considered a front-end bug.  We should not be
      generating ADDR_EXPR of something that isn't an LVALUE.  The only
      exception here is STRING_CST.  */
-  if (TREE_CODE (exp) == CONSTRUCTOR
-      || CONSTANT_CLASS_P (exp))
-    return XEXP (output_constant_def (exp, 0), 0);
+  if (CONSTANT_CLASS_P (exp))
+    return XEXP (expand_expr_constant (exp, 0, modifier), 0);
 
   /* Everything must be something allowed by is_gimple_addressable.  */
   switch (TREE_CODE (exp))
     {
     case INDIRECT_REF:
       /* This case will happen via recursion for &a->b.  */
-      return expand_expr (TREE_OPERAND (exp, 0), target, tmode, EXPAND_NORMAL);
+      return expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
 
     case CONST_DECL:
       /* Recurse and make the output_constant_def clause above handle this.  */
@@ -6046,12 +6768,27 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
       inner = TREE_OPERAND (exp, 0);
       break;
 
+    case VAR_DECL:
+      /* TLS emulation hook - replace __thread VAR's &VAR with
+        __emutls_get_address (&_emutls.VAR).  */
+      if (! targetm.have_tls
+         && TREE_CODE (exp) == VAR_DECL
+         && DECL_THREAD_LOCAL_P (exp))
+       {
+         exp = emutls_var_address (exp);
+         return expand_expr (exp, target, tmode, modifier);
+       }
+      /* Fall through.  */
+
     default:
       /* If the object is a DECL, then expand it for its rtl.  Don't bypass
         expand_expr, as that can have various side effects; LABEL_DECLs for
-        example, may not have their DECL_RTL set yet.  Assume language
-        specific tree nodes can be expanded in some interesting way.  */
+        example, may not have their DECL_RTL set yet.  Expand the rtl of
+        CONSTRUCTORs too, which should yield a memory reference for the
+        constructor's contents.  Assume language specific tree nodes can
+        be expanded in some interesting way.  */
       if (DECL_P (exp)
+         || TREE_CODE (exp) == CONSTRUCTOR
          || TREE_CODE (exp) >= LAST_AND_UNUSED_TREE_CODE)
        {
          result = expand_expr (exp, target, tmode,
@@ -6061,7 +6798,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?  */
@@ -6077,8 +6814,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;
     }
 
@@ -6094,12 +6836,14 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
 
       if (modifier != EXPAND_NORMAL)
        result = force_operand (result, NULL);
-      tmp = expand_expr (offset, NULL, tmode, EXPAND_NORMAL);
+      tmp = expand_expr (offset, NULL_RTX, tmode, 
+                        modifier == EXPAND_INITIALIZER
+                         ? EXPAND_INITIALIZER : EXPAND_NORMAL);
 
       result = convert_memory_address (tmode, result);
       tmp = convert_memory_address (tmode, tmp);
 
-      if (modifier == EXPAND_SUM)
+      if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
        result = gen_rtx_PLUS (tmode, result, tmp);
       else
        {
@@ -6158,6 +6902,89 @@ expand_expr_addr_expr (tree exp, rtx target, enum machine_mode tmode,
   return result;
 }
 
+/* Generate code for computing CONSTRUCTOR EXP.
+   An rtx for the computed value is returned.  If AVOID_TEMP_MEM
+   is TRUE, instead of creating a temporary variable in memory
+   NULL is returned and the caller needs to handle it differently.  */
+
+static rtx
+expand_constructor (tree exp, rtx target, enum expand_modifier modifier,
+                   bool avoid_temp_mem)
+{
+  tree type = TREE_TYPE (exp);
+  enum machine_mode mode = TYPE_MODE (type);
+
+  /* Try to avoid creating a temporary at all.  This is possible
+     if all of the initializer is zero.
+     FIXME: try to handle all [0..255] initializers we can handle
+     with memset.  */
+  if (TREE_STATIC (exp)
+      && !TREE_ADDRESSABLE (exp)
+      && target != 0 && mode == BLKmode
+      && all_zeros_p (exp))
+    {
+      clear_storage (target, expr_size (exp), BLOCK_OP_NORMAL);
+      return target;
+    }
+
+  /* All elts simple constants => refer to a constant in memory.  But
+     if this is a non-BLKmode mode, let it store a field at a time
+     since that should make a CONST_INT or CONST_DOUBLE when we
+     fold.  Likewise, if we have a target we can use, it is best to
+     store directly into the target unless the type is large enough
+     that memcpy will be used.  If we are making an initializer and
+     all operands are constant, put it in memory as well.
+
+     FIXME: Avoid trying to fill vector constructors piece-meal.
+     Output them with output_constant_def below unless we're sure
+     they're zeros.  This should go away when vector initializers
+     are treated like VECTOR_CST instead of arrays.  */
+  if ((TREE_STATIC (exp)
+       && ((mode == BLKmode
+           && ! (target != 0 && safe_from_p (target, exp, 1)))
+                 || TREE_ADDRESSABLE (exp)
+                 || (host_integerp (TYPE_SIZE_UNIT (type), 1)
+                     && (! MOVE_BY_PIECES_P
+                                    (tree_low_cst (TYPE_SIZE_UNIT (type), 1),
+                                     TYPE_ALIGN (type)))
+                     && ! mostly_zeros_p (exp))))
+      || ((modifier == EXPAND_INITIALIZER || modifier == EXPAND_CONST_ADDRESS)
+         && TREE_CONSTANT (exp)))
+    {
+      rtx constructor;
+
+      if (avoid_temp_mem)
+       return NULL_RTX;
+
+      constructor = expand_expr_constant (exp, 1, modifier);
+
+      if (modifier != EXPAND_CONST_ADDRESS
+         && modifier != EXPAND_INITIALIZER
+         && modifier != EXPAND_SUM)
+       constructor = validize_mem (constructor);
+
+      return constructor;
+    }
+
+  /* Handle calls that pass values in multiple non-contiguous
+     locations.  The Irix 6 ABI has examples of this.  */
+  if (target == 0 || ! safe_from_p (target, exp, 1)
+      || GET_CODE (target) == PARALLEL || modifier == EXPAND_STACK_PARM)
+    {
+      if (avoid_temp_mem)
+       return NULL_RTX;
+
+      target
+       = assign_temp (build_qualified_type (type, (TYPE_QUALS (type)
+                                                   | (TREE_READONLY (exp)
+                                                      * TYPE_QUAL_CONST))),
+                      0, TREE_ADDRESSABLE (exp), 1);
+    }
+
+  store_constructor (exp, target, 0, int_expr_size (exp));
+  return target;
+}
+
 
 /* expand_expr: generate code for computing expression EXP.
    An rtx for the computed value is returned.  The value is never null.
@@ -6219,7 +7046,8 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
 
   /* Handle ERROR_MARK before anybody tries to access its type.  */
   if (TREE_CODE (exp) == ERROR_MARK
-      || TREE_CODE (TREE_TYPE (exp)) == ERROR_MARK)
+      || TREE_CODE (exp) == PREDICT_EXPR
+      || (!GIMPLE_TUPLE_P (exp) && TREE_CODE (TREE_TYPE (exp)) == ERROR_MARK))
     {
       ret = CONST0_RTX (tmode);
       return ret ? ret : const0_rtx;
@@ -6245,10 +7073,10 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
     {
       location_t saved_location = input_location;
       input_location = EXPR_LOCATION (exp);
-      emit_line_note (input_location);
+      set_curr_insn_source_location (input_location);
 
       /* Record where the insns produced belong.  */
-      record_block_change (TREE_BLOCK (exp));
+      set_curr_insn_block (TREE_BLOCK (exp));
 
       ret = expand_expr_real_1 (exp, target, tmode, modifier, alt_rtl);
 
@@ -6288,45 +7116,47 @@ static rtx
 expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                    enum expand_modifier modifier, rtx *alt_rtl)
 {
-  rtx op0, op1, temp;
-  tree type = TREE_TYPE (exp);
+  rtx op0, op1, op2, temp, decl_rtl;
+  tree type;
   int unsignedp;
   enum machine_mode mode;
   enum tree_code code = TREE_CODE (exp);
   optab this_optab;
   rtx subtarget, original_target;
   int ignore;
-  tree context;
-  bool reduce_bit_field = false;
-#define REDUCE_BIT_FIELD(expr) (reduce_bit_field && !ignore              \
+  tree context, subexp0, subexp1;
+  bool reduce_bit_field;
+#define REDUCE_BIT_FIELD(expr) (reduce_bit_field                         \
                                 ? reduce_to_bit_field_precision ((expr), \
                                                                  target, \
                                                                  type)   \
                                 : (expr))
 
-  mode = TYPE_MODE (type);
-  unsignedp = TYPE_UNSIGNED (type);
-  if (lang_hooks.reduce_bit_field_operations
-      && TREE_CODE (type) == INTEGER_TYPE
-      && GET_MODE_PRECISION (mode) > TYPE_PRECISION (type))
-    {
-      /* An operation in what may be a bit-field type needs the
-        result to be reduced to the precision of the bit-field type,
-        which is narrower than that of the type's mode.  */
-      reduce_bit_field = true;
-      if (modifier == EXPAND_STACK_PARM)
-       target = 0;
+  if (GIMPLE_STMT_P (exp))
+    {
+      type = void_type_node;
+      mode = VOIDmode;
+      unsignedp = 0;
+    }
+  else
+    {
+      type = TREE_TYPE (exp);
+      mode = TYPE_MODE (type);
+      unsignedp = TYPE_UNSIGNED (type);
     }
 
-  /* Use subtarget as the target for operand 0 of a binary operation.  */
-  subtarget = get_subtarget (target);
-  original_target = target;
   ignore = (target == const0_rtx
-           || ((code == NON_LVALUE_EXPR || code == NOP_EXPR
-                || code == CONVERT_EXPR || code == COND_EXPR
-                || code == VIEW_CONVERT_EXPR)
+           || ((code == NOP_EXPR || code == CONVERT_EXPR 
+                || code == COND_EXPR || code == VIEW_CONVERT_EXPR)
                && TREE_CODE (type) == VOID_TYPE));
 
+  /* An operation in what may be a bit-field type needs the
+     result to be reduced to the precision of the bit-field type,
+     which is narrower than that of the type's mode.  */
+  reduce_bit_field = (!ignore
+                     && TREE_CODE (type) == INTEGER_TYPE
+                     && GET_MODE_PRECISION (mode) > TYPE_PRECISION (type));
+
   /* If we are going to ignore this result, we need only do something
      if there is a side-effect somewhere in the expression.  If there
      is, short-circuit the most common cases here.  Note that we must
@@ -6375,19 +7205,13 @@ 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)))
+  if (reduce_bit_field && modifier == EXPAND_STACK_PARM)
     target = 0;
 
+  /* Use subtarget as the target for operand 0 of a binary operation.  */
+  subtarget = get_subtarget (target);
+  original_target = target;
+
   switch (code)
     {
     case LABEL_DECL:
@@ -6418,11 +7242,23 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
          && (TREE_STATIC (exp) || DECL_EXTERNAL (exp)))
        layout_decl (exp, 0);
 
+      /* TLS emulation hook - replace __thread vars with
+        *__emutls_get_address (&_emutls.var).  */
+      if (! targetm.have_tls
+         && TREE_CODE (exp) == VAR_DECL
+         && DECL_THREAD_LOCAL_P (exp))
+       {
+         exp = build_fold_indirect_ref (emutls_var_address (exp));
+         return expand_expr_real_1 (exp, target, tmode, modifier, NULL);
+       }
+
       /* ... fall through ...  */
 
     case FUNCTION_DECL:
     case RESULT_DECL:
-      gcc_assert (DECL_RTL (exp));
+      decl_rtl = DECL_RTL (exp);
+      gcc_assert (decl_rtl);
+      decl_rtl = copy_rtx (decl_rtl);
 
       /* Ensure variable marked as used even if it doesn't go through
         a parser.  If it hasn't be used yet, write out an external
@@ -6449,27 +7285,22 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
         from its initializer, while the initializer is still being parsed.
         See expand_decl.  */
 
-      if (MEM_P (DECL_RTL (exp))
-              && REG_P (XEXP (DECL_RTL (exp), 0)))
-       temp = validize_mem (DECL_RTL (exp));
+      if (MEM_P (decl_rtl) && REG_P (XEXP (decl_rtl, 0)))
+       temp = validize_mem (decl_rtl);
 
-      /* If DECL_RTL is memory, we are in the normal case and either
-        the address is not valid or it is not a register and -fforce-addr
-        is specified, get the address into a register.  */
+      /* If DECL_RTL is memory, we are in the normal case and the
+        address is not valid, get the address into a register.  */
 
-      else if (MEM_P (DECL_RTL (exp))
-              && modifier != EXPAND_CONST_ADDRESS
-              && modifier != EXPAND_SUM
-              && modifier != EXPAND_INITIALIZER
-              && (! memory_address_p (DECL_MODE (exp),
-                                      XEXP (DECL_RTL (exp), 0))
-                  || (flag_force_addr
-                      && !REG_P (XEXP (DECL_RTL (exp), 0)))))
+      else if (MEM_P (decl_rtl) && modifier != EXPAND_INITIALIZER)
        {
          if (alt_rtl)
-           *alt_rtl = DECL_RTL (exp);
-         temp = replace_equiv_address (DECL_RTL (exp),
-                                       copy_rtx (XEXP (DECL_RTL (exp), 0)));
+           *alt_rtl = decl_rtl;
+         decl_rtl = use_anchored_address (decl_rtl);
+         if (modifier != EXPAND_CONST_ADDRESS
+             && modifier != EXPAND_SUM
+             && !memory_address_p (DECL_MODE (exp), XEXP (decl_rtl, 0)))
+           temp = replace_equiv_address (decl_rtl,
+                                         copy_rtx (XEXP (decl_rtl, 0)));
        }
 
       /* If we got something, return it.  But first, set the alignment
@@ -6486,48 +7317,54 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
         must be a promoted value.  We return a SUBREG of the wanted mode,
         but mark it so that we know that it was already extended.  */
 
-      if (REG_P (DECL_RTL (exp))
-         && GET_MODE (DECL_RTL (exp)) != DECL_MODE (exp))
+      if (REG_P (decl_rtl)
+         && GET_MODE (decl_rtl) != DECL_MODE (exp))
        {
          enum machine_mode pmode;
-         
+
          /* Get the signedness used for this variable.  Ensure we get the
             same mode we got when the variable was declared.  */
          pmode = promote_mode (type, DECL_MODE (exp), &unsignedp,
-                               (TREE_CODE (exp) == RESULT_DECL ? 1 : 0));
-         gcc_assert (GET_MODE (DECL_RTL (exp)) == pmode);
+                               (TREE_CODE (exp) == RESULT_DECL
+                                || TREE_CODE (exp) == PARM_DECL) ? 1 : 0);
+         gcc_assert (GET_MODE (decl_rtl) == pmode);
 
-         temp = gen_lowpart_SUBREG (mode, DECL_RTL (exp));
+         temp = gen_lowpart_SUBREG (mode, decl_rtl);
          SUBREG_PROMOTED_VAR_P (temp) = 1;
          SUBREG_PROMOTED_UNSIGNED_SET (temp, unsignedp);
          return temp;
        }
 
-      return DECL_RTL (exp);
+      return decl_rtl;
 
     case INTEGER_CST:
       temp = immed_double_const (TREE_INT_CST_LOW (exp),
                                 TREE_INT_CST_HIGH (exp), mode);
 
-      /* ??? If overflow is set, fold will have done an incomplete job,
-        which can result in (plus xx (const_int 0)), which can get
-        simplified by validate_replace_rtx during virtual register
-        instantiation, which can result in unrecognizable insns.
-        Avoid this by forcing all overflows into registers.  */
-      if (TREE_CONSTANT_OVERFLOW (exp)
-         && modifier != EXPAND_INITIALIZER)
-       temp = force_reg (mode, temp);
-
       return temp;
 
     case VECTOR_CST:
-      if (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (exp))) == MODE_VECTOR_INT
-         || 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)),
-                           ignore ? const0_rtx : target, tmode, modifier);
+      {
+       tree tmp = NULL_TREE;
+       if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
+           || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT
+           || GET_MODE_CLASS (mode) == MODE_VECTOR_FRACT
+           || GET_MODE_CLASS (mode) == MODE_VECTOR_UFRACT
+           || GET_MODE_CLASS (mode) == MODE_VECTOR_ACCUM
+           || GET_MODE_CLASS (mode) == MODE_VECTOR_UACCUM)
+         return const_vector_from_tree (exp);
+       if (GET_MODE_CLASS (mode) == MODE_INT)
+         {
+           tree type_for_mode = lang_hooks.types.type_for_mode (mode, 1);
+           if (type_for_mode)
+             tmp = fold_unary (VIEW_CONVERT_EXPR, type_for_mode, exp);
+         }
+       if (!tmp)
+         tmp = build_constructor_from_list (type,
+                                            TREE_VECTOR_CST_ELTS (exp));
+       return expand_expr (tmp, ignore ? const0_rtx : target,
+                           tmode, modifier);
+      }
 
     case CONST_DECL:
       return expand_expr (DECL_INITIAL (exp), target, VOIDmode, modifier);
@@ -6546,6 +7383,10 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       return CONST_DOUBLE_FROM_REAL_VALUE (TREE_REAL_CST (exp),
                                           TYPE_MODE (TREE_TYPE (exp)));
 
+    case FIXED_CST:
+      return CONST_FIXED_FROM_FIXED_VALUE (TREE_FIXED_CST (exp),
+                                          TYPE_MODE (TREE_TYPE (exp)));
+
     case COMPLEX_CST:
       /* Handle evaluating a complex constant in a CONCAT target.  */
       if (original_target && GET_CODE (original_target) == CONCAT)
@@ -6557,8 +7398,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
          itarg = XEXP (original_target, 1);
 
          /* Move the real and imaginary parts separately.  */
-         op0 = expand_expr (TREE_REALPART (exp), rtarg, mode, 0);
-         op1 = expand_expr (TREE_IMAGPART (exp), itarg, mode, 0);
+         op0 = expand_expr (TREE_REALPART (exp), rtarg, mode, EXPAND_NORMAL);
+         op1 = expand_expr (TREE_IMAGPART (exp), itarg, mode, EXPAND_NORMAL);
 
          if (op0 != rtarg)
            emit_move_insn (rtarg, op0);
@@ -6571,7 +7412,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       /* ... fall through ...  */
 
     case STRING_CST:
-      temp = output_constant_def (exp, 1);
+      temp = expand_expr_constant (exp, 1, modifier);
 
       /* temp contains a constant address.
         On RISC machines where a constant address isn't valid,
@@ -6579,8 +7420,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       if (modifier != EXPAND_CONST_ADDRESS
          && modifier != EXPAND_INITIALIZER
          && modifier != EXPAND_SUM
-         && (! memory_address_p (mode, XEXP (temp, 0))
-             || flag_force_addr))
+         && ! memory_address_p (mode, XEXP (temp, 0)))
        return replace_equiv_address (temp,
                                      copy_rtx (XEXP (temp, 0)));
       return temp;
@@ -6624,77 +7464,22 @@ 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, EXPAND_NORMAL);
 
          return const0_rtx;
        }
 
-      /* All elts simple constants => refer to a constant in memory.  But
-        if this is a non-BLKmode mode, let it store a field at a time
-        since that should make a CONST_INT or CONST_DOUBLE when we
-        fold.  Likewise, if we have a target we can use, it is best to
-        store directly into the target unless the type is large enough
-        that memcpy will be used.  If we are making an initializer and
-        all operands are constant, put it in memory as well.
-
-       FIXME: Avoid trying to fill vector constructors piece-meal.
-       Output them with output_constant_def below unless we're sure
-       they're zeros.  This should go away when vector initializers
-       are treated like VECTOR_CST instead of arrays.
-      */
-      else if ((TREE_STATIC (exp)
-               && ((mode == BLKmode
-                    && ! (target != 0 && safe_from_p (target, exp, 1)))
-                   || TREE_ADDRESSABLE (exp)
-                   || (host_integerp (TYPE_SIZE_UNIT (type), 1)
-                       && (! MOVE_BY_PIECES_P
-                           (tree_low_cst (TYPE_SIZE_UNIT (type), 1),
-                            TYPE_ALIGN (type)))
-                       && ! mostly_zeros_p (exp))))
-              || ((modifier == EXPAND_INITIALIZER
-                   || modifier == EXPAND_CONST_ADDRESS)
-                  && TREE_CONSTANT (exp)))
-       {
-         rtx constructor = output_constant_def (exp, 1);
-
-         if (modifier != EXPAND_CONST_ADDRESS
-             && modifier != EXPAND_INITIALIZER
-             && modifier != EXPAND_SUM)
-           constructor = validize_mem (constructor);
-
-         return constructor;
-       }
-      else
-       {
-         /* Handle calls that pass values in multiple non-contiguous
-            locations.  The Irix 6 ABI has examples of this.  */
-         if (target == 0 || ! safe_from_p (target, exp, 1)
-             || GET_CODE (target) == PARALLEL
-             || modifier == EXPAND_STACK_PARM)
-           target
-             = assign_temp (build_qualified_type (type,
-                                                  (TYPE_QUALS (type)
-                                                   | (TREE_READONLY (exp)
-                                                      * TYPE_QUAL_CONST))),
-                            0, TREE_ADDRESSABLE (exp), 1);
-
-         store_constructor (exp, target, 0, int_expr_size (exp));
-         return target;
-       }
+      return expand_constructor (exp, target, modifier, false);
 
     case MISALIGNED_INDIRECT_REF:
     case ALIGN_INDIRECT_REF:
     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)
          {
@@ -6717,14 +7502,51 @@ 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
+                       || modifier == EXPAND_STACK_PARM);
+
+           /* The vectorizer should have already checked the mode.  */
+           icode = optab_handler (movmisalign_optab, 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 TARGET_MEM_REF:
+      {
+       struct mem_address addr;
+
+       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;
+
     case ARRAY_REF:
 
       {
@@ -6758,16 +7580,17 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
            && ! TREE_SIDE_EFFECTS (array)
            && TREE_CODE (index) == INTEGER_CST)
          {
-           tree elem;
+           unsigned HOST_WIDE_INT ix;
+           tree field, value;
 
-           for (elem = CONSTRUCTOR_ELTS (array);
-                (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 (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
@@ -6785,29 +7608,64 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
                if (TREE_CODE (init) == CONSTRUCTOR)
                  {
-                   tree elem;
-
-                   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);
+                   unsigned HOST_WIDE_INT ix;
+                   tree field, value;
+
+                   FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), ix,
+                                             field, value)
+                     if (tree_int_cst_equal (field, index))
+                       {
+                         if (TREE_SIDE_EFFECTS (value))
+                           break;
+
+                         if (TREE_CODE (value) == CONSTRUCTOR)
+                           {
+                             /* If VALUE is a CONSTRUCTOR, this
+                                optimization is only useful if
+                                this doesn't store the CONSTRUCTOR
+                                into memory.  If it does, it is more
+                                efficient to just load the data from
+                                the array directly.  */
+                             rtx ret = expand_constructor (value, target,
+                                                           modifier, true);
+                             if (ret == NULL_RTX)
+                               break;
+                           }
+
+                         return expand_expr (fold (value), target, tmode,
+                                             modifier);
+                       }
                  }
-               else if (TREE_CODE (init) == STRING_CST
-                        && 0 > compare_tree_int (index,
-                                                 TREE_STRING_LENGTH (init)))
+               else if(TREE_CODE (init) == STRING_CST)
                  {
-                   tree type = TREE_TYPE (TREE_TYPE (init));
-                   enum machine_mode mode = TYPE_MODE (type);
+                   tree index1 = index;
+                   tree low_bound = array_ref_low_bound (exp);
+                   index1 = fold_convert (sizetype, TREE_OPERAND (exp, 1));
 
-                   if (GET_MODE_CLASS (mode) == MODE_INT
-                       && GET_MODE_SIZE (mode) == 1)
-                     return gen_int_mode (TREE_STRING_POINTER (init)
-                                          [TREE_INT_CST_LOW (index)], mode);
+                   /* Optimize the special-case of a zero lower bound.
+
+                      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,l (ARRAY
+                      +(INDEX-(unsigned char)1)) becomes ((ARRAY+(-(unsigned char)1))
+                      +INDEX), which becomes (ARRAY+255+INDEX).  Opps!)  */
+
+                   if (! integer_zerop (low_bound))
+                     index1 = size_diffop (index1, fold_convert (sizetype,
+                                                                 low_bound));
+
+                   if (0 > compare_tree_int (index1,
+                                             TREE_STRING_LENGTH (init)))
+                     {
+                       tree type = TREE_TYPE (TREE_TYPE (init));
+                       enum machine_mode mode = TYPE_MODE (type);
+
+                       if (GET_MODE_CLASS (mode) == MODE_INT
+                           && GET_MODE_SIZE (mode) == 1)
+                         return gen_int_mode (TREE_STRING_POINTER (init)
+                                              [TREE_INT_CST_LOW (index1)],
+                                              mode);
+                     }
                  }
              }
          }
@@ -6819,11 +7677,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,
@@ -6831,24 +7690,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);
@@ -6880,7 +7736,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
@@ -6905,26 +7761,34 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                          || modifier == EXPAND_STACK_PARM)
                         ? modifier : EXPAND_NORMAL);
 
-       /* If this is a constant, put it into a register if it is a
-          legitimate constant and OFFSET is 0 and memory if it isn't.  */
+       /* If this is a constant, put it into a register if it is a legitimate
+          constant, OFFSET is 0, and we won't try to extract outside the
+          register (in case we were passed a partially uninitialized object
+          or a view_conversion to a larger size) or a BLKmode piece of it
+          (e.g. if it is unchecked-converted to a record type in Ada).  Force
+          the constant to memory otherwise.  */
        if (CONSTANT_P (op0))
          {
            enum machine_mode mode = TYPE_MODE (TREE_TYPE (tem));
            if (mode != BLKmode && LEGITIMATE_CONSTANT_P (op0)
-               && offset == 0)
+               && offset == 0
+               && mode1 != BLKmode
+               && bitpos + bitsize <= GET_MODE_BITSIZE (mode))
              op0 = force_reg (mode, op0);
            else
              op0 = validize_mem (force_const_mem (mode, op0));
          }
 
-       /* Otherwise, if this object not in memory and we either have an
-          offset or a BLKmode result, put it there.  This case can't occur in
-          C, but can in Ada if we have unchecked conversion of an expression
-          from a scalar type to an array or record type or for an
-          ARRAY_RANGE_REF whose type is BLKmode.  */
+       /* Otherwise, if this object not in memory and we either have an
+          offset, a BLKmode result, or a reference outside the object, put it
+          there.  Such cases can occur in Ada if we have unchecked conversion
+          of an expression from a scalar type to an array or record type or
+          for an ARRAY_RANGE_REF whose type is BLKmode.  */
        else if (!MEM_P (op0)
                 && (offset != 0
-                    || (code == ARRAY_RANGE_REF && mode == BLKmode)))
+                    || mode1 == BLKmode
+                    || (bitpos + bitsize
+                        > GET_MODE_BITSIZE (GET_MODE (op0)))))
          {
            tree nt = build_qualified_type (TREE_TYPE (tem),
                                            (TYPE_QUALS (TREE_TYPE (tem))
@@ -7091,9 +7955,18 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
               necessarily be constant.  */
            if (mode == BLKmode)
              {
-               rtx new
-                 = assign_stack_temp_for_type
-                   (ext_mode, GET_MODE_BITSIZE (ext_mode), 0, type);
+               HOST_WIDE_INT size = GET_MODE_BITSIZE (ext_mode);
+               rtx new;
+
+               /* If the reference doesn't use the alias set of its type,
+                  we cannot create the temporary using that type.  */
+               if (component_uses_parent_alias_set (exp))
+                 {
+                   new = assign_stack_local (ext_mode, size, 0);
+                   set_mem_alias_set (new, get_alias_set (exp));
+                 }
+               else
+                 new = assign_stack_temp_for_type (ext_mode, size, 0, type);
 
                emit_move_insn (new, op0);
                op0 = copy_rtx (new);
@@ -7139,26 +8012,40 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       return expand_expr (OBJ_TYPE_REF_EXPR (exp), target, tmode, modifier);
 
     case CALL_EXPR:
-      /* Check for a built-in function.  */
-      if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
-         && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
-             == FUNCTION_DECL)
-         && DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
-       {
-         if (DECL_BUILT_IN_CLASS (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
-             == BUILT_IN_FRONTEND)
-           return lang_hooks.expand_expr (exp, original_target,
-                                          tmode, modifier,
-                                          alt_rtl);
-         else
-           return expand_builtin (exp, target, subtarget, tmode, ignore);
-       }
-
+      /* All valid uses of __builtin_va_arg_pack () are removed during
+        inlining.  */
+      if (CALL_EXPR_VA_ARG_PACK (exp))
+       error ("%Kinvalid use of %<__builtin_va_arg_pack ()%>", exp);
+      {
+       tree fndecl = get_callee_fndecl (exp), attr;
+
+       if (fndecl
+           && (attr = lookup_attribute ("error",
+                                        DECL_ATTRIBUTES (fndecl))) != NULL)
+         error ("%Kcall to %qs declared with attribute error: %s",
+                exp, lang_hooks.decl_printable_name (fndecl, 1),
+                TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr))));
+       if (fndecl
+           && (attr = lookup_attribute ("warning",
+                                        DECL_ATTRIBUTES (fndecl))) != NULL)
+         warning (0, "%Kcall to %qs declared with attribute warning: %s",
+                  exp, lang_hooks.decl_printable_name (fndecl, 1),
+                  TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr))));
+
+       /* Check for a built-in function.  */
+       if (fndecl && DECL_BUILT_IN (fndecl))
+         {
+           if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_FRONTEND)
+             return lang_hooks.expand_expr (exp, original_target,
+                                            tmode, modifier, alt_rtl);
+           else
+             return expand_builtin (exp, target, subtarget, tmode, ignore);
+         }
+      }
       return expand_call (exp, target, ignore);
 
-    case NON_LVALUE_EXPR:
-    case NOP_EXPR:
-    case CONVERT_EXPR:
+    case PAREN_EXPR:
+    CASE_CONVERT:
       if (TREE_OPERAND (exp, 0) == error_mark_node)
        return const0_rtx;
 
@@ -7190,12 +8077,13 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
            /* Store data into beginning of memory target.  */
            store_expr (TREE_OPERAND (exp, 0),
                        adjust_address (target, TYPE_MODE (valtype), 0),
-                       modifier == EXPAND_STACK_PARM);
+                       modifier == EXPAND_STACK_PARM,
+                       false);
 
          else
            {
              gcc_assert (REG_P (target));
-             
+
              /* Store this field into a union of the proper type.  */
              store_field (target,
                           MIN ((int_size_in_bytes (TREE_TYPE
@@ -7203,7 +8091,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                                 * BITS_PER_UNIT),
                                (HOST_WIDE_INT) GET_MODE_BITSIZE (mode)),
                           0, TYPE_MODE (valtype), TREE_OPERAND (exp, 0),
-                          type, 0);
+                          type, 0, false);
            }
 
          /* Return the entire union.  */
@@ -7225,7 +8113,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
          return REDUCE_BIT_FIELD (op0);
        }
 
-      op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, modifier);
+      op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode,
+                        modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier);
       if (GET_MODE (op0) == mode)
        ;
 
@@ -7263,22 +8152,31 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
     case VIEW_CONVERT_EXPR:
       op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, modifier);
 
-      /* If the input and output modes are both the same, we are done.
-        Otherwise, if neither mode is BLKmode and both are integral and within
-        a word, we can use gen_lowpart.  If neither is true, make sure the
-        operand is in memory and convert the MEM to the new mode.  */
+      /* If the input and output modes are both the same, we are done.  */
       if (TYPE_MODE (type) == GET_MODE (op0))
        ;
+      /* If neither mode is BLKmode, and both modes are the same size
+        then we can use gen_lowpart.  */
       else if (TYPE_MODE (type) != BLKmode && GET_MODE (op0) != BLKmode
-              && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
-              && GET_MODE_CLASS (TYPE_MODE (type)) == MODE_INT
-              && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_WORD
-              && GET_MODE_SIZE (GET_MODE (op0)) <= UNITS_PER_WORD)
-       op0 = gen_lowpart (TYPE_MODE (type), op0);
+              && GET_MODE_SIZE (TYPE_MODE (type))
+                  == GET_MODE_SIZE (GET_MODE (op0)))
+       {
+         if (GET_CODE (op0) == SUBREG)
+           op0 = force_reg (GET_MODE (op0), op0);
+         op0 = gen_lowpart (TYPE_MODE (type), op0);
+       }
+      /* If both modes are integral, then we can convert from one to the
+        other.  */
+      else if (SCALAR_INT_MODE_P (GET_MODE (op0))
+              && SCALAR_INT_MODE_P (TYPE_MODE (type)))
+       op0 = convert_modes (TYPE_MODE (type), GET_MODE (op0), op0,
+                            TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
+      /* As a last resort, spill op0 to memory, and reload it in a
+        different mode.  */
       else if (!MEM_P (op0))
        {
          /* If the operand is not a MEM, force it into memory.  Since we
-            are going to be be changing the mode of the MEM, don't call
+            are going to be changing the mode of the MEM, don't call
             force_const_mem for constants because we don't allow pool
             constants to change mode.  */
          tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
@@ -7334,7 +8232,61 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
       return op0;
 
+    case POINTER_PLUS_EXPR: 
+      /* Even though the sizetype mode and the pointer's mode can be different
+         expand is able to handle this correctly and get the correct result out 
+         of the PLUS_EXPR code.  */
     case PLUS_EXPR:
+
+      /* Check if this is a case for multiplication and addition.  */
+      if ((TREE_CODE (type) == INTEGER_TYPE
+          || TREE_CODE (type) == FIXED_POINT_TYPE)
+         && TREE_CODE (TREE_OPERAND (exp, 0)) == MULT_EXPR)
+       {
+         tree subsubexp0, subsubexp1;
+         enum tree_code code0, code1, this_code;
+
+         subexp0 = TREE_OPERAND (exp, 0);
+         subsubexp0 = TREE_OPERAND (subexp0, 0);
+         subsubexp1 = TREE_OPERAND (subexp0, 1);
+         code0 = TREE_CODE (subsubexp0);
+         code1 = TREE_CODE (subsubexp1);
+         this_code = TREE_CODE (type) == INTEGER_TYPE ? NOP_EXPR
+                                                      : FIXED_CONVERT_EXPR;
+         if (code0 == this_code && code1 == this_code
+             && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
+                 < TYPE_PRECISION (TREE_TYPE (subsubexp0)))
+             && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
+                 == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp1, 0))))
+             && (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
+                 == TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subsubexp1, 0)))))
+           {
+             tree op0type = TREE_TYPE (TREE_OPERAND (subsubexp0, 0));
+             enum machine_mode innermode = TYPE_MODE (op0type);
+             bool zextend_p = TYPE_UNSIGNED (op0type);
+             bool sat_p = TYPE_SATURATING (TREE_TYPE (subsubexp0));
+             if (sat_p == 0)
+               this_optab = zextend_p ? umadd_widen_optab : smadd_widen_optab;
+             else
+               this_optab = zextend_p ? usmadd_widen_optab
+                                      : ssmadd_widen_optab;
+             if (mode == GET_MODE_2XWIDER_MODE (innermode)
+                 && (optab_handler (this_optab, mode)->insn_code
+                     != CODE_FOR_nothing))
+               {
+                 expand_operands (TREE_OPERAND (subsubexp0, 0),
+                                  TREE_OPERAND (subsubexp1, 0),
+                                  NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+                 op2 = expand_expr (TREE_OPERAND (exp, 1), subtarget,
+                                    VOIDmode, EXPAND_NORMAL);
+                 temp = expand_ternary_op (mode, this_optab, op0, op1, op2,
+                                           target, unsignedp);
+                 gcc_assert (temp);
+                 return REDUCE_BIT_FIELD (temp);
+               }
+           }
+       }
+
       /* If we are adding a constant, a VAR_DECL that is sp, fp, or ap, and
         something else, make sure we add the register to the constant and
         then to the other thing.  This case can occur during strength
@@ -7395,7 +8347,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
            }
 
          else if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
-                  && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_INT
+                  && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
                   && TREE_CONSTANT (TREE_OPERAND (exp, 0)))
            {
              rtx constant_part;
@@ -7449,6 +8401,55 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       return REDUCE_BIT_FIELD (simplify_gen_binary (PLUS, mode, op0, op1));
 
     case MINUS_EXPR:
+      /* Check if this is a case for multiplication and subtraction.  */
+      if ((TREE_CODE (type) == INTEGER_TYPE
+          || TREE_CODE (type) == FIXED_POINT_TYPE)
+         && TREE_CODE (TREE_OPERAND (exp, 1)) == MULT_EXPR)
+       {
+         tree subsubexp0, subsubexp1;
+         enum tree_code code0, code1, this_code;
+
+         subexp1 = TREE_OPERAND (exp, 1);
+         subsubexp0 = TREE_OPERAND (subexp1, 0);
+         subsubexp1 = TREE_OPERAND (subexp1, 1);
+         code0 = TREE_CODE (subsubexp0);
+         code1 = TREE_CODE (subsubexp1);
+         this_code = TREE_CODE (type) == INTEGER_TYPE ? NOP_EXPR
+                                                      : FIXED_CONVERT_EXPR;
+         if (code0 == this_code && code1 == this_code
+             && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
+                 < TYPE_PRECISION (TREE_TYPE (subsubexp0)))
+             && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
+                 == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp1, 0))))
+             && (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
+                 == TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subsubexp1, 0)))))
+           {
+             tree op0type = TREE_TYPE (TREE_OPERAND (subsubexp0, 0));
+             enum machine_mode innermode = TYPE_MODE (op0type);
+             bool zextend_p = TYPE_UNSIGNED (op0type);
+             bool sat_p = TYPE_SATURATING (TREE_TYPE (subsubexp0));
+             if (sat_p == 0)
+               this_optab = zextend_p ? umsub_widen_optab : smsub_widen_optab;
+             else
+               this_optab = zextend_p ? usmsub_widen_optab
+                                      : ssmsub_widen_optab;
+             if (mode == GET_MODE_2XWIDER_MODE (innermode)
+                 && (optab_handler (this_optab, mode)->insn_code
+                     != CODE_FOR_nothing))
+               {
+                 expand_operands (TREE_OPERAND (subsubexp0, 0),
+                                  TREE_OPERAND (subsubexp1, 0),
+                                  NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+                 op2 = expand_expr (TREE_OPERAND (exp, 0), subtarget,
+                                    VOIDmode, EXPAND_NORMAL);
+                 temp = expand_ternary_op (mode, this_optab, op0, op1, op2,
+                                           target, unsignedp);
+                 gcc_assert (temp);
+                 return REDUCE_BIT_FIELD (temp);
+               }
+           }
+       }
+
       /* For initializers, we are allowed to return a MINUS of two
         symbolic constants.  Here we handle all cases when both operands
         are constant.  */
@@ -7490,6 +8491,12 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       goto binop2;
 
     case MULT_EXPR:
+      /* If this is a fixed-point operation, then we cannot use the code
+        below because "expand_mult" doesn't support sat/no-sat fixed-point
+         multiplications.   */
+      if (ALL_FIXED_POINT_MODE_P (mode))
+       goto binop;
+
       /* If first operand is constant, swap them.
         Thus the following special case checks need only
         check the second operand.  */
@@ -7528,7 +8535,43 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
         from a narrower type.  If this machine supports multiplying
         in that narrower type with a result in the desired type,
         do it that way, and avoid the explicit type-conversion.  */
-      if (TREE_CODE (TREE_OPERAND (exp, 0)) == NOP_EXPR
+
+      subexp0 = TREE_OPERAND (exp, 0);
+      subexp1 = TREE_OPERAND (exp, 1);
+      /* First, check if we have a multiplication of one signed and one
+        unsigned operand.  */
+      if (TREE_CODE (subexp0) == NOP_EXPR
+         && TREE_CODE (subexp1) == NOP_EXPR
+         && TREE_CODE (type) == INTEGER_TYPE
+         && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subexp0, 0)))
+             < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0))))
+         && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subexp0, 0)))
+             == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subexp1, 0))))
+         && (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subexp0, 0)))
+             != TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subexp1, 0)))))
+       {
+         enum machine_mode innermode
+           = TYPE_MODE (TREE_TYPE (TREE_OPERAND (subexp0, 0)));
+         this_optab = usmul_widen_optab;
+         if (mode == GET_MODE_WIDER_MODE (innermode))
+           {
+             if (optab_handler (this_optab, mode)->insn_code != CODE_FOR_nothing)
+               {
+                 if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subexp0, 0))))
+                   expand_operands (TREE_OPERAND (subexp0, 0),
+                                    TREE_OPERAND (subexp1, 0),
+                                    NULL_RTX, &op0, &op1, 0);
+                 else
+                   expand_operands (TREE_OPERAND (subexp0, 0),
+                                    TREE_OPERAND (subexp1, 0),
+                                    NULL_RTX, &op1, &op0, 0);
+
+                 goto binop3;
+               }
+           }
+       }
+      /* Check for a multiplication with matching signedness.  */
+      else if (TREE_CODE (TREE_OPERAND (exp, 0)) == NOP_EXPR
          && TREE_CODE (type) == INTEGER_TYPE
          && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
              < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0))))
@@ -7560,34 +8603,31 @@ 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)
+             if (optab_handler (this_optab, mode)->insn_code != CODE_FOR_nothing)
                {
                  if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
                    expand_operands (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
                                     TREE_OPERAND (exp, 1),
-                                    NULL_RTX, &op0, &op1, 0);
+                                    NULL_RTX, &op0, &op1, EXPAND_NORMAL);
                  else
                    expand_operands (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
                                     TREE_OPERAND (TREE_OPERAND (exp, 1), 0),
-                                    NULL_RTX, &op0, &op1, 0);
+                                    NULL_RTX, &op0, &op1, EXPAND_NORMAL);
                  goto binop3;
                }
-             else if (other_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing
+             else if (optab_handler (other_optab, mode)->insn_code != CODE_FOR_nothing
                       && innermode == word_mode)
                {
                  rtx htem, hipart;
-                 op0 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
-                                    NULL_RTX, VOIDmode, 0);
+                 op0 = expand_normal (TREE_OPERAND (TREE_OPERAND (exp, 0), 0));
                  if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
                    op1 = convert_modes (innermode, mode,
-                                        expand_expr (TREE_OPERAND (exp, 1),
-                                                     NULL_RTX, VOIDmode, 0),
+                                        expand_normal (TREE_OPERAND (exp, 1)),
                                         unsignedp);
                  else
-                   op1 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 1), 0),
-                                      NULL_RTX, VOIDmode, 0);
+                   op1 = expand_normal (TREE_OPERAND (TREE_OPERAND (exp, 1), 0));
                  temp = expand_binop (mode, other_optab, op0, op1, target,
                                       unsignedp, OPTAB_LIB_WIDEN);
                  hipart = gen_highpart (innermode, temp);
@@ -7609,6 +8649,12 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
     case CEIL_DIV_EXPR:
     case ROUND_DIV_EXPR:
     case EXACT_DIV_EXPR:
+      /* If this is a fixed-point operation, then we cannot use the code
+        below because "expand_divmod" doesn't support sat/no-sat fixed-point
+         divisions.   */
+      if (ALL_FIXED_POINT_MODE_P (mode))
+       goto binop;
+
       if (modifier == EXPAND_STACK_PARM)
        target = 0;
       /* Possible optimization: compute the dividend with EXPAND_SUM
@@ -7619,18 +8665,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:
@@ -7643,20 +8677,28 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                       subtarget, &op0, &op1, 0);
       return expand_divmod (1, code, mode, op0, op1, target, unsignedp);
 
-    case FIX_ROUND_EXPR:
-    case FIX_FLOOR_EXPR:
-    case FIX_CEIL_EXPR:
-      gcc_unreachable ();                      /* Not used for C.  */
+    case FIXED_CONVERT_EXPR:
+      op0 = expand_normal (TREE_OPERAND (exp, 0));
+      if (target == 0 || modifier == EXPAND_STACK_PARM)
+       target = gen_reg_rtx (mode);
+
+      if ((TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == INTEGER_TYPE
+          && TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))))
+          || (TREE_CODE (type) == INTEGER_TYPE && TYPE_UNSIGNED (type)))
+       expand_fixed_convert (target, op0, 1, TYPE_SATURATING (type));
+      else
+       expand_fixed_convert (target, op0, 0, TYPE_SATURATING (type));
+      return target;
 
     case FIX_TRUNC_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
+      op0 = expand_normal (TREE_OPERAND (exp, 0));
       if (target == 0 || modifier == EXPAND_STACK_PARM)
        target = gen_reg_rtx (mode);
       expand_fix (target, op0, unsignedp);
       return target;
 
     case FLOAT_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
+      op0 = expand_normal (TREE_OPERAND (exp, 0));
       if (target == 0 || modifier == EXPAND_STACK_PARM)
        target = gen_reg_rtx (mode);
       /* expand_float can't figure out what to do if FROM has VOIDmode.
@@ -7669,17 +8711,20 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       return target;
 
     case NEGATE_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget,
+                        VOIDmode, EXPAND_NORMAL);
       if (modifier == EXPAND_STACK_PARM)
        target = 0;
       temp = expand_unop (mode,
-                         optab_for_tree_code (NEGATE_EXPR, type),
+                         optab_for_tree_code (NEGATE_EXPR, type,
+                                              optab_default),
                          op0, target, 0);
       gcc_assert (temp);
       return REDUCE_BIT_FIELD (temp);
 
     case ABS_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget,
+                        VOIDmode, EXPAND_NORMAL);
       if (modifier == EXPAND_STACK_PARM)
        target = 0;
 
@@ -7711,7 +8756,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       /* First try to do it with a special MIN or MAX instruction.
         If that does not win, use a conditional jump to select the proper
         value.  */
-      this_optab = optab_for_tree_code (code, type);
+      this_optab = optab_for_tree_code (code, type, optab_default);
       temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
                           OPTAB_WIDEN);
       if (temp != 0)
@@ -7726,9 +8771,9 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       /* 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
@@ -7736,34 +8781,83 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       if (! CONSTANT_P (op1))
        op1 = force_reg (mode, op1);
 
-      if (target != op0)
-       emit_move_insn (target, op0);
+      {
+       enum rtx_code comparison_code;
+       rtx cmpop1 = op1;
 
-      op0 = gen_label_rtx ();
+       if (code == MAX_EXPR)
+         comparison_code = unsignedp ? GEU : GE;
+       else
+         comparison_code = unsignedp ? LEU : LE;
 
-      /* If this mode is an integer too wide to compare properly,
-        compare word by word.  Rely on cse to optimize constant cases.  */
-      if (GET_MODE_CLASS (mode) == MODE_INT
-         && ! can_compare_p (GE, mode, ccp_jump))
-       {
-         if (code == MAX_EXPR)
-           do_jump_by_parts_greater_rtx (mode, unsignedp, target, op1,
-                                         NULL_RTX, op0);
-         else
-           do_jump_by_parts_greater_rtx (mode, unsignedp, op1, target,
-                                         NULL_RTX, op0);
-       }
-      else
-       {
-         do_compare_rtx_and_jump (target, op1, code == MAX_EXPR ? GE : LE,
-                                  unsignedp, mode, NULL_RTX, NULL_RTX, op0);
-       }
+       /* Canonicalize to comparisons against 0.  */
+       if (op1 == const1_rtx)
+         {
+           /* Converting (a >= 1 ? a : 1) into (a > 0 ? a : 1)
+              or (a != 0 ? a : 1) for unsigned.
+              For MIN we are safe converting (a <= 1 ? a : 1)
+              into (a <= 0 ? a : 1)  */
+           cmpop1 = const0_rtx;
+           if (code == MAX_EXPR)
+             comparison_code = unsignedp ? NE : GT;
+         }
+       if (op1 == constm1_rtx && !unsignedp)
+         {
+           /* Converting (a >= -1 ? a : -1) into (a >= 0 ? a : -1)
+              and (a <= -1 ? a : -1) into (a < 0 ? a : -1) */
+           cmpop1 = const0_rtx;
+           if (code == MIN_EXPR)
+             comparison_code = LT;
+         }
+#ifdef HAVE_conditional_move
+       /* Use a conditional move if possible.  */
+       if (can_conditionally_move_p (mode))
+         {
+           rtx insn;
+
+           /* ??? 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, cmpop1, 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);
+
+       temp = gen_label_rtx ();
+       do_compare_rtx_and_jump (target, cmpop1, comparison_code,
+                                unsignedp, mode, NULL_RTX, NULL_RTX, temp);
+      }
       emit_move_insn (target, op1);
-      emit_label (op0);
+      emit_label (temp);
       return target;
 
     case BIT_NOT_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget,
+                        VOIDmode, EXPAND_NORMAL);
       if (modifier == EXPAND_STACK_PARM)
        target = 0;
       temp = expand_unop (mode, one_cmpl_optab, op0, target, 1);
@@ -7798,17 +8892,32 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
     case BIT_XOR_EXPR:
       goto binop;
 
-    case LSHIFT_EXPR:
-    case RSHIFT_EXPR:
     case LROTATE_EXPR:
     case RROTATE_EXPR:
+      gcc_assert (VECTOR_MODE_P (TYPE_MODE (type))
+                 || (GET_MODE_PRECISION (TYPE_MODE (type))
+                     == TYPE_PRECISION (type)));
+      /* fall through */
+
+    case LSHIFT_EXPR:
+    case RSHIFT_EXPR:
+      /* If this is a fixed-point operation, then we cannot use the code
+        below because "expand_shift" doesn't support sat/no-sat fixed-point
+         shifts.   */
+      if (ALL_FIXED_POINT_MODE_P (mode))
+       goto binop;
+
       if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
        subtarget = 0;
       if (modifier == EXPAND_STACK_PARM)
        target = 0;
-      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
-      return expand_shift (code, mode, op0, TREE_OPERAND (exp, 1), target,
+      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget,
+                        VOIDmode, EXPAND_NORMAL);
+      temp = expand_shift (code, mode, op0, TREE_OPERAND (exp, 1), target,
                           unsignedp);
+      if (code == LSHIFT_EXPR)
+       temp = REDUCE_BIT_FIELD (temp);
+      return temp;
 
       /* Could determine the answer when only additive constants differ.  Also,
         the addition of one can be handled by changing the condition.  */
@@ -7840,7 +8949,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
              == TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
        {
          temp = expand_expr (TREE_OPERAND (exp, 0), original_target,
-                             VOIDmode, 0);
+                             VOIDmode, EXPAND_NORMAL);
 
          /* If temp is constant, we can just compute the result.  */
          if (GET_CODE (temp) == CONST_INT)
@@ -7899,7 +9008,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
     case TRUTH_NOT_EXPR:
       if (modifier == EXPAND_STACK_PARM)
        target = 0;
-      op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0);
+      op0 = expand_expr (TREE_OPERAND (exp, 0), target,
+                        VOIDmode, EXPAND_NORMAL);
       /* The parser is careful to generate TRUTH_NOT_EXPR
         only with operands that are always zero or one.  */
       temp = expand_binop (mode, xor_optab, op0, const1_rtx,
@@ -7958,13 +9068,15 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
        op1 = gen_label_rtx ();
        jumpifnot (TREE_OPERAND (exp, 0), op0);
        store_expr (TREE_OPERAND (exp, 1), temp,
-                 modifier == EXPAND_STACK_PARM);
+                 modifier == EXPAND_STACK_PARM,
+                 false);
 
        emit_jump_insn (gen_jump (op1));
        emit_barrier ();
        emit_label (op0);
        store_expr (TREE_OPERAND (exp, 2), temp,
-                 modifier == EXPAND_STACK_PARM);
+                 modifier == EXPAND_STACK_PARM,
+                 false);
 
        emit_label (op1);
        OK_DEFER_POP;
@@ -7978,6 +9090,15 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       {
        tree lhs = TREE_OPERAND (exp, 0);
        tree rhs = TREE_OPERAND (exp, 1);
+       gcc_assert (ignore);
+       expand_assignment (lhs, rhs, false);
+       return const0_rtx;
+      }
+
+    case GIMPLE_MODIFY_STMT:
+      {
+       tree lhs = GIMPLE_STMT_OPERAND (exp, 0);
+       tree rhs = GIMPLE_STMT_OPERAND (exp, 1);
 
        gcc_assert (ignore);
 
@@ -7998,21 +9119,18 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
            && integer_onep (DECL_SIZE (TREE_OPERAND (TREE_OPERAND (rhs, 1), 1))))
          {
            rtx label = gen_label_rtx ();
-
+           int value = TREE_CODE (rhs) == BIT_IOR_EXPR;
            do_jump (TREE_OPERAND (rhs, 1),
-                    TREE_CODE (rhs) == BIT_IOR_EXPR ? label : 0,
-                    TREE_CODE (rhs) == BIT_AND_EXPR ? label : 0);
-           expand_assignment (lhs, convert (TREE_TYPE (rhs),
-                                            (TREE_CODE (rhs) == BIT_IOR_EXPR
-                                             ? integer_one_node
-                                             : integer_zero_node)));
+                    value ? label : 0,
+                    value ? 0 : label);
+           expand_assignment (lhs, build_int_cst (TREE_TYPE (rhs), value),
+                              MOVE_NONTEMPORAL (exp));
            do_pending_stack_adjust ();
            emit_label (label);
            return const0_rtx;
          }
 
-       expand_assignment (lhs, rhs);
-
+       expand_assignment (lhs, rhs, MOVE_NONTEMPORAL (exp));
        return const0_rtx;
       }
 
@@ -8028,8 +9146,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
     case COMPLEX_EXPR:
       /* 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);
+      op0 = expand_normal (TREE_OPERAND (exp, 0));
+      op1 = expand_normal (TREE_OPERAND (exp, 1));
 
       if (!target)
        target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
@@ -8041,11 +9159,11 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       return target;
 
     case REALPART_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
+      op0 = expand_normal (TREE_OPERAND (exp, 0));
       return read_complex_part (op0, false);
 
     case IMAGPART_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
+      op0 = expand_normal (TREE_OPERAND (exp, 0));
       return read_complex_part (op0, true);
 
     case RESX_EXPR:
@@ -8079,11 +9197,18 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       /* Lowered by gimplify.c.  */
       gcc_unreachable ();
 
+    case CHANGE_DYNAMIC_TYPE_EXPR:
+      /* This is ignored at the RTL level.  The tree level set
+        DECL_POINTER_ALIAS_SET of any variable to be 0, which is
+        overkill for the RTL layer but is all that we can
+        represent.  */
+      return const0_rtx;
+
     case EXC_PTR_EXPR:
-      return get_exception_pointer (cfun);
+      return get_exception_pointer ();
 
     case FILTER_EXPR:
-      return get_exception_filter (cfun);
+      return get_exception_filter ();
 
     case FDESC_EXPR:
       /* Function descriptors are not valid except for as
@@ -8110,21 +9235,141 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
     case REALIGN_LOAD_EXPR:
       {
-        tree oprnd0 = TREE_OPERAND (exp, 0); 
+        tree oprnd0 = TREE_OPERAND (exp, 0);
         tree oprnd1 = TREE_OPERAND (exp, 1);
         tree oprnd2 = TREE_OPERAND (exp, 2);
         rtx op2;
 
-        this_optab = optab_for_tree_code (code, type);
-        expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, 0);
-        op2 = expand_expr (oprnd2, NULL_RTX, VOIDmode, 0);
-        temp = expand_ternary_op (mode, this_optab, op0, op1, op2, 
+        this_optab = optab_for_tree_code (code, type, optab_default);
+        expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+        op2 = expand_normal (oprnd2);
+        temp = expand_ternary_op (mode, this_optab, op0, op1, op2,
                                  target, unsignedp);
-        if (temp == 0)
-          abort ();
+        gcc_assert (temp);
+        return temp;
+      }
+
+    case DOT_PROD_EXPR:
+      {
+       tree oprnd0 = TREE_OPERAND (exp, 0);
+       tree oprnd1 = TREE_OPERAND (exp, 1);
+       tree oprnd2 = TREE_OPERAND (exp, 2);
+       rtx op2;
+
+       expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+       op2 = expand_normal (oprnd2);
+       target = expand_widen_pattern_expr (exp, op0, op1, op2,
+                                           target, unsignedp);
+       return target;
+      }
+
+    case WIDEN_SUM_EXPR:
+      {
+        tree oprnd0 = TREE_OPERAND (exp, 0);
+        tree oprnd1 = TREE_OPERAND (exp, 1);
+
+        expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, 0);
+        target = expand_widen_pattern_expr (exp, op0, NULL_RTX, op1,
+                                            target, unsignedp);
+        return target;
+      }
+
+    case REDUC_MAX_EXPR:
+    case REDUC_MIN_EXPR:
+    case REDUC_PLUS_EXPR:
+      {
+        op0 = expand_normal (TREE_OPERAND (exp, 0));
+        this_optab = optab_for_tree_code (code, type, optab_default);
+        temp = expand_unop (mode, this_optab, op0, target, unsignedp);
+        gcc_assert (temp);
         return temp;
       }
 
+    case VEC_EXTRACT_EVEN_EXPR:
+    case VEC_EXTRACT_ODD_EXPR:
+      {
+        expand_operands (TREE_OPERAND (exp, 0),  TREE_OPERAND (exp, 1),
+                         NULL_RTX, &op0, &op1, 0);
+        this_optab = optab_for_tree_code (code, type, optab_default);
+        temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
+                             OPTAB_WIDEN);
+        gcc_assert (temp);
+        return temp;
+      }
+
+    case VEC_INTERLEAVE_HIGH_EXPR:
+    case VEC_INTERLEAVE_LOW_EXPR:
+      {
+        expand_operands (TREE_OPERAND (exp, 0),  TREE_OPERAND (exp, 1),
+                         NULL_RTX, &op0, &op1, 0);
+        this_optab = optab_for_tree_code (code, type, optab_default);
+        temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
+                             OPTAB_WIDEN);
+        gcc_assert (temp);
+        return temp;
+      }
+
+    case VEC_LSHIFT_EXPR:
+    case VEC_RSHIFT_EXPR:
+      {
+       target = expand_vec_shift_expr (exp, target);
+       return target;
+      }
+
+    case VEC_UNPACK_HI_EXPR:
+    case VEC_UNPACK_LO_EXPR:
+      {
+       op0 = expand_normal (TREE_OPERAND (exp, 0));
+       this_optab = optab_for_tree_code (code, type, optab_default);
+       temp = expand_widen_pattern_expr (exp, op0, NULL_RTX, NULL_RTX,
+                                         target, unsignedp);
+       gcc_assert (temp);
+       return temp;
+      }
+
+    case VEC_UNPACK_FLOAT_HI_EXPR:
+    case VEC_UNPACK_FLOAT_LO_EXPR:
+      {
+       op0 = expand_normal (TREE_OPERAND (exp, 0));
+       /* The signedness is determined from input operand.  */
+       this_optab = optab_for_tree_code (code,
+                                         TREE_TYPE (TREE_OPERAND (exp, 0)),
+                                         optab_default);
+       temp = expand_widen_pattern_expr
+         (exp, op0, NULL_RTX, NULL_RTX,
+          target, TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
+
+       gcc_assert (temp);
+       return temp;
+      }
+
+    case VEC_WIDEN_MULT_HI_EXPR:
+    case VEC_WIDEN_MULT_LO_EXPR:
+      {
+       tree oprnd0 = TREE_OPERAND (exp, 0);
+       tree oprnd1 = TREE_OPERAND (exp, 1);
+
+       expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, 0);
+       target = expand_widen_pattern_expr (exp, op0, op1, NULL_RTX,
+                                           target, unsignedp);
+       gcc_assert (target);
+       return target;
+      }
+
+    case VEC_PACK_TRUNC_EXPR:
+    case VEC_PACK_SAT_EXPR:
+    case VEC_PACK_FIX_TRUNC_EXPR:
+      {
+       mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
+       goto binop;
+      }
+
+    case OMP_ATOMIC_LOAD:
+    case OMP_ATOMIC_STORE:
+      /* OMP expansion is not run when there were errors, so these codes
+                 can get here.  */
+      gcc_assert (errorcount != 0);
+      return NULL_RTX;
 
     default:
       return lang_hooks.expand_expr (exp, original_target, tmode,
@@ -8136,7 +9381,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
   expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
                   subtarget, &op0, &op1, 0);
  binop2:
-  this_optab = optab_for_tree_code (code, type);
+  this_optab = optab_for_tree_code (code, type, optab_default);
  binop3:
   if (modifier == EXPAND_STACK_PARM)
     target = 0;
@@ -8155,7 +9400,14 @@ reduce_to_bit_field_precision (rtx exp, rtx target, tree type)
   HOST_WIDE_INT prec = TYPE_PRECISION (type);
   if (target && GET_MODE (target) != GET_MODE (exp))
     target = 0;
-  if (TYPE_UNSIGNED (type))
+  /* For constant values, reduce using build_int_cst_type. */
+  if (GET_CODE (exp) == CONST_INT)
+    {
+      HOST_WIDE_INT value = INTVAL (exp);
+      tree t = build_int_cst_type (type, value);
+      return expand_expr (t, target, VOIDmode, EXPAND_NORMAL);
+    }
+  else if (TYPE_UNSIGNED (type))
     {
       rtx mask;
       if (prec < HOST_BITS_PER_WIDE_INT)
@@ -8182,12 +9434,10 @@ reduce_to_bit_field_precision (rtx exp, rtx target, tree type)
    aligned more than BIGGEST_ALIGNMENT.  */
 
 static int
-is_aligning_offset (tree offset, tree exp)
+is_aligning_offset (const_tree offset, const_tree exp)
 {
   /* Strip off any conversions.  */
-  while (TREE_CODE (offset) == NON_LVALUE_EXPR
-        || TREE_CODE (offset) == NOP_EXPR
-        || TREE_CODE (offset) == CONVERT_EXPR)
+  while (CONVERT_EXPR_P (offset))
     offset = TREE_OPERAND (offset, 0);
 
   /* We must now have a BIT_AND_EXPR with a constant that is one less than
@@ -8202,18 +9452,14 @@ is_aligning_offset (tree offset, tree exp)
   /* Look at the first operand of BIT_AND_EXPR and strip any conversion.
      It must be NEGATE_EXPR.  Then strip any more conversions.  */
   offset = TREE_OPERAND (offset, 0);
-  while (TREE_CODE (offset) == NON_LVALUE_EXPR
-        || TREE_CODE (offset) == NOP_EXPR
-        || TREE_CODE (offset) == CONVERT_EXPR)
+  while (CONVERT_EXPR_P (offset))
     offset = TREE_OPERAND (offset, 0);
 
   if (TREE_CODE (offset) != NEGATE_EXPR)
     return 0;
 
   offset = TREE_OPERAND (offset, 0);
-  while (TREE_CODE (offset) == NON_LVALUE_EXPR
-        || TREE_CODE (offset) == NOP_EXPR
-        || TREE_CODE (offset) == CONVERT_EXPR)
+  while (CONVERT_EXPR_P (offset))
     offset = TREE_OPERAND (offset, 0);
 
   /* This must now be the address of EXP.  */
@@ -8228,7 +9474,7 @@ is_aligning_offset (tree offset, tree exp)
 tree
 string_constant (tree arg, tree *ptr_offset)
 {
-  tree array, offset;
+  tree array, offset, lower_bound;
   STRIP_NOPS (arg);
 
   if (TREE_CODE (arg) == ADDR_EXPR)
@@ -8250,11 +9496,25 @@ string_constant (tree arg, tree *ptr_offset)
          if (TREE_CODE (array) != STRING_CST
              && TREE_CODE (array) != VAR_DECL)
            return 0;
+
+         /* Check if the array has a nonzero lower bound.  */
+         lower_bound = array_ref_low_bound (TREE_OPERAND (arg, 0));
+         if (!integer_zerop (lower_bound))
+           {
+             /* If the offset and base aren't both constants, return 0.  */
+             if (TREE_CODE (lower_bound) != INTEGER_CST)
+               return 0;
+             if (TREE_CODE (offset) != INTEGER_CST)
+               return 0;
+             /* Adjust offset by the lower bound.  */
+             offset = size_diffop (fold_convert (sizetype, offset),
+                                   fold_convert (sizetype, lower_bound));
+           }
        }
       else
        return 0;
     }
-  else if (TREE_CODE (arg) == PLUS_EXPR)
+  else if (TREE_CODE (arg) == PLUS_EXPR || TREE_CODE (arg) == POINTER_PLUS_EXPR)
     {
       tree arg0 = TREE_OPERAND (arg, 0);
       tree arg1 = TREE_OPERAND (arg, 1);
@@ -8284,7 +9544,7 @@ string_constant (tree arg, tree *ptr_offset)
 
   if (TREE_CODE (array) == STRING_CST)
     {
-      *ptr_offset = convert (sizetype, offset);
+      *ptr_offset = fold_convert (sizetype, offset);
       return array;
     }
   else if (TREE_CODE (array) == VAR_DECL)
@@ -8311,7 +9571,7 @@ string_constant (tree arg, tree *ptr_offset)
 
       /* If variable is bigger than the string literal, OFFSET must be constant
         and inside of the bounds of the string literal.  */
-      offset = convert (sizetype, offset);
+      offset = fold_convert (sizetype, offset);
       if (compare_tree_int (DECL_SIZE_UNIT (array), length) > 0
          && (! host_integerp (offset, 1)
              || compare_tree_int (offset, length) >= 0))
@@ -8468,7 +9728,8 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
     }
 
   /* Put a constant second.  */
-  if (TREE_CODE (arg0) == REAL_CST || TREE_CODE (arg0) == INTEGER_CST)
+  if (TREE_CODE (arg0) == REAL_CST || TREE_CODE (arg0) == INTEGER_CST
+      || TREE_CODE (arg0) == FIXED_CST)
     {
       tem = arg0; arg0 = arg1; arg1 = tem;
       code = swap_condition (code);
@@ -8498,6 +9759,17 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
     return 0;
 
   icode = setcc_gen_code[(int) code];
+
+  if (icode == CODE_FOR_nothing)
+    {
+      enum machine_mode wmode;
+
+      for (wmode = operand_mode;
+          icode == CODE_FOR_nothing && wmode != VOIDmode;
+          wmode = GET_MODE_WIDER_MODE (wmode))
+       icode = optab_handler (cstore_optab, wmode)->insn_code;
+    }
+
   if (icode == CODE_FOR_nothing
       || (only_cheap && insn_data[(int) icode].operand[0].mode != mode))
     {
@@ -8506,12 +9778,11 @@ 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
+              && ((optab_handler (abs_optab, operand_mode)->insn_code
                    != CODE_FOR_nothing)
-                  || (ffs_optab->handlers[(int) operand_mode].insn_code
+                  || (optab_handler (ffs_optab, operand_mode)->insn_code
                       != CODE_FOR_nothing)))
        ;
       else
@@ -8544,25 +9815,10 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
     target = gen_reg_rtx (GET_MODE (target));
 
   emit_move_insn (target, invert ? const0_rtx : const1_rtx);
-  result = compare_from_rtx (op0, op1, code, unsignedp,
-                            operand_mode, NULL_RTX);
-  if (GET_CODE (result) == CONST_INT)
-    return (((result == const0_rtx && ! invert)
-            || (result != const0_rtx && invert))
-           ? const0_rtx : const1_rtx);
-
-  /* The code of RESULT may not match CODE if compare_from_rtx
-     decided to swap its operands and reverse the original code.
-
-     We know that compare_from_rtx returns either a CONST_INT or
-     a new comparison code, so it is safe to just extract the
-     code from RESULT.  */
-  code = GET_CODE (result);
-
   label = gen_label_rtx ();
-  gcc_assert (bcc_gen_fctn[(int) code]);
+  do_compare_rtx_and_jump (op0, op1, code, unsignedp, operand_mode, NULL_RTX,
+                          NULL_RTX, label);
 
-  emit_jump_insn ((*bcc_gen_fctn[(int) code]) (label));
   emit_move_insn (target, invert ? const1_rtx : const0_rtx);
   emit_label (label);
 
@@ -8594,7 +9850,8 @@ case_values_threshold (void)
    0 otherwise (i.e. if there is no casesi instruction).  */
 int
 try_casesi (tree index_type, tree index_expr, tree minval, tree range,
-           rtx table_label ATTRIBUTE_UNUSED, rtx default_label)
+           rtx table_label ATTRIBUTE_UNUSED, rtx default_label,
+           rtx fallback_label ATTRIBUTE_UNUSED)
 {
   enum machine_mode index_mode = SImode;
   int index_bits = GET_MODE_BITSIZE (index_mode);
@@ -8608,15 +9865,16 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range,
   if (GET_MODE_BITSIZE (TYPE_MODE (index_type)) > GET_MODE_BITSIZE (index_mode))
     {
       enum machine_mode omode = TYPE_MODE (index_type);
-      rtx rangertx = expand_expr (range, NULL_RTX, VOIDmode, 0);
+      rtx rangertx = expand_normal (range);
 
       /* We must handle the endpoints in the original mode.  */
       index_expr = build2 (MINUS_EXPR, index_type,
                           index_expr, minval);
       minval = integer_zero_node;
-      index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
-      emit_cmp_and_jump_insns (rangertx, index, LTU, NULL_RTX,
-                              omode, 1, default_label);
+      index = expand_normal (index_expr);
+      if (default_label)
+        emit_cmp_and_jump_insns (rangertx, index, LTU, NULL_RTX,
+                                omode, 1, default_label);
       /* Now we can safely truncate.  */
       index = convert_to_mode (index_mode, index, 0);
     }
@@ -8624,12 +9882,11 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range,
     {
       if (TYPE_MODE (index_type) != index_mode)
        {
-         index_expr = convert (lang_hooks.types.type_for_size
-                               (index_bits, 0), index_expr);
-         index_type = TREE_TYPE (index_expr);
+         index_type = lang_hooks.types.type_for_size (index_bits, 0);
+         index_expr = fold_convert (index_type, index_expr);
        }
 
-      index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
+      index = expand_normal (index_expr);
     }
 
   do_pending_stack_adjust ();
@@ -8639,7 +9896,7 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range,
       (index, op_mode))
     index = copy_to_mode_reg (op_mode, index);
 
-  op1 = expand_expr (minval, NULL_RTX, VOIDmode, 0);
+  op1 = expand_normal (minval);
 
   op_mode = insn_data[(int) CODE_FOR_casesi].operand[1].mode;
   op1 = convert_modes (op_mode, TYPE_MODE (TREE_TYPE (minval)),
@@ -8648,7 +9905,7 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range,
       (op1, op_mode))
     op1 = copy_to_mode_reg (op_mode, op1);
 
-  op2 = expand_expr (range, NULL_RTX, VOIDmode, 0);
+  op2 = expand_normal (range);
 
   op_mode = insn_data[(int) CODE_FOR_casesi].operand[2].mode;
   op2 = convert_modes (op_mode, TYPE_MODE (TREE_TYPE (range)),
@@ -8658,7 +9915,8 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range,
     op2 = copy_to_mode_reg (op_mode, op2);
 
   emit_jump_insn (gen_casesi (index, op1, op2,
-                             table_label, default_label));
+                             table_label, !default_label
+                                          ? fallback_label : default_label));
   return 1;
 }
 
@@ -8685,8 +9943,8 @@ do_tablejump (rtx index, enum machine_mode mode, rtx range, rtx table_label,
 {
   rtx temp, vector;
 
-  if (INTVAL (range) > cfun->max_jumptable_ents)
-    cfun->max_jumptable_ents = INTVAL (range);
+  if (INTVAL (range) > cfun->cfg->max_jumptable_ents)
+    cfun->cfg->max_jumptable_ents = INTVAL (range);
 
   /* Do an unsigned comparison (in the proper mode) between the index
      expression and the value which represents the length of the range.
@@ -8696,8 +9954,9 @@ do_tablejump (rtx index, enum machine_mode mode, rtx range, rtx table_label,
      or equal to the minimum value of the range and less than or equal to
      the maximum value of the range.  */
 
-  emit_cmp_and_jump_insns (index, range, GTU, NULL_RTX, mode, 1,
-                          default_label);
+  if (default_label)
+    emit_cmp_and_jump_insns (index, range, GTU, NULL_RTX, mode, 1,
+                            default_label);
 
   /* If index is in range, it must fit in Pmode.
      Convert to Pmode so we can index with it.  */
@@ -8712,10 +9971,6 @@ do_tablejump (rtx index, enum machine_mode mode, rtx range, rtx table_label,
     index = copy_to_mode_reg (Pmode, index);
 #endif
 
-  /* If flag_force_addr were to affect this address
-     it could interfere with the tricky assumptions made
-     about addresses that contain label-refs,
-     which may be valid only very near the tablejump itself.  */
   /* ??? The only correct use of CASE_VECTOR_MODE is the one inside the
      GET_MODE_SIZE, because this indicates how large insns are.  The other
      uses should all be Pmode, because they are addresses.  This code
@@ -8729,7 +9984,7 @@ do_tablejump (rtx index, enum machine_mode mode, rtx range, rtx table_label,
     index = PIC_CASE_VECTOR_ADDRESS (index);
   else
 #endif
-    index = memory_address_noforce (CASE_VECTOR_MODE, index);
+    index = memory_address (CASE_VECTOR_MODE, index);
   temp = gen_reg_rtx (CASE_VECTOR_MODE);
   vector = gen_const_mem (CASE_VECTOR_MODE, index);
   convert_move (temp, vector, 0);
@@ -8751,17 +10006,16 @@ 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 = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
+  index_expr = fold_build2 (MINUS_EXPR, index_type,
+                           fold_convert (index_type, index_expr),
+                           fold_convert (index_type, minval));
+  index = expand_normal (index_expr);
   do_pending_stack_adjust ();
 
   do_tablejump (index, TYPE_MODE (index_type),
                convert_modes (TYPE_MODE (index_type),
                               TYPE_MODE (TREE_TYPE (range)),
-                              expand_expr (range, NULL_RTX,
-                                           VOIDmode, 0),
+                              expand_normal (range),
                               TYPE_UNSIGNED (TREE_TYPE (range))),
                table_label, default_label);
   return 1;
@@ -8779,7 +10033,11 @@ vector_mode_valid_p (enum machine_mode mode)
 
   /* Doh!  What's going on?  */
   if (class != MODE_VECTOR_INT
-      && class != MODE_VECTOR_FLOAT)
+      && class != MODE_VECTOR_FLOAT
+      && class != MODE_VECTOR_FRACT
+      && class != MODE_VECTOR_UFRACT
+      && class != MODE_VECTOR_ACCUM
+      && class != MODE_VECTOR_UACCUM)
     return 0;
 
   /* Hardware support.  Woo hoo!  */
@@ -8823,6 +10081,9 @@ const_vector_from_tree (tree exp)
       if (TREE_CODE (elt) == REAL_CST)
        RTVEC_ELT (v, i) = CONST_DOUBLE_FROM_REAL_VALUE (TREE_REAL_CST (elt),
                                                         inner);
+      else if (TREE_CODE (elt) == FIXED_CST)
+       RTVEC_ELT (v, i) = CONST_FIXED_FROM_FIXED_VALUE (TREE_FIXED_CST (elt),
+                                                        inner);
       else
        RTVEC_ELT (v, i) = immed_double_const (TREE_INT_CST_LOW (elt),
                                               TREE_INT_CST_HIGH (elt),