OSDN Git Service

PR c++/47132
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index 08c747e..971432c 100644 (file)
@@ -1,6 +1,6 @@
 /* Convert tree expression to rtl instructions, for GNU compiler.
    Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -24,7 +24,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "machmode.h"
-#include "real.h"
 #include "rtl.h"
 #include "tree.h"
 #include "flags.h"
@@ -43,7 +42,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "output.h"
 #include "typeclass.h"
 #include "toplev.h"
-#include "ggc.h"
 #include "langhooks.h"
 #include "intl.h"
 #include "tm_p.h"
@@ -55,6 +53,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "df.h"
 #include "diagnostic.h"
 #include "ssaexpand.h"
+#include "target-globals.h"
 
 /* Decide whether a function's arguments should be processed
    from first to last or from last to first.
@@ -152,7 +151,7 @@ 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);
-static rtx do_store_flag (tree, rtx, enum machine_mode);
+static rtx do_store_flag (sepops, rtx, enum machine_mode);
 #ifdef PUSH_ROUNDING
 static void emit_single_push_insn (enum machine_mode, rtx, tree);
 #endif
@@ -160,17 +159,6 @@ 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
-   to use that mode directly when accessing a field of that mode.  */
-
-static char direct_load[NUM_MACHINE_MODES];
-static char direct_store[NUM_MACHINE_MODES];
-
-/* Record for each mode whether we can float-extend from memory.  */
-
-static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
-
 /* This macro is used to determine whether move_by_pieces should be called
    to perform a structure copy.  */
 #ifndef MOVE_BY_PIECES_P
@@ -203,41 +191,6 @@ static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
    < (unsigned int) MOVE_RATIO (optimize_insn_for_speed_p ()))
 #endif
 
-/* 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 sets.  */
-enum insn_code setmem_optab[NUM_MACHINE_MODES];
-
-/* 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_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
@@ -333,7 +286,7 @@ init_expr_target (void)
 
          PUT_MODE (mem, srcmode);
 
-         if ((*insn_data[ic].operand[1].predicate) (mem, srcmode))
+         if (insn_operand_matches (ic, 1, mem))
            float_extend_from_mem[mode][srcmode] = true;
        }
     }
@@ -436,7 +389,7 @@ convert_move (rtx to, rtx from, int unsignedp)
 
       /* Try converting directly if the insn is supported.  */
 
-      code = convert_optab_handler (tab, to_mode, from_mode)->insn_code;
+      code = convert_optab_handler (tab, to_mode, from_mode);
       if (code != CODE_FOR_nothing)
        {
          emit_unop_insn (code, to, from,
@@ -470,12 +423,12 @@ 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 (convert_optab_handler (trunc_optab, to_mode, full_mode)->insn_code
+      gcc_assert (convert_optab_handler (trunc_optab, to_mode, full_mode)
                  != CODE_FOR_nothing);
 
       if (full_mode != from_mode)
        from = convert_to_mode (full_mode, from, unsignedp);
-      emit_unop_insn (convert_optab_handler (trunc_optab, to_mode, full_mode)->insn_code,
+      emit_unop_insn (convert_optab_handler (trunc_optab, to_mode, full_mode),
                      to, from, UNKNOWN);
       return;
     }
@@ -485,18 +438,19 @@ convert_move (rtx to, rtx from, int unsignedp)
       enum machine_mode full_mode
        = smallest_mode_for_size (GET_MODE_BITSIZE (from_mode), MODE_INT);
 
-      gcc_assert (convert_optab_handler (sext_optab, full_mode, from_mode)->insn_code
+      gcc_assert (convert_optab_handler (sext_optab, full_mode, from_mode)
                  != CODE_FOR_nothing);
 
       if (to_mode == full_mode)
        {
-         emit_unop_insn (convert_optab_handler (sext_optab, full_mode, from_mode)->insn_code,
+         emit_unop_insn (convert_optab_handler (sext_optab, full_mode,
+                                                from_mode),
                          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,
+      emit_unop_insn (convert_optab_handler (sext_optab, full_mode, from_mode),
                      new_from, from, UNKNOWN);
 
       /* else proceed to integer conversions below.  */
@@ -662,7 +616,7 @@ convert_move (rtx to, rtx from, int unsignedp)
        {
          enum machine_mode intermediate;
          rtx tmp;
-         tree shift_amount;
+         int shift_amount;
 
          /* Search for a mode to convert via.  */
          for (intermediate = from_mode; intermediate != VOIDmode;
@@ -682,9 +636,8 @@ convert_move (rtx to, rtx from, int unsignedp)
 
          /* No suitable intermediate mode.
             Generate what we need with shifts.  */
-         shift_amount = build_int_cst (NULL_TREE,
-                                       GET_MODE_BITSIZE (to_mode)
-                                       - GET_MODE_BITSIZE (from_mode));
+         shift_amount = (GET_MODE_BITSIZE (to_mode)
+                         - GET_MODE_BITSIZE (from_mode));
          from = gen_lowpart (to_mode, force_reg (from_mode, from));
          tmp = expand_shift (LSHIFT_EXPR, to_mode, from, shift_amount,
                              to, unsignedp);
@@ -697,9 +650,10 @@ convert_move (rtx to, rtx from, int unsignedp)
     }
 
   /* Support special truncate insns for certain modes.  */
-  if (convert_optab_handler (trunc_optab, to_mode, from_mode)->insn_code != CODE_FOR_nothing)
+  if (convert_optab_handler (trunc_optab, to_mode,
+                            from_mode) != CODE_FOR_nothing)
     {
-      emit_unop_insn (convert_optab_handler (trunc_optab, to_mode, from_mode)->insn_code,
+      emit_unop_insn (convert_optab_handler (trunc_optab, to_mode, from_mode),
                      to, from, UNKNOWN);
       return;
     }
@@ -774,18 +728,13 @@ convert_modes (enum machine_mode mode, enum machine_mode oldmode, rtx x, int uns
       && GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT
       && CONST_INT_P (x) && INTVAL (x) < 0)
     {
-      HOST_WIDE_INT val = INTVAL (x);
-
-      if (oldmode != VOIDmode
-         && HOST_BITS_PER_WIDE_INT > GET_MODE_BITSIZE (oldmode))
-       {
-         int width = GET_MODE_BITSIZE (oldmode);
+      double_int val = uhwi_to_double_int (INTVAL (x));
 
-         /* We need to zero extend VAL.  */
-         val &= ((HOST_WIDE_INT) 1 << width) - 1;
-       }
+      /* We need to zero extend VAL.  */
+      if (oldmode != VOIDmode)
+       val = double_int_zext (val, GET_MODE_BITSIZE (oldmode));
 
-      return immed_double_const (val, (HOST_WIDE_INT) 0, mode);
+      return immed_double_int_const (val, mode);
     }
 
   /* We can do this with a gen_lowpart if both desired and current modes
@@ -842,6 +791,50 @@ convert_modes (enum machine_mode mode, enum machine_mode oldmode, rtx x, int uns
   return temp;
 }
 \f
+/* Return the largest alignment we can use for doing a move (or store)
+   of MAX_PIECES.  ALIGN is the largest alignment we could use.  */
+
+static unsigned int
+alignment_for_piecewise_move (unsigned int max_pieces, unsigned int align)
+{
+  enum machine_mode tmode;
+
+  tmode = mode_for_size (max_pieces * BITS_PER_UNIT, MODE_INT, 1);
+  if (align >= GET_MODE_ALIGNMENT (tmode))
+    align = GET_MODE_ALIGNMENT (tmode);
+  else
+    {
+      enum machine_mode tmode, xmode;
+
+      for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT), xmode = tmode;
+          tmode != VOIDmode;
+          xmode = tmode, tmode = GET_MODE_WIDER_MODE (tmode))
+       if (GET_MODE_SIZE (tmode) > max_pieces
+           || SLOW_UNALIGNED_ACCESS (tmode, align))
+         break;
+
+      align = MAX (align, GET_MODE_ALIGNMENT (xmode));
+    }
+
+  return align;
+}
+
+/* Return the widest integer mode no wider than SIZE.  If no such mode
+   can be found, return VOIDmode.  */
+
+static enum machine_mode
+widest_int_mode_for_size (unsigned int size)
+{
+  enum machine_mode tmode, mode = VOIDmode;
+
+  for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+       tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode))
+    if (GET_MODE_SIZE (tmode) < size)
+      mode = tmode;
+
+  return mode;
+}
+
 /* STORE_MAX_PIECES is the number of bytes at a time that we can
    store efficiently.  Due to internal GCC limitations, this is
    MOVE_MAX_PIECES limited by the number of bytes GCC can represent
@@ -877,9 +870,10 @@ move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len,
                unsigned int align, int endp)
 {
   struct move_by_pieces_d data;
+  enum machine_mode to_addr_mode, from_addr_mode
+    = targetm.addr_space.address_mode (MEM_ADDR_SPACE (from));
   rtx to_addr, from_addr = XEXP (from, 0);
   unsigned int max_size = MOVE_MAX_PIECES + 1;
-  enum machine_mode mode = VOIDmode, tmode;
   enum insn_code icode;
 
   align = MIN (to ? MEM_ALIGN (to) : align, MEM_ALIGN (from));
@@ -888,6 +882,7 @@ move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len,
   data.from_addr = from_addr;
   if (to)
     {
+      to_addr_mode = targetm.addr_space.address_mode (MEM_ADDR_SPACE (to));
       to_addr = XEXP (to, 0);
       data.to = to;
       data.autinc_to
@@ -898,6 +893,7 @@ move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len,
     }
   else
     {
+      to_addr_mode = VOIDmode;
       to_addr = NULL_RTX;
       data.to = NULL_RTX;
       data.autinc_to = 1;
@@ -925,73 +921,57 @@ move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len,
   if (!(data.autinc_from && data.autinc_to)
       && move_by_pieces_ninsns (len, align, max_size) > 2)
     {
-      /* Find the mode of the largest move...  */
-      for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
-          tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode))
-       if (GET_MODE_SIZE (tmode) < max_size)
-         mode = tmode;
+      /* Find the mode of the largest move...
+        MODE might not be used depending on the definitions of the
+        USE_* macros below.  */
+      enum machine_mode mode ATTRIBUTE_UNUSED
+       = widest_int_mode_for_size (max_size);
 
       if (USE_LOAD_PRE_DECREMENT (mode) && data.reverse && ! data.autinc_from)
        {
-         data.from_addr = copy_addr_to_reg (plus_constant (from_addr, len));
+         data.from_addr = copy_to_mode_reg (from_addr_mode,
+                                            plus_constant (from_addr, len));
          data.autinc_from = 1;
          data.explicit_inc_from = -1;
        }
       if (USE_LOAD_POST_INCREMENT (mode) && ! data.autinc_from)
        {
-         data.from_addr = copy_addr_to_reg (from_addr);
+         data.from_addr = copy_to_mode_reg (from_addr_mode, from_addr);
          data.autinc_from = 1;
          data.explicit_inc_from = 1;
        }
       if (!data.autinc_from && CONSTANT_P (from_addr))
-       data.from_addr = copy_addr_to_reg (from_addr);
+       data.from_addr = copy_to_mode_reg (from_addr_mode, from_addr);
       if (USE_STORE_PRE_DECREMENT (mode) && data.reverse && ! data.autinc_to)
        {
-         data.to_addr = copy_addr_to_reg (plus_constant (to_addr, len));
+         data.to_addr = copy_to_mode_reg (to_addr_mode,
+                                          plus_constant (to_addr, len));
          data.autinc_to = 1;
          data.explicit_inc_to = -1;
        }
       if (USE_STORE_POST_INCREMENT (mode) && ! data.reverse && ! data.autinc_to)
        {
-         data.to_addr = copy_addr_to_reg (to_addr);
+         data.to_addr = copy_to_mode_reg (to_addr_mode, to_addr);
          data.autinc_to = 1;
          data.explicit_inc_to = 1;
        }
       if (!data.autinc_to && CONSTANT_P (to_addr))
-       data.to_addr = copy_addr_to_reg (to_addr);
+       data.to_addr = copy_to_mode_reg (to_addr_mode, to_addr);
     }
 
-  tmode = mode_for_size (MOVE_MAX_PIECES * BITS_PER_UNIT, MODE_INT, 1);
-  if (align >= GET_MODE_ALIGNMENT (tmode))
-    align = GET_MODE_ALIGNMENT (tmode);
-  else
-    {
-      enum machine_mode xmode;
-
-      for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT), xmode = tmode;
-          tmode != VOIDmode;
-          xmode = tmode, tmode = GET_MODE_WIDER_MODE (tmode))
-       if (GET_MODE_SIZE (tmode) > MOVE_MAX_PIECES
-           || SLOW_UNALIGNED_ACCESS (tmode, align))
-         break;
-
-      align = MAX (align, GET_MODE_ALIGNMENT (xmode));
-    }
+  align = alignment_for_piecewise_move (MOVE_MAX_PIECES, align);
 
   /* First move what we can in the largest integer mode, then go to
      successively smaller modes.  */
 
   while (max_size > 1)
     {
-      for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
-          tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode))
-       if (GET_MODE_SIZE (tmode) < max_size)
-         mode = tmode;
+      enum machine_mode mode = widest_int_mode_for_size (max_size);
 
       if (mode == VOIDmode)
        break;
 
-      icode = optab_handler (mov_optab, mode)->insn_code;
+      icode = optab_handler (mov_optab, mode);
       if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode))
        move_by_pieces_1 (GEN_FCN (icode), mode, &data);
 
@@ -1013,7 +993,8 @@ move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len,
              if (HAVE_POST_INCREMENT && data.explicit_inc_to > 0)
                emit_insn (gen_add2_insn (data.to_addr, constm1_rtx));
              else
-               data.to_addr = copy_addr_to_reg (plus_constant (data.to_addr,
+               data.to_addr = copy_to_mode_reg (to_addr_mode,
+                                                plus_constant (data.to_addr,
                                                                -1));
            }
          to1 = adjust_automodify_address (data.to, QImode, data.to_addr,
@@ -1039,39 +1020,20 @@ move_by_pieces_ninsns (unsigned HOST_WIDE_INT l, unsigned int align,
                       unsigned int max_size)
 {
   unsigned HOST_WIDE_INT n_insns = 0;
-  enum machine_mode tmode;
-
-  tmode = mode_for_size (MOVE_MAX_PIECES * BITS_PER_UNIT, MODE_INT, 1);
-  if (align >= GET_MODE_ALIGNMENT (tmode))
-    align = GET_MODE_ALIGNMENT (tmode);
-  else
-    {
-      enum machine_mode tmode, xmode;
-
-      for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT), xmode = tmode;
-          tmode != VOIDmode;
-          xmode = tmode, tmode = GET_MODE_WIDER_MODE (tmode))
-       if (GET_MODE_SIZE (tmode) > MOVE_MAX_PIECES
-           || SLOW_UNALIGNED_ACCESS (tmode, align))
-         break;
 
-      align = MAX (align, GET_MODE_ALIGNMENT (xmode));
-    }
+  align = alignment_for_piecewise_move (MOVE_MAX_PIECES, align);
 
   while (max_size > 1)
     {
-      enum machine_mode mode = VOIDmode;
+      enum machine_mode mode;
       enum insn_code icode;
 
-      for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
-          tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode))
-       if (GET_MODE_SIZE (tmode) < max_size)
-         mode = tmode;
+      mode = widest_int_mode_for_size (max_size);
 
       if (mode == VOIDmode)
        break;
 
-      icode = optab_handler (mov_optab, mode)->insn_code;
+      icode = optab_handler (mov_optab, mode);
       if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode))
        n_insns += l / GET_MODE_SIZE (mode), l %= GET_MODE_SIZE (mode);
 
@@ -1163,6 +1125,11 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method,
   rtx retval = 0;
   unsigned int align;
 
+  gcc_assert (size);
+  if (CONST_INT_P (size)
+      && INTVAL (size) == 0)
+    return 0;
+
   switch (method)
     {
     case BLOCK_OP_NORMAL:
@@ -1186,11 +1153,9 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method,
       gcc_unreachable ();
     }
 
+  gcc_assert (MEM_P (x) && MEM_P (y));
   align = MIN (MEM_ALIGN (x), MEM_ALIGN (y));
-
-  gcc_assert (MEM_P (x));
-  gcc_assert (MEM_P (y));
-  gcc_assert (size);
+  gcc_assert (align >= BITS_PER_UNIT);
 
   /* Make sure we've got BLKmode addresses; store_one_arg can decide that
      block copy is more efficient for other large modes, e.g. DCmode.  */
@@ -1201,9 +1166,6 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method,
      can be incorrect is coming from __builtin_memcpy.  */
   if (CONST_INT_P (size))
     {
-      if (INTVAL (size) == 0)
-       return 0;
-
       x = shallow_copy_rtx (x);
       y = shallow_copy_rtx (y);
       set_mem_size (x, size);
@@ -1215,7 +1177,9 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method,
   else if (emit_block_move_via_movmem (x, y, size, align,
                                       expected_align, expected_size))
     ;
-  else if (may_use_call)
+  else if (may_use_call
+          && ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (x))
+          && ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (y)))
     retval = emit_block_move_via_libcall (x, y, size,
                                          method == BLOCK_OP_TAILCALL);
   else
@@ -1252,6 +1216,9 @@ block_move_libcall_safe_for_call_parm (void)
      an outgoing argument.  */
 #if defined (REG_PARM_STACK_SPACE)
   fn = emit_block_move_libcall_fn (false);
+  /* Avoid set but not used warning if *REG_PARM_STACK_SPACE doesn't
+     depend on its argument.  */
+  (void) fn;
   if (OUTGOING_REG_PARM_STACK_SPACE ((!fn ? NULL_TREE : TREE_TYPE (fn)))
       && REG_PARM_STACK_SPACE (fn) != 0)
     return false;
@@ -1270,12 +1237,14 @@ block_move_libcall_safe_for_call_parm (void)
     for ( ; arg != void_list_node ; arg = TREE_CHAIN (arg))
       {
        enum machine_mode mode = TYPE_MODE (TREE_VALUE (arg));
-       rtx tmp = FUNCTION_ARG (args_so_far, mode, NULL_TREE, 1);
+       rtx tmp = targetm.calls.function_arg (&args_so_far, mode,
+                                             NULL_TREE, true);
        if (!tmp || !REG_P (tmp))
          return false;
        if (targetm.calls.arg_partial_bytes (&args_so_far, mode, NULL, 1))
          return false;
-       FUNCTION_ARG_ADVANCE (args_so_far, mode, NULL_TREE, 1);
+       targetm.calls.function_arg_advance (&args_so_far, mode,
+                                           NULL_TREE, true);
       }
   }
   return true;
@@ -1288,7 +1257,6 @@ static bool
 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;
 
@@ -1305,8 +1273,7 @@ emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align,
   for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
        mode = GET_MODE_WIDER_MODE (mode))
     {
-      enum insn_code code = movmem_optab[(int) mode];
-      insn_operand_predicate_fn pred;
+      enum insn_code code = direct_optab_handler (movmem_optab, mode);
 
       if (code != CODE_FOR_nothing
          /* We don't need MODE to be narrower than BITS_PER_HOST_WIDE_INT
@@ -1316,43 +1283,33 @@ emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align,
          && ((CONST_INT_P (size)
               && ((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) (x, BLKmode))
-         && ((pred = insn_data[(int) code].operand[1].predicate) == 0
-             || (*pred) (y, BLKmode))
-         && ((pred = insn_data[(int) code].operand[3].predicate) == 0
-             || (*pred) (opalign, VOIDmode)))
+             || GET_MODE_BITSIZE (mode) >= BITS_PER_WORD))
        {
-         rtx op2;
-         rtx last = get_last_insn ();
-         rtx pat;
-
-         op2 = convert_to_mode (mode, size, 1);
-         pred = insn_data[(int) code].operand[2].predicate;
-         if (pred != 0 && ! (*pred) (op2, mode))
-           op2 = copy_to_mode_reg (mode, op2);
+         struct expand_operand ops[6];
+         unsigned int nops;
 
          /* ??? When called via emit_block_move_for_call, it'd be
             nice if there were some way to inform the backend, so
             that it doesn't fail the expansion because it thinks
             emitting the libcall would be more efficient.  */
-
-         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
-                                                / BITS_PER_UNIT),
-                                       GEN_INT (expected_size));
-         if (pat)
+         nops = insn_data[(int) code].n_generator_args;
+         gcc_assert (nops == 4 || nops == 6);
+
+         create_fixed_operand (&ops[0], x);
+         create_fixed_operand (&ops[1], y);
+         /* The check above guarantees that this size conversion is valid.  */
+         create_convert_operand_to (&ops[2], size, mode, true);
+         create_integer_operand (&ops[3], align / BITS_PER_UNIT);
+         if (nops == 6)
+           {
+             create_integer_operand (&ops[4], expected_align / BITS_PER_UNIT);
+             create_integer_operand (&ops[5], expected_size);
+           }
+         if (maybe_expand_insn (code, nops, ops))
            {
-             emit_insn (pat);
              volatile_ok = save_volatile_ok;
              return true;
            }
-         else
-           delete_insns_since (last);
        }
     }
 
@@ -1466,6 +1423,10 @@ emit_block_move_via_loop (rtx x, rtx y, rtx size,
                          unsigned int align ATTRIBUTE_UNUSED)
 {
   rtx cmp_label, top_label, iter, x_addr, y_addr, tmp;
+  enum machine_mode x_addr_mode
+    = targetm.addr_space.address_mode (MEM_ADDR_SPACE (x));
+  enum machine_mode y_addr_mode
+    = targetm.addr_space.address_mode (MEM_ADDR_SPACE (y));
   enum machine_mode iter_mode;
 
   iter_mode = GET_MODE (size);
@@ -1485,9 +1446,13 @@ emit_block_move_via_loop (rtx x, rtx y, rtx size,
   emit_jump (cmp_label);
   emit_label (top_label);
 
-  tmp = convert_modes (Pmode, iter_mode, iter, true);
-  x_addr = gen_rtx_PLUS (Pmode, x_addr, tmp);
-  y_addr = gen_rtx_PLUS (Pmode, y_addr, tmp);
+  tmp = convert_modes (x_addr_mode, iter_mode, iter, true);
+  x_addr = gen_rtx_PLUS (x_addr_mode, x_addr, tmp);
+
+  if (x_addr_mode != y_addr_mode)
+    tmp = convert_modes (y_addr_mode, iter_mode, iter, true);
+  y_addr = gen_rtx_PLUS (y_addr_mode, y_addr, tmp);
+
   x = change_address (x, QImode, x_addr);
   y = change_address (y, QImode, y_addr);
 
@@ -1519,7 +1484,7 @@ move_block_to_reg (int regno, rtx x, int nregs, enum machine_mode mode)
   if (nregs == 0)
     return;
 
-  if (CONSTANT_P (x) && ! LEGITIMATE_CONSTANT_P (x))
+  if (CONSTANT_P (x) && !targetm.legitimate_constant_p (mode, x))
     x = validize_mem (force_const_mem (mode, x));
 
   /* See if the machine can do this with a load multiple insn.  */
@@ -1731,7 +1696,7 @@ emit_group_load_1 (rtx *tmps, rtx dst, rtx orig_src, tree type, int ssize)
                  && (!REG_P (tmps[i]) || GET_MODE (tmps[i]) != mode))
                tmps[i] = extract_bit_field (tmps[i], bytelen * BITS_PER_UNIT,
                                             (bytepos % slen0) * BITS_PER_UNIT,
-                                            1, NULL_RTX, mode, mode);
+                                            1, false, NULL_RTX, mode, mode);
            }
          else
            {
@@ -1741,7 +1706,7 @@ emit_group_load_1 (rtx *tmps, rtx dst, rtx orig_src, tree type, int ssize)
              mem = assign_stack_temp (GET_MODE (src), slen, 0);
              emit_move_insn (mem, src);
              tmps[i] = extract_bit_field (mem, bytelen * BITS_PER_UNIT,
-                                          0, 1, NULL_RTX, mode, mode);
+                                          0, 1, false, NULL_RTX, mode, mode);
            }
        }
       /* FIXME: A SIMD parallel will eventually lead to a subreg of a
@@ -1782,12 +1747,12 @@ emit_group_load_1 (rtx *tmps, rtx dst, rtx orig_src, tree type, int ssize)
        tmps[i] = src;
       else
        tmps[i] = extract_bit_field (src, bytelen * BITS_PER_UNIT,
-                                    bytepos * BITS_PER_UNIT, 1, NULL_RTX,
+                                    bytepos * BITS_PER_UNIT, 1, false, NULL_RTX,
                                     mode, mode);
 
       if (shift)
        tmps[i] = expand_shift (LSHIFT_EXPR, mode, tmps[i],
-                               build_int_cst (NULL_TREE, shift), tmps[i], 0);
+                               shift, tmps[i], 0);
     }
 }
 
@@ -2084,8 +2049,7 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
            {
              int shift = (bytelen - (ssize - bytepos)) * BITS_PER_UNIT;
              tmps[i] = expand_shift (RSHIFT_EXPR, mode, tmps[i],
-                                     build_int_cst (NULL_TREE, shift),
-                                     tmps[i], 0);
+                                     shift, tmps[i], 0);
            }
          bytelen = adj_bytelen;
        }
@@ -2195,7 +2159,7 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
         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,
+                                         xbitpos % BITS_PER_WORD, 1, false,
                                          NULL_RTX, copy_mode, copy_mode));
     }
 
@@ -2286,35 +2250,21 @@ can_store_by_pieces (unsigned HOST_WIDE_INT len,
   unsigned HOST_WIDE_INT l;
   unsigned int max_size;
   HOST_WIDE_INT offset = 0;
-  enum machine_mode mode, tmode;
+  enum machine_mode mode;
   enum insn_code icode;
   int reverse;
-  rtx cst;
+  /* cst is set but not used if LEGITIMATE_CONSTANT doesn't use it.  */
+  rtx cst ATTRIBUTE_UNUSED;
 
   if (len == 0)
     return 1;
 
-  if (! (memsetp 
+  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);
-  if (align >= GET_MODE_ALIGNMENT (tmode))
-    align = GET_MODE_ALIGNMENT (tmode);
-  else
-    {
-      enum machine_mode xmode;
-
-      for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT), xmode = tmode;
-          tmode != VOIDmode;
-          xmode = tmode, tmode = GET_MODE_WIDER_MODE (tmode))
-       if (GET_MODE_SIZE (tmode) > STORE_MAX_PIECES
-           || SLOW_UNALIGNED_ACCESS (tmode, align))
-         break;
-
-      align = MAX (align, GET_MODE_ALIGNMENT (xmode));
-    }
+  align = alignment_for_piecewise_move (STORE_MAX_PIECES, align);
 
   /* We would first store what we can in the largest integer mode, then go to
      successively smaller modes.  */
@@ -2324,19 +2274,15 @@ can_store_by_pieces (unsigned HOST_WIDE_INT len,
        reverse++)
     {
       l = len;
-      mode = VOIDmode;
       max_size = STORE_MAX_PIECES + 1;
       while (max_size > 1)
        {
-         for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
-              tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode))
-           if (GET_MODE_SIZE (tmode) < max_size)
-             mode = tmode;
+         mode = widest_int_mode_for_size (max_size);
 
          if (mode == VOIDmode)
            break;
 
-         icode = optab_handler (mov_optab, mode)->insn_code;
+         icode = optab_handler (mov_optab, mode);
          if (icode != CODE_FOR_nothing
              && align >= GET_MODE_ALIGNMENT (mode))
            {
@@ -2348,7 +2294,7 @@ can_store_by_pieces (unsigned HOST_WIDE_INT len,
                    offset -= size;
 
                  cst = (*constfun) (constfundata, offset, mode);
-                 if (!LEGITIMATE_CONSTANT_P (cst))
+                 if (!targetm.legitimate_constant_p (mode, cst))
                    return 0;
 
                  if (!reverse)
@@ -2382,6 +2328,8 @@ store_by_pieces (rtx to, unsigned HOST_WIDE_INT len,
                 rtx (*constfun) (void *, HOST_WIDE_INT, enum machine_mode),
                 void *constfundata, unsigned int align, bool memsetp, int endp)
 {
+  enum machine_mode to_addr_mode
+    = targetm.addr_space.address_mode (MEM_ADDR_SPACE (to));
   struct store_by_pieces_d data;
 
   if (len == 0)
@@ -2410,7 +2358,8 @@ store_by_pieces (rtx to, unsigned HOST_WIDE_INT len,
              if (HAVE_POST_INCREMENT && data.explicit_inc_to > 0)
                emit_insn (gen_add2_insn (data.to_addr, constm1_rtx));
              else
-               data.to_addr = copy_addr_to_reg (plus_constant (data.to_addr,
+               data.to_addr = copy_to_mode_reg (to_addr_mode,
+                                                plus_constant (data.to_addr,
                                                                -1));
            }
          to1 = adjust_automodify_address (data.to, QImode, data.to_addr,
@@ -2465,9 +2414,10 @@ static void
 store_by_pieces_1 (struct store_by_pieces_d *data ATTRIBUTE_UNUSED,
                   unsigned int align ATTRIBUTE_UNUSED)
 {
+  enum machine_mode to_addr_mode
+    = targetm.addr_space.address_mode (MEM_ADDR_SPACE (data->to));
   rtx to_addr = XEXP (data->to, 0);
   unsigned int max_size = STORE_MAX_PIECES + 1;
-  enum machine_mode mode = VOIDmode, tmode;
   enum insn_code icode;
 
   data->offset = 0;
@@ -2488,15 +2438,16 @@ store_by_pieces_1 (struct store_by_pieces_d *data ATTRIBUTE_UNUSED,
   if (!data->autinc_to
       && move_by_pieces_ninsns (data->len, align, max_size) > 2)
     {
-      /* Determine the main mode we'll be using.  */
-      for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
-          tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode))
-       if (GET_MODE_SIZE (tmode) < max_size)
-         mode = tmode;
+      /* Determine the main mode we'll be using.
+        MODE might not be used depending on the definitions of the
+        USE_* macros below.  */
+      enum machine_mode mode ATTRIBUTE_UNUSED
+       = widest_int_mode_for_size (max_size);
 
       if (USE_STORE_PRE_DECREMENT (mode) && data->reverse && ! data->autinc_to)
        {
-         data->to_addr = copy_addr_to_reg (plus_constant (to_addr, data->len));
+         data->to_addr = copy_to_mode_reg (to_addr_mode,
+                                           plus_constant (to_addr, data->len));
          data->autinc_to = 1;
          data->explicit_inc_to = -1;
        }
@@ -2504,46 +2455,28 @@ store_by_pieces_1 (struct store_by_pieces_d *data ATTRIBUTE_UNUSED,
       if (USE_STORE_POST_INCREMENT (mode) && ! data->reverse
          && ! data->autinc_to)
        {
-         data->to_addr = copy_addr_to_reg (to_addr);
+         data->to_addr = copy_to_mode_reg (to_addr_mode, to_addr);
          data->autinc_to = 1;
          data->explicit_inc_to = 1;
        }
 
       if ( !data->autinc_to && CONSTANT_P (to_addr))
-       data->to_addr = copy_addr_to_reg (to_addr);
+       data->to_addr = copy_to_mode_reg (to_addr_mode, to_addr);
     }
 
-  tmode = mode_for_size (STORE_MAX_PIECES * BITS_PER_UNIT, MODE_INT, 1);
-  if (align >= GET_MODE_ALIGNMENT (tmode))
-    align = GET_MODE_ALIGNMENT (tmode);
-  else
-    {
-      enum machine_mode xmode;
-
-      for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT), xmode = tmode;
-          tmode != VOIDmode;
-          xmode = tmode, tmode = GET_MODE_WIDER_MODE (tmode))
-       if (GET_MODE_SIZE (tmode) > STORE_MAX_PIECES
-           || SLOW_UNALIGNED_ACCESS (tmode, align))
-         break;
-
-      align = MAX (align, GET_MODE_ALIGNMENT (xmode));
-    }
+  align = alignment_for_piecewise_move (STORE_MAX_PIECES, align);
 
   /* First store what we can in the largest integer mode, then go to
      successively smaller modes.  */
 
   while (max_size > 1)
     {
-      for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
-          tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode))
-       if (GET_MODE_SIZE (tmode) < max_size)
-         mode = tmode;
+      enum machine_mode mode = widest_int_mode_for_size (max_size);
 
       if (mode == VOIDmode)
        break;
 
-      icode = optab_handler (mov_optab, mode)->insn_code;
+      icode = optab_handler (mov_optab, mode);
       if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode))
        store_by_pieces_2 (GEN_FCN (icode), mode, data);
 
@@ -2641,9 +2574,11 @@ clear_storage_hints (rtx object, rtx size, enum block_op_methods method,
   else if (set_storage_via_setmem (object, size, const0_rtx, align,
                                   expected_align, expected_size))
     ;
-  else
+  else if (ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (object)))
     return set_storage_via_libcall (object, size, const0_rtx,
                                    method == BLOCK_OP_TAILCALL);
+  else
+    gcc_unreachable ();
 
   return NULL;
 }
@@ -2687,8 +2622,7 @@ set_storage_via_libcall (rtx object, rtx size, rtx val, bool tailcall)
   val_tree = make_tree (integer_type_node, val);
 
   fn = clear_storage_libcall_fn (true);
-  call_expr = build_call_expr (fn, 3,
-                              object_tree, integer_zero_node, size_tree);
+  call_expr = build_call_expr (fn, 3, object_tree, val_tree, size_tree);
   CALL_EXPR_TAILCALL (call_expr) = tailcall;
 
   retval = expand_normal (call_expr);
@@ -2757,7 +2691,6 @@ set_storage_via_setmem (rtx object, rtx size, rtx val, unsigned int align,
      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)
@@ -2766,8 +2699,7 @@ set_storage_via_setmem (rtx object, rtx size, rtx val, unsigned int 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;
+      enum insn_code code = direct_optab_handler (setmem_optab, mode);
 
       if (code != CODE_FOR_nothing
          /* We don't need MODE to be narrower than
@@ -2777,46 +2709,26 @@ set_storage_via_setmem (rtx object, rtx size, rtx val, unsigned int align,
          && ((CONST_INT_P (size)
               && ((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)))
+             || GET_MODE_BITSIZE (mode) >= BITS_PER_WORD))
        {
-         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
-                                                / BITS_PER_UNIT),
-                                       GEN_INT (expected_size));
-         if (pat)
+         struct expand_operand ops[6];
+         unsigned int nops;
+
+         nops = insn_data[(int) code].n_generator_args;
+         gcc_assert (nops == 4 || nops == 6);
+
+         create_fixed_operand (&ops[0], object);
+         /* The check above guarantees that this size conversion is valid.  */
+         create_convert_operand_to (&ops[1], size, mode, true);
+         create_convert_operand_from (&ops[2], val, byte_mode, true);
+         create_integer_operand (&ops[3], align / BITS_PER_UNIT);
+         if (nops == 6)
            {
-             emit_insn (pat);
-             return true;
+             create_integer_operand (&ops[4], expected_align / BITS_PER_UNIT);
+             create_integer_operand (&ops[5], expected_size);
            }
-         else
-           delete_insns_since (last);
+         if (maybe_expand_insn (code, nops, ops))
+           return true;
        }
     }
 
@@ -2945,7 +2857,7 @@ read_complex_part (rtx cplx, bool imag_p)
     }
 
   return extract_bit_field (cplx, ibitsize, imag_p ? ibitsize : 0,
-                           true, NULL_RTX, imode, imode);
+                           true, false, NULL_RTX, imode, imode);
 }
 \f
 /* A subroutine of emit_move_insn_1.  Yet another lowpart generator.
@@ -3011,7 +2923,7 @@ emit_move_via_integer (enum machine_mode mode, rtx x, rtx y, bool force)
     return NULL_RTX;
 
   /* The target must support moves in this mode.  */
-  code = optab_handler (mov_optab, imode)->insn_code;
+  code = optab_handler (mov_optab, imode);
   if (code == CODE_FOR_nothing)
     return NULL_RTX;
 
@@ -3161,7 +3073,7 @@ emit_move_complex (enum machine_mode mode, rtx x, rtx y)
 
   /* 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)
+      && optab_handler (mov_optab, GET_MODE_INNER (mode)) != CODE_FOR_nothing)
     try_int = false;
   /* Not possible if the values are inherently not adjacent.  */
   else if (GET_CODE (x) == CONCAT || GET_CODE (y) == CONCAT)
@@ -3212,7 +3124,7 @@ 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 = optab_handler (mov_optab, CCmode)->insn_code;
+      enum insn_code code = optab_handler (mov_optab, CCmode);
       if (code != CODE_FOR_nothing)
        {
          x = emit_move_change_mode (CCmode, mode, x, true);
@@ -3352,7 +3264,7 @@ emit_move_insn_1 (rtx x, rtx y)
 
   gcc_assert ((unsigned int) mode < (unsigned int) MAX_MACHINE_MODE);
 
-  code = optab_handler (mov_optab, mode)->insn_code;
+  code = optab_handler (mov_optab, mode);
   if (code != CODE_FOR_nothing)
     return emit_insn (GEN_FCN (code) (x, y));
 
@@ -3415,7 +3327,7 @@ emit_move_insn (rtx x, rtx y)
 
       y_cst = y;
 
-      if (!LEGITIMATE_CONSTANT_P (y))
+      if (!targetm.legitimate_constant_p (mode, y))
        {
          y = force_const_mem (mode, y);
 
@@ -3432,12 +3344,14 @@ emit_move_insn (rtx x, rtx 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))
+      && (! memory_address_addr_space_p (GET_MODE (x), XEXP (x, 0),
+                                        MEM_ADDR_SPACE (x))
          && ! push_operand (x, GET_MODE (x))))
     x = validize_mem (x);
 
   if (MEM_P (y)
-      && ! memory_address_p (GET_MODE (y), XEXP (y, 0)))
+      && ! memory_address_addr_space_p (GET_MODE (y), XEXP (y, 0),
+                                       MEM_ADDR_SPACE (y)))
     y = validize_mem (y);
 
   gcc_assert (mode != BLKmode);
@@ -3448,7 +3362,7 @@ emit_move_insn (rtx x, rtx y)
       && (set = single_set (last_insn)) != NULL_RTX
       && SET_DEST (set) == x
       && ! rtx_equal_p (y_cst, SET_SRC (set)))
-    set_unique_reg_note (last_insn, REG_EQUAL, y_cst);
+    set_unique_reg_note (last_insn, REG_EQUAL, copy_rtx (y_cst));
 
   return last_insn;
 }
@@ -3469,7 +3383,7 @@ compress_float_constant (rtx x, rtx y)
 
   REAL_VALUE_FROM_CONST_DOUBLE (r, y);
 
-  if (LEGITIMATE_CONSTANT_P (y))
+  if (targetm.legitimate_constant_p (dstmode, y))
     oldcost = rtx_cost (y, SET, speed);
   else
     oldcost = rtx_cost (force_const_mem (dstmode, y), SET, speed);
@@ -3492,11 +3406,11 @@ compress_float_constant (rtx x, rtx y)
 
       trunc_y = CONST_DOUBLE_FROM_REAL_VALUE (r, srcmode);
 
-      if (LEGITIMATE_CONSTANT_P (trunc_y))
+      if (targetm.legitimate_constant_p (srcmode, trunc_y))
        {
          /* Skip if the target needs extra instructions to perform
             the extension.  */
-         if (! (*insn_data[ic].operand[1].predicate) (trunc_y, srcmode))
+         if (!insn_operand_matches (ic, 1, trunc_y))
            continue;
          /* This is valid, but may not be cheaper than the original. */
          newcost = rtx_cost (gen_rtx_FLOAT_EXTEND (dstmode, trunc_y), SET, speed);
@@ -3597,19 +3511,18 @@ emit_single_push_insn (enum machine_mode mode, rtx x, tree type)
   unsigned rounded_size = PUSH_ROUNDING (GET_MODE_SIZE (mode));
   rtx dest;
   enum insn_code icode;
-  insn_operand_predicate_fn pred;
 
   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 = optab_handler (push_optab, mode)->insn_code;
+  icode = optab_handler (push_optab, mode);
   if (icode != CODE_FOR_nothing)
     {
-      if (((pred = insn_data[(int) icode].operand[0].predicate)
-          && !((*pred) (x, mode))))
-       x = force_reg (mode, x);
-      emit_insn (GEN_FCN (icode) (x));
-      return;
+      struct expand_operand ops[1];
+
+      create_input_operand (&ops[0], x, mode);
+      if (maybe_expand_insn (icode, 1, ops))
+       return;
     }
   if (GET_MODE_SIZE (mode) == rounded_size)
     dest_addr = gen_rtx_fmt_e (STACK_PUSH_CODE, Pmode, stack_pointer_rtx);
@@ -3794,7 +3707,7 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
              || align >= BIGGEST_ALIGNMENT
              || (PUSH_ROUNDING (align / BITS_PER_UNIT)
                  == (align / BITS_PER_UNIT)))
-         && PUSH_ROUNDING (INTVAL (size)) == INTVAL (size))
+         && (HOST_WIDE_INT) PUSH_ROUNDING (INTVAL (size)) == INTVAL (size))
        {
          /* Push padding now if padding above and stack grows down,
             or if padding below and stack grows up.
@@ -3905,7 +3818,7 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
         by setting SKIP to 0.  */
       skip = (reg_parm_stack_space == 0) ? 0 : not_stack;
 
-      if (CONSTANT_P (x) && ! LEGITIMATE_CONSTANT_P (x))
+      if (CONSTANT_P (x) && !targetm.legitimate_constant_p (mode, x))
        x = validize_mem (force_const_mem (mode, x));
 
       /* If X is a hard register in a non-integer mode, copy it into a pseudo;
@@ -4024,6 +3937,8 @@ optimize_bitfield_assignment_op (unsigned HOST_WIDE_INT bitsize,
   tree op0, op1;
   rtx value, result;
   optab binop;
+  gimple srcstmt;
+  enum tree_code code;
 
   if (mode1 != VOIDmode
       || bitsize >= BITS_PER_WORD
@@ -4033,13 +3948,37 @@ optimize_bitfield_assignment_op (unsigned HOST_WIDE_INT bitsize,
     return false;
 
   STRIP_NOPS (src);
-  if (!BINARY_CLASS_P (src)
-      || TREE_CODE (TREE_TYPE (src)) != INTEGER_TYPE)
+  if (TREE_CODE (src) != SSA_NAME)
+    return false;
+  if (TREE_CODE (TREE_TYPE (src)) != INTEGER_TYPE)
     return false;
 
-  op0 = TREE_OPERAND (src, 0);
-  op1 = TREE_OPERAND (src, 1);
-  STRIP_NOPS (op0);
+  srcstmt = get_gimple_for_ssa_name (src);
+  if (!srcstmt
+      || TREE_CODE_CLASS (gimple_assign_rhs_code (srcstmt)) != tcc_binary)
+    return false;
+
+  code = gimple_assign_rhs_code (srcstmt);
+
+  op0 = gimple_assign_rhs1 (srcstmt);
+
+  /* If OP0 is an SSA_NAME, then we want to walk the use-def chain
+     to find its initialization.  Hopefully the initialization will
+     be from a bitfield load.  */
+  if (TREE_CODE (op0) == SSA_NAME)
+    {
+      gimple op0stmt = get_gimple_for_ssa_name (op0);
+
+      /* We want to eventually have OP0 be the same as TO, which
+        should be a bitfield.  */
+      if (!op0stmt
+         || !is_gimple_assign (op0stmt)
+         || gimple_assign_rhs_code (op0stmt) != TREE_CODE (to))
+       return false;
+      op0 = gimple_assign_rhs1 (op0stmt);
+    }
+
+  op1 = gimple_assign_rhs2 (srcstmt);
 
   if (!operand_equal_p (to, op0, 0))
     return false;
@@ -4076,7 +4015,7 @@ optimize_bitfield_assignment_op (unsigned HOST_WIDE_INT bitsize,
   if (BYTES_BIG_ENDIAN)
     bitpos = str_bitsize - bitpos - bitsize;
 
-  switch (TREE_CODE (src))
+  switch (code)
     {
     case PLUS_EXPR:
     case MINUS_EXPR:
@@ -4104,15 +4043,14 @@ optimize_bitfield_assignment_op (unsigned HOST_WIDE_INT bitsize,
          set_mem_expr (str_rtx, 0);
        }
 
-      binop = TREE_CODE (src) == PLUS_EXPR ? add_optab : sub_optab;
+      binop = code == PLUS_EXPR ? add_optab : sub_optab;
       if (bitsize == 1 && bitpos + bitsize != str_bitsize)
        {
          value = expand_and (str_mode, value, const1_rtx, NULL);
          binop = xor_optab;
        }
       value = expand_shift (LSHIFT_EXPR, str_mode, value,
-                           build_int_cst (NULL_TREE, bitpos),
-                           NULL_RTX, 1);
+                           bitpos, NULL_RTX, 1);
       result = expand_binop (str_mode, binop, str_rtx,
                             value, str_rtx, 1, OPTAB_WIDEN);
       if (result != str_rtx)
@@ -4137,7 +4075,7 @@ optimize_bitfield_assignment_op (unsigned HOST_WIDE_INT bitsize,
          set_mem_expr (str_rtx, 0);
        }
 
-      binop = TREE_CODE (src) == BIT_IOR_EXPR ? ior_optab : xor_optab;
+      binop = code == 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)
@@ -4146,8 +4084,7 @@ optimize_bitfield_assignment_op (unsigned HOST_WIDE_INT bitsize,
                              NULL_RTX);
        }
       value = expand_shift (LSHIFT_EXPR, GET_MODE (str_rtx), value,
-                           build_int_cst (NULL_TREE, bitpos),
-                           NULL_RTX, 1);
+                           bitpos, NULL_RTX, 1);
       result = expand_binop (GET_MODE (str_rtx), binop, str_rtx,
                             value, str_rtx, 1, OPTAB_WIDEN);
       if (result != str_rtx)
@@ -4170,11 +4107,14 @@ expand_assignment (tree to, tree from, bool nontemporal)
 {
   rtx to_rtx = 0;
   rtx result;
+  enum machine_mode mode;
+  int align;
+  enum insn_code icode;
 
   /* Don't crash if the lhs of the assignment was erroneous.  */
   if (TREE_CODE (to) == ERROR_MARK)
     {
-      result = expand_normal (from);
+      expand_normal (from);
       return;
     }
 
@@ -4182,12 +4122,77 @@ expand_assignment (tree to, tree from, bool nontemporal)
   if (operand_equal_p (to, from, 0))
     return;
 
+  mode = TYPE_MODE (TREE_TYPE (to));
+  if ((TREE_CODE (to) == MEM_REF
+       || TREE_CODE (to) == TARGET_MEM_REF)
+      && mode != BLKmode
+      && ((align = MAX (TYPE_ALIGN (TREE_TYPE (to)),
+                       get_object_alignment (to, BIGGEST_ALIGNMENT)))
+         < (signed) GET_MODE_ALIGNMENT (mode))
+      && ((icode = optab_handler (movmisalign_optab, mode))
+         != CODE_FOR_nothing))
+    {
+      struct expand_operand ops[2];
+      enum machine_mode address_mode;
+      rtx reg, op0, mem;
+
+      reg = expand_expr (from, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+      reg = force_not_mem (reg);
+
+      if (TREE_CODE (to) == MEM_REF)
+       {
+         addr_space_t as
+             = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (to, 1))));
+         tree base = TREE_OPERAND (to, 0);
+         address_mode = targetm.addr_space.address_mode (as);
+         op0 = expand_expr (base, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+         op0 = convert_memory_address_addr_space (address_mode, op0, as);
+         if (!integer_zerop (TREE_OPERAND (to, 1)))
+           {
+             rtx off
+                 = immed_double_int_const (mem_ref_offset (to), address_mode);
+             op0 = simplify_gen_binary (PLUS, address_mode, op0, off);
+           }
+         op0 = memory_address_addr_space (mode, op0, as);
+         mem = gen_rtx_MEM (mode, op0);
+         set_mem_attributes (mem, to, 0);
+         set_mem_addr_space (mem, as);
+       }
+      else if (TREE_CODE (to) == TARGET_MEM_REF)
+       {
+         addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (to));
+         struct mem_address addr;
+
+         get_address_description (to, &addr);
+         op0 = addr_for_mem_ref (&addr, as, true);
+         op0 = memory_address_addr_space (mode, op0, as);
+         mem = gen_rtx_MEM (mode, op0);
+         set_mem_attributes (mem, to, 0);
+         set_mem_addr_space (mem, as);
+       }
+      else
+       gcc_unreachable ();
+      if (TREE_THIS_VOLATILE (to))
+       MEM_VOLATILE_P (mem) = 1;
+
+      create_fixed_operand (&ops[0], mem);
+      create_input_operand (&ops[1], reg, mode);
+      /* The movmisalign<mode> pattern cannot fail, else the assignment would
+         silently be omitted.  */
+      expand_insn (icode, 2, ops);
+      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
      an array element in an unaligned packed structure field, has the same
      problem.  */
   if (handled_component_p (to)
+      /* ???  We only need to handle MEM_REF here if the access is not
+         a full access of the base object.  */
+      || (TREE_CODE (to) == MEM_REF
+         && TREE_CODE (TREE_OPERAND (to, 0)) == ADDR_EXPR)
       || TREE_CODE (TREE_TYPE (to)) == ARRAY_TYPE)
     {
       enum machine_mode mode1;
@@ -4206,8 +4211,21 @@ expand_assignment (tree to, tree from, bool nontemporal)
 
       to_rtx = expand_normal (tem);
 
+      /* If the bitfield is volatile, we want to access it in the
+        field's mode, not the computed mode.
+        If a MEM has VOIDmode (external with incomplete type),
+        use BLKmode for it instead.  */
+      if (MEM_P (to_rtx))
+       {
+         if (volatilep && flag_strict_volatile_bitfields > 0)
+           to_rtx = adjust_address (to_rtx, mode1, 0);
+         else if (GET_MODE (to_rtx) == VOIDmode)
+           to_rtx = adjust_address (to_rtx, BLKmode, 0);
+       }
       if (offset != 0)
        {
+         enum machine_mode address_mode;
          rtx offset_rtx;
 
          if (!MEM_P (to_rtx))
@@ -4220,13 +4238,10 @@ expand_assignment (tree to, tree from, bool nontemporal)
            }
 
          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);
-#else
-         if (GET_MODE (offset_rtx) != ptr_mode)
-           offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
-#endif
+         address_mode
+           = targetm.addr_space.address_mode (MEM_ADDR_SPACE (to_rtx));
+         if (GET_MODE (offset_rtx) != address_mode)
+           offset_rtx = convert_to_mode (address_mode, offset_rtx, 0);
 
          /* A constant address in TO_RTX can have VOIDmode, we must not try
             to call force_reg for that case.  Avoid that case.  */
@@ -4247,19 +4262,61 @@ expand_assignment (tree to, tree from, bool nontemporal)
                                                                   offset));
        }
 
+      /* No action is needed if the target is not a memory and the field
+        lies completely outside that target.  This can occur if the source
+        code contains an out-of-bounds access to a small array.  */
+      if (!MEM_P (to_rtx)
+         && GET_MODE (to_rtx) != BLKmode
+         && (unsigned HOST_WIDE_INT) bitpos
+            >= GET_MODE_BITSIZE (GET_MODE (to_rtx)))
+       {
+         expand_normal (from);
+         result = NULL;
+       }
       /* Handle expand_expr of a complex value returning a CONCAT.  */
-      if (GET_CODE (to_rtx) == CONCAT)
+      else if (GET_CODE (to_rtx) == CONCAT)
        {
-         if (COMPLEX_MODE_P (TYPE_MODE (TREE_TYPE (from))))
+         unsigned short mode_bitsize = GET_MODE_BITSIZE (GET_MODE (to_rtx));
+         if (COMPLEX_MODE_P (TYPE_MODE (TREE_TYPE (from)))
+             && bitpos == 0
+             && bitsize == mode_bitsize)
+           result = store_expr (from, to_rtx, false, nontemporal);
+         else if (bitsize == mode_bitsize / 2
+                  && (bitpos == 0 || bitpos == mode_bitsize / 2))
+           result = store_expr (from, XEXP (to_rtx, bitpos != 0), false,
+                                nontemporal);
+         else if (bitpos + bitsize <= mode_bitsize / 2)
+           result = store_field (XEXP (to_rtx, 0), bitsize, bitpos,
+                                 mode1, from, TREE_TYPE (tem),
+                                 get_alias_set (to), nontemporal);
+         else if (bitpos >= mode_bitsize / 2)
+           result = store_field (XEXP (to_rtx, 1), bitsize,
+                                 bitpos - mode_bitsize / 2, mode1, from,
+                                 TREE_TYPE (tem), get_alias_set (to),
+                                 nontemporal);
+         else if (bitpos == 0 && bitsize == mode_bitsize)
            {
-             gcc_assert (bitpos == 0);
-             result = store_expr (from, to_rtx, false, nontemporal);
+             rtx from_rtx;
+             result = expand_normal (from);
+             from_rtx = simplify_gen_subreg (GET_MODE (to_rtx), result,
+                                             TYPE_MODE (TREE_TYPE (from)), 0);
+             emit_move_insn (XEXP (to_rtx, 0),
+                             read_complex_part (from_rtx, false));
+             emit_move_insn (XEXP (to_rtx, 1),
+                             read_complex_part (from_rtx, true));
            }
          else
            {
-             gcc_assert (bitpos == 0 || bitpos == GET_MODE_BITSIZE (mode1));
-             result = store_expr (from, XEXP (to_rtx, bitpos != 0), false,
-                                  nontemporal);
+             rtx temp = assign_stack_temp (GET_MODE (to_rtx),
+                                           GET_MODE_SIZE (GET_MODE (to_rtx)),
+                                           0);
+             write_complex_part (temp, XEXP (to_rtx, 0), false);
+             write_complex_part (temp, XEXP (to_rtx, 1), true);
+             result = store_field (temp, bitsize, bitpos, mode1, from,
+                                   TREE_TYPE (tem), get_alias_set (to),
+                                   nontemporal);
+             emit_move_insn (XEXP (to_rtx, 0), read_complex_part (temp, false));
+             emit_move_insn (XEXP (to_rtx, 1), read_complex_part (temp, true));
            }
        }
       else
@@ -4296,36 +4353,6 @@ expand_assignment (tree to, tree from, bool nontemporal)
       return;
     }
 
-   else if (TREE_CODE (to) == MISALIGNED_INDIRECT_REF)
-     {
-       enum machine_mode mode, op_mode1;
-       enum insn_code icode;
-       rtx reg, addr, mem, insn;
-
-       reg = expand_expr (from, NULL_RTX, VOIDmode, EXPAND_NORMAL);
-       reg = force_not_mem (reg);
-
-       mode = TYPE_MODE (TREE_TYPE (to));
-       addr = expand_expr (TREE_OPERAND (to, 0), NULL_RTX, VOIDmode,
-                         EXPAND_SUM);
-       addr = memory_address (mode, addr);
-       mem = gen_rtx_MEM (mode, addr);
-
-       set_mem_attributes (mem, to, 0);
-
-       icode = movmisalign_optab->handlers[mode].insn_code;
-       gcc_assert (icode != CODE_FOR_nothing);
-
-       op_mode1 = insn_data[icode].operand[1].mode;
-       if (! (*insn_data[icode].operand[1].predicate) (reg, op_mode1)
-           && op_mode1 != VOIDmode)
-         reg = copy_to_mode_reg (op_mode1, reg);
-
-      insn = GEN_FCN (icode) (mem, reg);
-       emit_insn (insn);
-       return;
-     }
-
   /* If the rhs is a function call and its value is not an aggregate,
      call the function before we start to compute the lhs.
      This is needed for correct code for cases such as
@@ -4360,7 +4387,10 @@ expand_assignment (tree to, tree from, bool nontemporal)
       else
        {
          if (POINTER_TYPE_P (TREE_TYPE (to)))
-           value = convert_memory_address (GET_MODE (to_rtx), value);
+           value = convert_memory_address_addr_space
+                     (GET_MODE (to_rtx), value,
+                      TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (to))));
+
          emit_move_insn (to_rtx, value);
        }
       preserve_temp_slots (to_rtx);
@@ -4399,7 +4429,11 @@ expand_assignment (tree to, tree from, bool nontemporal)
   /* In case we are returning the contents of an object which overlaps
      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
+  if (TREE_CODE (to) == RESULT_DECL
+      && TREE_CODE (from) == INDIRECT_REF
+      && ADDR_SPACE_GENERIC_P
+          (TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (from, 0)))))
+      && refs_may_alias_p (to, from)
       && cfun->returns_struct
       && !cfun->returns_pcc_struct)
     {
@@ -4435,34 +4469,19 @@ expand_assignment (tree to, tree from, bool nontemporal)
 /* Emits nontemporal store insn that moves FROM to TO.  Returns true if this
    succeeded, false otherwise.  */
 
-static bool
+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;
+  struct expand_operand ops[2];
+  enum machine_mode mode = GET_MODE (to);
+  enum insn_code code = optab_handler (storent_optab, mode);
 
   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;
+  create_fixed_operand (&ops[0], to);
+  create_input_operand (&ops[1], from, mode);
+  return maybe_expand_insn (code, 2, ops);
 }
 
 /* Generate code for computing expression EXP,
@@ -4477,7 +4496,7 @@ emit_storent_insn (rtx to, rtx from)
 
    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.
+
    If NONTEMPORAL is true, try using a nontemporal store instruction.  */
 
 rtx
@@ -4485,7 +4504,6 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
 {
   rtx temp;
   rtx alt_rtl = NULL_RTX;
-  int dont_return_target = 0;
   location_t loc = EXPR_LOCATION (exp);
 
   if (VOID_TYPE_P (TREE_TYPE (exp)))
@@ -4517,7 +4535,7 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
 
       do_pending_stack_adjust ();
       NO_DEFER_POP;
-      jumpifnot (TREE_OPERAND (exp, 0), lab1);
+      jumpifnot (TREE_OPERAND (exp, 0), lab1, -1);
       store_expr (TREE_OPERAND (exp, 1), target, call_param_p,
                  nontemporal);
       emit_jump_insn (gen_jump (lab2));
@@ -4592,32 +4610,42 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
 
       return NULL_RTX;
     }
-  else if (TREE_CODE (exp) == STRING_CST
+  else if ((TREE_CODE (exp) == STRING_CST
+           || (TREE_CODE (exp) == MEM_REF
+               && TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
+               && TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
+                  == STRING_CST
+               && integer_zerop (TREE_OPERAND (exp, 1))))
           && !nontemporal && !call_param_p
-          && TREE_STRING_LENGTH (exp) > 0
-          && TYPE_MODE (TREE_TYPE (exp)) == BLKmode)
+          && MEM_P (target))
     {
       /* Optimize initialization of an array with a STRING_CST.  */
       HOST_WIDE_INT exp_len, str_copy_len;
       rtx dest_mem;
+      tree str = TREE_CODE (exp) == STRING_CST
+                ? exp : TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
 
       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)
+      if (TREE_STRING_LENGTH (str) <= 0)
+       goto normal_expr;
+
+      str_copy_len = strlen (TREE_STRING_POINTER (str));
+      if (str_copy_len < TREE_STRING_LENGTH (str) - 1)
        goto normal_expr;
 
-      str_copy_len = TREE_STRING_LENGTH (exp);
-      if ((STORE_MAX_PIECES & (STORE_MAX_PIECES - 1)) == 0)
+      str_copy_len = TREE_STRING_LENGTH (str);
+      if ((STORE_MAX_PIECES & (STORE_MAX_PIECES - 1)) == 0
+         && TREE_STRING_POINTER (str)[TREE_STRING_LENGTH (str) - 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,
-                               CONST_CAST(char *, TREE_STRING_POINTER (exp)),
+                               CONST_CAST (char *, TREE_STRING_POINTER (str)),
                                MEM_ALIGN (target), false))
        goto normal_expr;
 
@@ -4625,7 +4653,8 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
 
       dest_mem = store_by_pieces (dest_mem,
                                  str_copy_len, builtin_strncpy_read_str,
-                                 CONST_CAST(char *, TREE_STRING_POINTER (exp)),
+                                 CONST_CAST (char *,
+                                             TREE_STRING_POINTER (str)),
                                  MEM_ALIGN (target), false,
                                  exp_len > str_copy_len ? 1 : 0);
       if (exp_len > str_copy_len)
@@ -4646,19 +4675,6 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
                               (call_param_p
                                ? EXPAND_STACK_PARM : EXPAND_NORMAL),
                               &alt_rtl);
-      /* Return TARGET if it's a specified hardware register.
-        If TARGET is a volatile mem ref, either return TARGET
-        or return a reg copied *from* TARGET; ANSI requires this.
-
-        Otherwise, if TEMP is not TARGET, return TEMP
-        if it is constant (for efficiency),
-        or if we really want the correct value.  */
-      if (!(target && REG_P (target)
-           && REGNO (target) < FIRST_PSEUDO_REGISTER)
-         && !(MEM_P (target) && MEM_VOLATILE_P (target))
-         && ! rtx_equal_p (temp, target)
-         && CONSTANT_P (temp))
-       dont_return_target = 1;
     }
 
   /* If TEMP is a VOIDmode constant and the mode of the type of EXP is not
@@ -4696,7 +4712,10 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
       /* If store_expr stores a DECL whose DECL_RTL(exp) == TARGET,
         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))
+      && !(alt_rtl
+          && rtx_equal_p (alt_rtl, target)
+          && !side_effects_p (alt_rtl)
+          && !side_effects_p (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 must not be given objects that are not
@@ -4707,20 +4726,15 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
          && GET_MODE (temp) != VOIDmode)
        {
          int unsignedp = TYPE_UNSIGNED (TREE_TYPE (exp));
-         if (dont_return_target)
-           {
-             /* In this case, we will return TEMP,
-                so make sure it has the proper mode.
-                But don't forget to store the value into TARGET.  */
-             temp = convert_to_mode (GET_MODE (target), temp, unsignedp);
-             emit_move_insn (target, temp);
-           }
-         else if (GET_MODE (target) == BLKmode
-                  || GET_MODE (temp) == BLKmode)
+         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 if (GET_MODE (target) == BLKmode)
+           store_bit_field (target, INTVAL (expr_size (exp)) * BITS_PER_UNIT,
+                            0, GET_MODE (temp), temp);
          else
            convert_move (target, temp, unsignedp);
        }
@@ -4740,6 +4754,11 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
                              ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
          else
            {
+             enum machine_mode pointer_mode
+               = targetm.addr_space.pointer_mode (MEM_ADDR_SPACE (target));
+             enum machine_mode address_mode
+               = targetm.addr_space.address_mode (MEM_ADDR_SPACE (target));
+
              /* Compute the size of the data to copy from the string.  */
              tree copy_size
                = size_binop_loc (loc, MIN_EXPR,
@@ -4752,14 +4771,14 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
              rtx label = 0;
 
              /* Copy that much.  */
-             copy_size_rtx = convert_to_mode (ptr_mode, copy_size_rtx,
+             copy_size_rtx = convert_to_mode (pointer_mode, copy_size_rtx,
                                               TYPE_UNSIGNED (sizetype));
              emit_block_move (target, temp, copy_size_rtx,
                               (call_param_p
                                ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
 
              /* Figure out how much is left in TARGET that we have to clear.
-                Do all calculations in ptr_mode.  */
+                Do all calculations in pointer_mode.  */
              if (CONST_INT_P (copy_size_rtx))
                {
                  size = plus_constant (size, -INTVAL (copy_size_rtx));
@@ -4772,11 +4791,10 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
                                       copy_size_rtx, NULL_RTX, 0,
                                       OPTAB_LIB_WIDEN);
 
-#ifdef POINTERS_EXTEND_UNSIGNED
-                 if (GET_MODE (copy_size_rtx) != Pmode)
-                   copy_size_rtx = convert_to_mode (Pmode, copy_size_rtx,
+                 if (GET_MODE (copy_size_rtx) != address_mode)
+                   copy_size_rtx = convert_to_mode (address_mode,
+                                                    copy_size_rtx,
                                                     TYPE_UNSIGNED (sizetype));
-#endif
 
                  target = offset_address (target, copy_size_rtx,
                                           highest_pow2_factor (copy_size));
@@ -4839,9 +4857,8 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
 
   FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), idx, purpose, value)
     {
-      HOST_WIDE_INT mult;
+      HOST_WIDE_INT mult = 1;
 
-      mult = 1;
       if (TREE_CODE (purpose) == RANGE_EXPR)
        {
          tree lo_index = TREE_OPERAND (purpose, 0);
@@ -4903,12 +4920,17 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
          break;
 
        default:
-         nz_elts += mult;
-         elt_count += mult;
+         {
+           HOST_WIDE_INT tc = count_type_elements (TREE_TYPE (value), true);
+           if (tc < 1)
+             tc = 1;
+           nz_elts += mult * tc;
+           elt_count += mult * tc;
 
-         if (const_from_elts_p && const_p)
-           const_p = initializer_constant_valid_p (value, TREE_TYPE (value))
-                     != NULL_TREE;
+           if (const_from_elts_p && const_p)
+             const_p = initializer_constant_valid_p (value, TREE_TYPE (value))
+                       != NULL_TREE;
+         }
          break;
        }
     }
@@ -5009,7 +5031,7 @@ count_type_elements (const_tree type, bool allow_flexarr)
        HOST_WIDE_INT n = 0, t;
        tree f;
 
-       for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f))
+       for (f = TYPE_FIELDS (type); f ; f = DECL_CHAIN (f))
          if (TREE_CODE (f) == FIELD_DECL)
            {
              t = count_type_elements (TREE_TYPE (f), false);
@@ -5018,7 +5040,7 @@ count_type_elements (const_tree type, bool allow_flexarr)
                  /* Check for structures with flexible array member.  */
                  tree tf = TREE_TYPE (f);
                  if (allow_flexarr
-                     && TREE_CHAIN (f) == NULL
+                     && DECL_CHAIN (f) == NULL
                      && TREE_CODE (tf) == ARRAY_TYPE
                      && TYPE_DOMAIN (tf)
                      && TYPE_MIN_VALUE (TYPE_DOMAIN (tf))
@@ -5266,6 +5288,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
 
            if (offset)
              {
+               enum machine_mode address_mode;
                rtx offset_rtx;
 
                offset
@@ -5276,13 +5299,10 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                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);
-#else
-               if (GET_MODE (offset_rtx) != ptr_mode)
-                 offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
-#endif
+               address_mode
+                 = targetm.addr_space.address_mode (MEM_ADDR_SPACE (to_rtx));
+               if (GET_MODE (offset_rtx) != address_mode)
+                 offset_rtx = convert_to_mode (address_mode, offset_rtx, 0);
 
                to_rtx = offset_address (to_rtx, offset_rtx,
                                         highest_pow2_factor (offset));
@@ -5532,7 +5552,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                    /* Generate a conditional jump to exit the loop.  */
                    exit_cond = build2 (LT_EXPR, integer_type_node,
                                        index, hi_index);
-                   jumpif (exit_cond, loop_end);
+                   jumpif (exit_cond, loop_end, -1);
 
                    /* Update the loop counter, and jump to the head of
                       the loop.  */
@@ -5617,7 +5637,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
          {
            enum machine_mode mode = GET_MODE (target);
 
-           icode = (int) optab_handler (vec_init_optab, mode)->insn_code;
+           icode = (int) optab_handler (vec_init_optab, mode);
            if (icode != CODE_FOR_nothing)
              {
                unsigned int i;
@@ -5645,7 +5665,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                int n_elts_here = tree_low_cst
                  (int_const_binop (TRUNC_DIV_EXPR,
                                    TYPE_SIZE (TREE_TYPE (value)),
-                                   TYPE_SIZE (elttype), 0), 1);
+                                   TYPE_SIZE (elttype)), 1);
 
                count += n_elts_here;
                if (mostly_zeros_p (value))
@@ -5739,7 +5759,7 @@ 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.
-   
+
    If NONTEMPORAL is true, try generating a nontemporal store.  */
 
 static rtx
@@ -5747,8 +5767,6 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
             enum machine_mode mode, tree exp, tree type,
             alias_set_type alias_set, bool nontemporal)
 {
-  HOST_WIDE_INT width_mask = 0;
-
   if (TREE_CODE (exp) == ERROR_MARK)
     return const0_rtx;
 
@@ -5756,8 +5774,6 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
      side-effects.  */
   if (bitsize == 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;
 
   /* If we are storing into an unaligned field of an aligned union that is
      in a register, we may have the mode of TARGET being an integer mode but
@@ -5819,7 +5835,15 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
         operations.  */
       || (bitsize >= 0
          && TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) == INTEGER_CST
-         && compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)), bitsize) != 0))
+         && compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)), bitsize) != 0)
+      /* If we are expanding a MEM_REF of a non-BLKmode non-addressable
+         decl we must use bitfield operations.  */
+      || (bitsize >= 0
+         && TREE_CODE (exp) == MEM_REF
+         && TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
+         && DECL_P (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
+         && !TREE_ADDRESSABLE (TREE_OPERAND (TREE_OPERAND (exp, 0),0 ))
+         && DECL_MODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) != BLKmode))
     {
       rtx temp;
       gimple nop_def;
@@ -5854,8 +5878,7 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
          && bitsize < (HOST_WIDE_INT) GET_MODE_BITSIZE (GET_MODE (temp))
          && TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
        temp = expand_shift (RSHIFT_EXPR, GET_MODE (temp), temp,
-                            size_int (GET_MODE_BITSIZE (GET_MODE (temp))
-                                      - bitsize),
+                            GET_MODE_BITSIZE (GET_MODE (temp)) - bitsize,
                             NULL_RTX, 1);
 
       /* Unless MODE is VOIDmode or BLKmode, convert TEMP to
@@ -5900,7 +5923,8 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
       if (to_rtx == target)
        to_rtx = copy_rtx (to_rtx);
 
-      MEM_SET_IN_STRUCT_P (to_rtx, 1);
+      if (!MEM_SCALAR_P (to_rtx))
+       MEM_IN_STRUCT_P (to_rtx) = 1;
       if (!MEM_KEEP_ALIAS_SET_P (to_rtx) && MEM_ALIAS_SET (to_rtx) != 0)
        set_mem_alias_set (to_rtx, alias_set);
 
@@ -5953,10 +5977,11 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
   enum machine_mode mode = VOIDmode;
   bool blkmode_bitfield = false;
   tree offset = size_zero_node;
-  tree bit_offset = bitsize_zero_node;
+  double_int bit_offset = double_int_zero;
 
   /* First get the mode, signedness, and size.  We do this from just the
      outermost expression.  */
+  *pbitsize = -1;
   if (TREE_CODE (exp) == COMPONENT_REF)
     {
       tree field = TREE_OPERAND (exp, 1);
@@ -5965,6 +5990,12 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
        mode = DECL_MODE (field);
       else if (DECL_MODE (field) == BLKmode)
        blkmode_bitfield = true;
+      else if (TREE_THIS_VOLATILE (exp)
+              && flag_strict_volatile_bitfields > 0)
+       /* Volatile bitfields should be accessed in the mode of the
+            field's type, not the mode computed based on the bit
+            size.  */
+       mode = TYPE_MODE (DECL_BIT_FIELD_TYPE (field));
 
       *punsignedp = DECL_UNSIGNED (field);
     }
@@ -6007,8 +6038,9 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
       switch (TREE_CODE (exp))
        {
        case BIT_FIELD_REF:
-         bit_offset = size_binop (PLUS_EXPR, bit_offset,
-                                  TREE_OPERAND (exp, 2));
+         bit_offset
+           = double_int_add (bit_offset,
+                             tree_to_double_int (TREE_OPERAND (exp, 2)));
          break;
 
        case COMPONENT_REF:
@@ -6023,8 +6055,9 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
              break;
 
            offset = size_binop (PLUS_EXPR, offset, this_offset);
-           bit_offset = size_binop (PLUS_EXPR, bit_offset,
-                                    DECL_FIELD_BIT_OFFSET (field));
+           bit_offset = double_int_add (bit_offset,
+                                        tree_to_double_int
+                                          (DECL_FIELD_BIT_OFFSET (field)));
 
            /* ??? Right now we don't do anything with DECL_OFFSET_ALIGN.  */
          }
@@ -6056,8 +6089,8 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
          break;
 
        case IMAGPART_EXPR:
-         bit_offset = size_binop (PLUS_EXPR, bit_offset,
-                                  bitsize_int (*pbitsize));
+         bit_offset = double_int_add (bit_offset,
+                                      uhwi_to_double_int (*pbitsize));
          break;
 
        case VIEW_CONVERT_EXPR:
@@ -6071,6 +6104,24 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
            goto done;
          break;
 
+       case MEM_REF:
+         /* Hand back the decl for MEM[&decl, off].  */
+         if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR)
+           {
+             tree off = TREE_OPERAND (exp, 1);
+             if (!integer_zerop (off))
+               {
+                 double_int boff, coff = mem_ref_offset (exp);
+                 boff = double_int_lshift (coff,
+                                           BITS_PER_UNIT == 8
+                                           ? 3 : exact_log2 (BITS_PER_UNIT),
+                                           HOST_BITS_PER_DOUBLE_INT, true);
+                 bit_offset = double_int_add (bit_offset, boff);
+               }
+             exp = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+           }
+         goto done;
+
        default:
          goto done;
        }
@@ -6088,9 +6139,11 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
      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));
+      double_int tem = double_int_lshift (tree_to_double_int (offset),
+                                         BITS_PER_UNIT == 8
+                                         ? 3 : exact_log2 (BITS_PER_UNIT),
+                                         HOST_BITS_PER_DOUBLE_INT, true);
+      tem = double_int_add (tem, bit_offset);
       if (double_int_fits_in_shwi_p (tem))
        {
          *pbitpos = double_int_to_shwi (tem);
@@ -6101,7 +6154,7 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
   /* Otherwise, split it up.  */
   if (offset)
     {
-      *pbitpos = tree_low_cst (bit_offset, 0);
+      *pbitpos = double_int_to_shwi (bit_offset);
       *poffset = offset;
     }
 
@@ -6133,7 +6186,7 @@ contains_packed_reference (const_tree exp)
        case COMPONENT_REF:
          {
            tree field = TREE_OPERAND (exp, 1);
-           packed_p = DECL_PACKED (field) 
+           packed_p = DECL_PACKED (field)
                       || TYPE_PACKED (TREE_TYPE (field))
                       || TYPE_PACKED (TREE_TYPE (exp));
            if (packed_p)
@@ -6521,9 +6574,7 @@ safe_from_p (const_rtx x, tree exp, int top_p)
          constructor_elt *ce;
          unsigned HOST_WIDE_INT idx;
 
-         for (idx = 0;
-              VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (exp), idx, ce);
-              idx++)
+         FOR_EACH_VEC_ELT (constructor_elt, CONSTRUCTOR_ELTS (exp), idx, ce)
            if ((ce->index != NULL_TREE && !safe_from_p (x, ce->index, 0))
                || !safe_from_p (x, ce->value, 0))
              return 0;
@@ -6583,9 +6634,7 @@ safe_from_p (const_rtx x, tree exp, int top_p)
            }
          break;
 
-       case MISALIGNED_INDIRECT_REF:
-       case ALIGN_INDIRECT_REF:
-       case INDIRECT_REF:
+       case MEM_REF:
          if (MEM_P (x)
              && alias_sets_conflict_p (MEM_ALIAS_SET (x),
                                        get_alias_set (exp)))
@@ -6740,24 +6789,10 @@ highest_pow2_factor_for_target (const_tree target, const_tree exp)
 {
   unsigned HOST_WIDE_INT talign = target_align (target) / BITS_PER_UNIT;
   unsigned HOST_WIDE_INT factor = highest_pow2_factor (exp);
-  
-  return MAX (factor, talign);
-}
-\f
-/* Return &VAR expression for emulated thread local VAR.  */
 
-static tree
-emutls_var_address (tree var)
-{
-  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 (UNKNOWN_LOCATION, fn, arglist);
-  return fold_convert (build_pointer_type (TREE_TYPE (var)), call);
+  return MAX (factor, talign);
 }
 \f
-
 /* Subroutine of expand_expr.  Expand the two operands of a binary
    expression EXP0 and EXP1 placing the results in OP0 and OP1.
    The value may be stored in TARGET if TARGET is nonzero.  The
@@ -6805,7 +6840,7 @@ expand_expr_constant (tree exp, int defer, enum expand_modifier modifier)
 
 static rtx
 expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
-                        enum expand_modifier modifier)
+                        enum expand_modifier modifier, addr_space_t as)
 {
   rtx result, subtarget;
   tree inner, offset;
@@ -6829,10 +6864,19 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
       /* This case will happen via recursion for &a->b.  */
       return expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
 
+    case MEM_REF:
+      {
+       tree tem = TREE_OPERAND (exp, 0);
+       if (!integer_zerop (TREE_OPERAND (exp, 1)))
+         tem = build2 (POINTER_PLUS_EXPR, TREE_TYPE (TREE_OPERAND (exp, 1)),
+                       tem,
+                       double_int_to_tree (sizetype, mem_ref_offset (exp)));
+       return expand_expr (tem, target, tmode, modifier);
+      }
+
     case CONST_DECL:
-      /* Recurse and make the output_constant_def clause above handle this.  */
-      return expand_expr_addr_expr_1 (DECL_INITIAL (exp), target,
-                                     tmode, modifier);
+      /* Expand the initializer like constants above.  */
+      return XEXP (expand_expr_constant (DECL_INITIAL (exp), 0, modifier), 0);
 
     case REALPART_EXPR:
       /* The real part of the complex number is always first, therefore
@@ -6851,18 +6895,6 @@ 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
@@ -6922,7 +6954,7 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
       TYPE_ALIGN (TREE_TYPE (inner)) = TYPE_ALIGN (TREE_TYPE (exp));
       TYPE_USER_ALIGN (TREE_TYPE (inner)) = 1;
     }
-  result = expand_expr_addr_expr_1 (inner, subtarget, tmode, modifier);
+  result = expand_expr_addr_expr_1 (inner, subtarget, tmode, modifier, as);
 
   if (offset)
     {
@@ -6930,15 +6962,15 @@ 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_RTX, tmode, 
+      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);
+      result = convert_memory_address_addr_space (tmode, result, as);
+      tmp = convert_memory_address_addr_space (tmode, tmp, as);
 
       if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
-       result = gen_rtx_PLUS (tmode, result, tmp);
+       result = simplify_gen_binary (PLUS, tmode, result, tmp);
       else
        {
          subtarget = bitpos ? NULL_RTX : target;
@@ -6968,6 +7000,9 @@ static rtx
 expand_expr_addr_expr (tree exp, rtx target, enum machine_mode tmode,
                       enum expand_modifier modifier)
 {
+  addr_space_t as = ADDR_SPACE_GENERIC;
+  enum machine_mode address_mode = Pmode;
+  enum machine_mode pointer_mode = ptr_mode;
   enum machine_mode rmode;
   rtx result;
 
@@ -6975,14 +7010,21 @@ expand_expr_addr_expr (tree exp, rtx target, enum machine_mode tmode,
   if (tmode == VOIDmode)
     tmode = TYPE_MODE (TREE_TYPE (exp));
 
+  if (POINTER_TYPE_P (TREE_TYPE (exp)))
+    {
+      as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp)));
+      address_mode = targetm.addr_space.address_mode (as);
+      pointer_mode = targetm.addr_space.pointer_mode (as);
+    }
+
   /* We can get called with some Weird Things if the user does silliness
      like "(short) &a".  In that case, convert_memory_address won't do
      the right thing, so ignore the given target mode.  */
-  if (tmode != Pmode && tmode != ptr_mode)
-    tmode = Pmode;
+  if (tmode != address_mode && tmode != pointer_mode)
+    tmode = address_mode;
 
   result = expand_expr_addr_expr_1 (TREE_OPERAND (exp, 0), target,
-                                   tmode, modifier);
+                                   tmode, modifier, as);
 
   /* Despite expand_expr claims concerning ignoring TMODE when not
      strictly convenient, stuff breaks if we don't honor it.  Note
@@ -6991,7 +7033,7 @@ expand_expr_addr_expr (tree exp, rtx target, enum machine_mode tmode,
   if (rmode == VOIDmode)
     rmode = tmode;
   if (rmode != tmode)
-    result = convert_memory_address (tmode, result);
+    result = convert_memory_address_addr_space (tmode, result, as);
 
   return result;
 }
@@ -7128,15 +7170,11 @@ expand_constructor (tree exp, rtx target, enum expand_modifier modifier,
    COMPOUND_EXPR whose second argument is such a VAR_DECL, and so on
    recursively.  */
 
-static rtx expand_expr_real_1 (tree, rtx, enum machine_mode,
-                              enum expand_modifier, rtx *);
-
 rtx
 expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
                  enum expand_modifier modifier, rtx *alt_rtl)
 {
-  int rn = -1;
-  rtx ret, last = NULL;
+  rtx ret;
 
   /* Handle ERROR_MARK before anybody tries to access its type.  */
   if (TREE_CODE (exp) == ERROR_MARK
@@ -7146,15 +7184,6 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
       return ret ? ret : const0_rtx;
     }
 
-  if (flag_non_call_exceptions)
-    {
-      rn = lookup_expr_eh_region (exp);
-
-      /* If rn < 0, then either (1) tree-ssa not used or (2) doesn't throw.  */
-      if (rn >= 0)
-       last = get_last_insn ();
-    }
-
   /* If this is an expression of some kind and it has an associated line
      number, then emit the line number before expanding the expression.
 
@@ -7166,6 +7195,8 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
   if (cfun && EXPR_HAS_LOCATION (exp))
     {
       location_t saved_location = input_location;
+      location_t saved_curr_loc = get_curr_insn_source_location ();
+      tree saved_block = get_curr_insn_block ();
       input_location = EXPR_LOCATION (exp);
       set_curr_insn_source_location (input_location);
 
@@ -7175,1942 +7206,2303 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
       ret = expand_expr_real_1 (exp, target, tmode, modifier, alt_rtl);
 
       input_location = saved_location;
+      set_curr_insn_block (saved_block);
+      set_curr_insn_source_location (saved_curr_loc);
     }
   else
     {
       ret = expand_expr_real_1 (exp, target, tmode, modifier, alt_rtl);
     }
 
-  /* If using non-call exceptions, mark all insns that may trap.
-     expand_call() will mark CALL_INSNs before we get to this code,
-     but it doesn't handle libcalls, and these may trap.  */
-  if (rn >= 0)
-    {
-      rtx insn;
-      for (insn = next_real_insn (last); insn;
-          insn = next_real_insn (insn))
-       {
-         if (! find_reg_note (insn, REG_EH_REGION, NULL_RTX)
-             /* If we want exceptions for non-call insns, any
-                may_trap_p instruction may throw.  */
-             && GET_CODE (PATTERN (insn)) != CLOBBER
-             && GET_CODE (PATTERN (insn)) != USE
-             && (CALL_P (insn) || may_trap_p (PATTERN (insn))))
-           add_reg_note (insn, REG_EH_REGION, GEN_INT (rn));
-       }
-    }
-
   return ret;
 }
 
-static rtx
-expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
-                   enum expand_modifier modifier, rtx *alt_rtl)
+rtx
+expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
+                   enum expand_modifier modifier)
 {
-  rtx op0, op1, op2, temp, decl_rtl;
+  rtx op0, op1, op2, temp;
   tree type;
   int unsignedp;
   enum machine_mode mode;
-  enum tree_code code = TREE_CODE (exp);
+  enum tree_code code = ops->code;
   optab this_optab;
   rtx subtarget, original_target;
   int ignore;
-  tree context, subexp0, subexp1;
   bool reduce_bit_field;
-  gimple subexp0_def, subexp1_def;
-  tree top0, top1;
-  location_t loc = EXPR_LOCATION (exp);
+  location_t loc = ops->location;
+  tree treeop0, treeop1, treeop2;
 #define REDUCE_BIT_FIELD(expr) (reduce_bit_field                         \
                                 ? reduce_to_bit_field_precision ((expr), \
                                                                  target, \
                                                                  type)   \
                                 : (expr))
 
-  type = TREE_TYPE (exp);
+  type = ops->type;
   mode = TYPE_MODE (type);
   unsignedp = TYPE_UNSIGNED (type);
 
+  treeop0 = ops->op0;
+  treeop1 = ops->op1;
+  treeop2 = ops->op2;
+
+  /* We should be called only on simple (binary or unary) expressions,
+     exactly those that are valid in gimple expressions that aren't
+     GIMPLE_SINGLE_RHS (or invalid).  */
+  gcc_assert (get_gimple_rhs_class (code) == GIMPLE_UNARY_RHS
+             || get_gimple_rhs_class (code) == GIMPLE_BINARY_RHS
+             || get_gimple_rhs_class (code) == GIMPLE_TERNARY_RHS);
+
   ignore = (target == const0_rtx
            || ((CONVERT_EXPR_CODE_P (code)
                 || code == COND_EXPR || code == VIEW_CONVERT_EXPR)
                && TREE_CODE (type) == VOID_TYPE));
 
+  /* We should be called only if we need the result.  */
+  gcc_assert (!ignore);
+
   /* 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
+  reduce_bit_field = (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
-     not call expand_expr with anything but const0_rtx in case this
-     is an initial expansion of a size that contains a PLACEHOLDER_EXPR.  */
+  if (reduce_bit_field && modifier == EXPAND_STACK_PARM)
+    target = 0;
 
-  if (ignore)
-    {
-      if (! TREE_SIDE_EFFECTS (exp))
-       return const0_rtx;
-
-      /* Ensure we reference a volatile object even if value is ignored, but
-        don't do this if all we are doing is taking its address.  */
-      if (TREE_THIS_VOLATILE (exp)
-         && TREE_CODE (exp) != FUNCTION_DECL
-         && mode != VOIDmode && mode != BLKmode
-         && modifier != EXPAND_CONST_ADDRESS)
-       {
-         temp = expand_expr (exp, NULL_RTX, VOIDmode, modifier);
-         if (MEM_P (temp))
-           temp = copy_to_reg (temp);
-         return const0_rtx;
-       }
-
-      if (TREE_CODE_CLASS (code) == tcc_unary
-         || code == COMPONENT_REF || code == INDIRECT_REF)
-       return expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
-                           modifier);
-
-      else if (TREE_CODE_CLASS (code) == tcc_binary
-              || TREE_CODE_CLASS (code) == tcc_comparison
-              || code == ARRAY_REF || code == ARRAY_RANGE_REF)
-       {
-         expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, modifier);
-         expand_expr (TREE_OPERAND (exp, 1), const0_rtx, VOIDmode, modifier);
-         return const0_rtx;
-       }
-      else if (code == BIT_FIELD_REF)
-       {
-         expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, modifier);
-         expand_expr (TREE_OPERAND (exp, 1), const0_rtx, VOIDmode, modifier);
-         expand_expr (TREE_OPERAND (exp, 2), const0_rtx, VOIDmode, modifier);
-         return const0_rtx;
-       }
-
-      target = 0;
-    }
-
-  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;
+  /* Use subtarget as the target for operand 0 of a binary operation.  */
+  subtarget = get_subtarget (target);
+  original_target = target;
 
   switch (code)
     {
-    case LABEL_DECL:
-      {
-       tree function = decl_function_context (exp);
-
-       temp = label_rtx (exp);
-       temp = gen_rtx_LABEL_REF (Pmode, temp);
+    case NON_LVALUE_EXPR:
+    case PAREN_EXPR:
+    CASE_CONVERT:
+      if (treeop0 == error_mark_node)
+       return const0_rtx;
 
-       if (function != current_function_decl
-           && function != 0)
-         LABEL_REF_NONLOCAL_P (temp) = 1;
+      if (TREE_CODE (type) == UNION_TYPE)
+       {
+         tree valtype = TREE_TYPE (treeop0);
 
-       temp = gen_rtx_MEM (FUNCTION_MODE, temp);
-       return temp;
-      }
+         /* If both input and output are BLKmode, this conversion isn't doing
+            anything except possibly changing memory attribute.  */
+         if (mode == BLKmode && TYPE_MODE (valtype) == BLKmode)
+           {
+             rtx result = expand_expr (treeop0, target, tmode,
+                                       modifier);
 
-    case SSA_NAME:
-      /* ??? ivopts calls expander, without any preparation from
-         out-of-ssa.  So fake instructions as if this was an access to the
-        base variable.  This unnecessarily allocates a pseudo, see how we can
-        reuse it, if partition base vars have it set already.  */
-      if (!currently_expanding_to_rtl)
-       return expand_expr_real_1 (SSA_NAME_VAR (exp), target, tmode, modifier, NULL);
-      {
-       gimple g = get_gimple_for_ssa_name (exp);
-       if (g)
-         return expand_expr_real_1 (gimple_assign_rhs_to_tree (g), target,
-                                    tmode, modifier, NULL);
-      }
-      decl_rtl = get_rtx_for_ssa_name (exp);
-      exp = SSA_NAME_VAR (exp);
-      goto expand_decl_rtl;
+             result = copy_rtx (result);
+             set_mem_attributes (result, type, 0);
+             return result;
+           }
 
-    case PARM_DECL:
-    case VAR_DECL:
-      /* If a static var's type was incomplete when the decl was written,
-        but the type is complete now, lay out the decl now.  */
-      if (DECL_SIZE (exp) == 0
-         && COMPLETE_OR_UNBOUND_ARRAY_TYPE_P (TREE_TYPE (exp))
-         && (TREE_STATIC (exp) || DECL_EXTERNAL (exp)))
-       layout_decl (exp, 0);
+         if (target == 0)
+           {
+             if (TYPE_MODE (type) != BLKmode)
+               target = gen_reg_rtx (TYPE_MODE (type));
+             else
+               target = assign_temp (type, 0, 1, 1);
+           }
 
-      /* 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_loc (loc, emutls_var_address (exp));
-         return expand_expr_real_1 (exp, target, tmode, modifier, NULL);
-       }
+         if (MEM_P (target))
+           /* Store data into beginning of memory target.  */
+           store_expr (treeop0,
+                       adjust_address (target, TYPE_MODE (valtype), 0),
+                       modifier == EXPAND_STACK_PARM,
+                       false);
 
-      /* ... fall through ...  */
+         else
+           {
+             gcc_assert (REG_P (target));
 
-    case FUNCTION_DECL:
-    case RESULT_DECL:
-      decl_rtl = DECL_RTL (exp);
-    expand_decl_rtl:
-      gcc_assert (decl_rtl);
-      decl_rtl = copy_rtx (decl_rtl);
+             /* Store this field into a union of the proper type.  */
+             store_field (target,
+                          MIN ((int_size_in_bytes (TREE_TYPE
+                                                   (treeop0))
+                                * BITS_PER_UNIT),
+                               (HOST_WIDE_INT) GET_MODE_BITSIZE (mode)),
+                          0, TYPE_MODE (valtype), treeop0,
+                          type, 0, false);
+           }
 
-      /* 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
-        definition.  */
-      if (! TREE_USED (exp))
-       {
-         assemble_external (exp);
-         TREE_USED (exp) = 1;
+         /* Return the entire union.  */
+         return target;
        }
 
-      /* Show we haven't gotten RTL for this yet.  */
-      temp = 0;
-
-      /* Variables inherited from containing functions should have
-        been lowered by this point.  */
-      context = decl_function_context (exp);
-      gcc_assert (!context
-                 || context == current_function_decl
-                 || TREE_STATIC (exp)
-                 /* ??? C++ creates functions that are not TREE_STATIC.  */
-                 || TREE_CODE (exp) == FUNCTION_DECL);
+      if (mode == TYPE_MODE (TREE_TYPE (treeop0)))
+       {
+         op0 = expand_expr (treeop0, target, VOIDmode,
+                            modifier);
 
-      /* This is the case of an array whose size is to be determined
-        from its initializer, while the initializer is still being parsed.
-        See expand_decl.  */
+         /* If the signedness of the conversion differs and OP0 is
+            a promoted SUBREG, clear that indication since we now
+            have to do the proper extension.  */
+         if (TYPE_UNSIGNED (TREE_TYPE (treeop0)) != unsignedp
+             && GET_CODE (op0) == SUBREG)
+           SUBREG_PROMOTED_VAR_P (op0) = 0;
 
-      if (MEM_P (decl_rtl) && REG_P (XEXP (decl_rtl, 0)))
-       temp = validize_mem (decl_rtl);
+         return REDUCE_BIT_FIELD (op0);
+       }
 
-      /* If DECL_RTL is memory, we are in the normal case and the
-        address is not valid, get the address into a register.  */
+      op0 = expand_expr (treeop0, NULL_RTX, mode,
+                        modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier);
+      if (GET_MODE (op0) == mode)
+       ;
 
-      else if (MEM_P (decl_rtl) && modifier != EXPAND_INITIALIZER)
+      /* If OP0 is a constant, just convert it into the proper mode.  */
+      else if (CONSTANT_P (op0))
        {
-         if (alt_rtl)
-           *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)));
-       }
+         tree inner_type = TREE_TYPE (treeop0);
+         enum machine_mode inner_mode = GET_MODE (op0);
 
-      /* If we got something, return it.  But first, set the alignment
-        if the address is a register.  */
-      if (temp != 0)
-       {
-         if (MEM_P (temp) && REG_P (XEXP (temp, 0)))
-           mark_reg_pointer (XEXP (temp, 0), DECL_ALIGN (exp));
+         if (inner_mode == VOIDmode)
+           inner_mode = TYPE_MODE (inner_type);
 
-         return temp;
+         if (modifier == EXPAND_INITIALIZER)
+           op0 = simplify_gen_subreg (mode, op0, inner_mode,
+                                      subreg_lowpart_offset (mode,
+                                                             inner_mode));
+         else
+           op0=  convert_modes (mode, inner_mode, op0,
+                                TYPE_UNSIGNED (inner_type));
        }
 
-      /* If the mode of DECL_RTL does not match that of the decl, it
-        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.  */
+      else if (modifier == EXPAND_INITIALIZER)
+       op0 = gen_rtx_fmt_e (unsignedp ? ZERO_EXTEND : SIGN_EXTEND, mode, op0);
 
-      if (REG_P (decl_rtl)
-         && GET_MODE (decl_rtl) != DECL_MODE (exp))
+      else if (target == 0)
+       op0 = convert_to_mode (mode, op0,
+                              TYPE_UNSIGNED (TREE_TYPE
+                                             (treeop0)));
+      else
        {
-         enum machine_mode pmode;
+         convert_move (target, op0,
+                       TYPE_UNSIGNED (TREE_TYPE (treeop0)));
+         op0 = target;
+       }
 
-         /* Get the signedness used for this variable.  Ensure we get the
-            same mode we got when the variable was declared.  */
-         pmode = promote_decl_mode (exp, &unsignedp);
-         gcc_assert (GET_MODE (decl_rtl) == pmode);
+      return REDUCE_BIT_FIELD (op0);
 
-         temp = gen_lowpart_SUBREG (mode, decl_rtl);
-         SUBREG_PROMOTED_VAR_P (temp) = 1;
-         SUBREG_PROMOTED_UNSIGNED_SET (temp, unsignedp);
-         return temp;
-       }
+    case ADDR_SPACE_CONVERT_EXPR:
+      {
+       tree treeop0_type = TREE_TYPE (treeop0);
+       addr_space_t as_to;
+       addr_space_t as_from;
 
-      return decl_rtl;
+       gcc_assert (POINTER_TYPE_P (type));
+       gcc_assert (POINTER_TYPE_P (treeop0_type));
 
-    case INTEGER_CST:
-      temp = immed_double_const (TREE_INT_CST_LOW (exp),
-                                TREE_INT_CST_HIGH (exp), mode);
+       as_to = TYPE_ADDR_SPACE (TREE_TYPE (type));
+       as_from = TYPE_ADDR_SPACE (TREE_TYPE (treeop0_type));
 
-      return temp;
+        /* Conversions between pointers to the same address space should
+          have been implemented via CONVERT_EXPR / NOP_EXPR.  */
+       gcc_assert (as_to != as_from);
 
-    case VECTOR_CST:
-      {
-       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)
+        /* Ask target code to handle conversion between pointers
+          to overlapping address spaces.  */
+       if (targetm.addr_space.subset_p (as_to, as_from)
+           || targetm.addr_space.subset_p (as_from, as_to))
          {
-           tree type_for_mode = lang_hooks.types.type_for_mode (mode, 1);
-           if (type_for_mode)
-             tmp = fold_unary_loc (loc, VIEW_CONVERT_EXPR, type_for_mode, exp);
+           op0 = expand_expr (treeop0, NULL_RTX, VOIDmode, modifier);
+           op0 = targetm.addr_space.convert (op0, treeop0_type, type);
+           gcc_assert (op0);
+           return op0;
          }
-       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);
+       /* For disjoint address spaces, converting anything but
+          a null pointer invokes undefined behaviour.  We simply
+          always return a null pointer here.  */
+       return CONST0_RTX (mode);
+      }
 
-    case REAL_CST:
-      /* If optimized, generate immediate CONST_DOUBLE
-        which will be turned into memory by reload if necessary.
+    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.  */
+      /* Make sure to sign-extend the sizetype offset in a POINTER_PLUS_EXPR
+         if sizetype precision is smaller than pointer precision.  */
+      if (TYPE_PRECISION (sizetype) < TYPE_PRECISION (type))
+       treeop1 = fold_convert_loc (loc, type,
+                                   fold_convert_loc (loc, ssizetype,
+                                                     treeop1));
+    case PLUS_EXPR:
+      /* 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
+        reduction and doing it this way will produce better code if the
+        frame pointer or argument pointer is eliminated.
 
-        We used to force a register so that loop.c could see it.  But
-        this does not allow gen_* patterns to perform optimizations with
-        the constants.  It also produces two insns in cases like "x = 1.0;".
-        On most machines, floating-point constants are not permitted in
-        many insns, so we'd end up copying it to a register in any case.
+        fold-const.c will ensure that the constant is always in the inner
+        PLUS_EXPR, so the only case we need to do anything about is if
+        sp, ap, or fp is our second argument, in which case we must swap
+        the innermost first argument and our second argument.  */
 
-        Now, we do the copying in expand_binop, if appropriate.  */
-      return CONST_DOUBLE_FROM_REAL_VALUE (TREE_REAL_CST (exp),
-                                          TYPE_MODE (TREE_TYPE (exp)));
+      if (TREE_CODE (treeop0) == PLUS_EXPR
+         && TREE_CODE (TREE_OPERAND (treeop0, 1)) == INTEGER_CST
+         && TREE_CODE (treeop1) == VAR_DECL
+         && (DECL_RTL (treeop1) == frame_pointer_rtx
+             || DECL_RTL (treeop1) == stack_pointer_rtx
+             || DECL_RTL (treeop1) == arg_pointer_rtx))
+       {
+         tree t = treeop1;
 
-    case FIXED_CST:
-      return CONST_FIXED_FROM_FIXED_VALUE (TREE_FIXED_CST (exp),
-                                          TYPE_MODE (TREE_TYPE (exp)));
+         treeop1 = TREE_OPERAND (treeop0, 0);
+         TREE_OPERAND (treeop0, 0) = t;
+       }
 
-    case COMPLEX_CST:
-      /* Handle evaluating a complex constant in a CONCAT target.  */
-      if (original_target && GET_CODE (original_target) == CONCAT)
+      /* If the result is to be ptr_mode and we are adding an integer to
+        something, we might be forming a constant.  So try to use
+        plus_constant.  If it produces a sum and we can't accept it,
+        use force_operand.  This allows P = &ARR[const] to generate
+        efficient code on machines where a SYMBOL_REF is not a valid
+        address.
+
+        If this is an EXPAND_SUM call, always return the sum.  */
+      if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER
+         || (mode == ptr_mode && (unsignedp || ! flag_trapv)))
        {
-         enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
-         rtx rtarg, itarg;
+         if (modifier == EXPAND_STACK_PARM)
+           target = 0;
+         if (TREE_CODE (treeop0) == INTEGER_CST
+             && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+             && TREE_CONSTANT (treeop1))
+           {
+             rtx constant_part;
 
-         rtarg = XEXP (original_target, 0);
-         itarg = XEXP (original_target, 1);
+             op1 = expand_expr (treeop1, subtarget, VOIDmode,
+                                EXPAND_SUM);
+             /* Use immed_double_const to ensure that the constant is
+                truncated according to the mode of OP1, then sign extended
+                to a HOST_WIDE_INT.  Using the constant directly can result
+                in non-canonical RTL in a 64x32 cross compile.  */
+             constant_part
+               = immed_double_const (TREE_INT_CST_LOW (treeop0),
+                                     (HOST_WIDE_INT) 0,
+                                     TYPE_MODE (TREE_TYPE (treeop1)));
+             op1 = plus_constant (op1, INTVAL (constant_part));
+             if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
+               op1 = force_operand (op1, target);
+             return REDUCE_BIT_FIELD (op1);
+           }
 
-         /* Move the real and imaginary parts separately.  */
-         op0 = expand_expr (TREE_REALPART (exp), rtarg, mode, EXPAND_NORMAL);
-         op1 = expand_expr (TREE_IMAGPART (exp), itarg, mode, EXPAND_NORMAL);
+         else if (TREE_CODE (treeop1) == INTEGER_CST
+                  && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+                  && TREE_CONSTANT (treeop0))
+           {
+             rtx constant_part;
 
-         if (op0 != rtarg)
-           emit_move_insn (rtarg, op0);
-         if (op1 != itarg)
-           emit_move_insn (itarg, op1);
+             op0 = expand_expr (treeop0, subtarget, VOIDmode,
+                                (modifier == EXPAND_INITIALIZER
+                                ? EXPAND_INITIALIZER : EXPAND_SUM));
+             if (! CONSTANT_P (op0))
+               {
+                 op1 = expand_expr (treeop1, NULL_RTX,
+                                    VOIDmode, modifier);
+                 /* Return a PLUS if modifier says it's OK.  */
+                 if (modifier == EXPAND_SUM
+                     || modifier == EXPAND_INITIALIZER)
+                   return simplify_gen_binary (PLUS, mode, op0, op1);
+                 goto binop2;
+               }
+             /* Use immed_double_const to ensure that the constant is
+                truncated according to the mode of OP1, then sign extended
+                to a HOST_WIDE_INT.  Using the constant directly can result
+                in non-canonical RTL in a 64x32 cross compile.  */
+             constant_part
+               = immed_double_const (TREE_INT_CST_LOW (treeop1),
+                                     (HOST_WIDE_INT) 0,
+                                     TYPE_MODE (TREE_TYPE (treeop0)));
+             op0 = plus_constant (op0, INTVAL (constant_part));
+             if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
+               op0 = force_operand (op0, target);
+             return REDUCE_BIT_FIELD (op0);
+           }
+       }
 
-         return original_target;
+      /* Use TER to expand pointer addition of a negated value
+        as pointer subtraction.  */
+      if ((POINTER_TYPE_P (TREE_TYPE (treeop0))
+          || (TREE_CODE (TREE_TYPE (treeop0)) == VECTOR_TYPE
+              && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (treeop0)))))
+         && TREE_CODE (treeop1) == SSA_NAME
+         && TYPE_MODE (TREE_TYPE (treeop0))
+            == TYPE_MODE (TREE_TYPE (treeop1)))
+       {
+         gimple def = get_def_for_expr (treeop1, NEGATE_EXPR);
+         if (def)
+           {
+             treeop1 = gimple_assign_rhs1 (def);
+             code = MINUS_EXPR;
+             goto do_minus;
+           }
        }
 
-      /* ... fall through ...  */
+      /* No sense saving up arithmetic to be done
+        if it's all in the wrong mode to form part of an address.
+        And force_operand won't know whether to sign-extend or
+        zero-extend.  */
+      if ((modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
+         || mode != ptr_mode)
+       {
+         expand_operands (treeop0, treeop1,
+                          subtarget, &op0, &op1, EXPAND_NORMAL);
+         if (op0 == const0_rtx)
+           return op1;
+         if (op1 == const0_rtx)
+           return op0;
+         goto binop2;
+       }
 
-    case STRING_CST:
-      temp = expand_expr_constant (exp, 1, modifier);
+      expand_operands (treeop0, treeop1,
+                      subtarget, &op0, &op1, modifier);
+      return REDUCE_BIT_FIELD (simplify_gen_binary (PLUS, mode, op0, op1));
 
-      /* temp contains a constant address.
-        On RISC machines where a constant address isn't valid,
-        make some insns to get that address into a register.  */
-      if (modifier != EXPAND_CONST_ADDRESS
-         && modifier != EXPAND_INITIALIZER
-         && modifier != EXPAND_SUM
-         && ! memory_address_p (mode, XEXP (temp, 0)))
-       return replace_equiv_address (temp,
-                                     copy_rtx (XEXP (temp, 0)));
-      return temp;
+    case MINUS_EXPR:
+    do_minus:
+      /* For initializers, we are allowed to return a MINUS of two
+        symbolic constants.  Here we handle all cases when both operands
+        are constant.  */
+      /* Handle difference of two symbolic constants,
+        for the sake of an initializer.  */
+      if ((modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
+         && really_constant_p (treeop0)
+         && really_constant_p (treeop1))
+       {
+         expand_operands (treeop0, treeop1,
+                          NULL_RTX, &op0, &op1, modifier);
 
-    case SAVE_EXPR:
-      {
-       tree val = TREE_OPERAND (exp, 0);
-       rtx ret = expand_expr_real_1 (val, target, tmode, modifier, alt_rtl);
+         /* If the last operand is a CONST_INT, use plus_constant of
+            the negated constant.  Else make the MINUS.  */
+         if (CONST_INT_P (op1))
+           return REDUCE_BIT_FIELD (plus_constant (op0, - INTVAL (op1)));
+         else
+           return REDUCE_BIT_FIELD (gen_rtx_MINUS (mode, op0, op1));
+       }
 
-       if (!SAVE_EXPR_RESOLVED_P (exp))
-         {
-           /* We can indeed still hit this case, typically via builtin
-              expanders calling save_expr immediately before expanding
-              something.  Assume this means that we only have to deal
-              with non-BLKmode values.  */
-           gcc_assert (GET_MODE (ret) != BLKmode);
+      /* No sense saving up arithmetic to be done
+        if it's all in the wrong mode to form part of an address.
+        And force_operand won't know whether to sign-extend or
+        zero-extend.  */
+      if ((modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
+         || mode != ptr_mode)
+       goto binop;
 
-           val = build_decl (EXPR_LOCATION (exp),
-                             VAR_DECL, NULL, TREE_TYPE (exp));
-           DECL_ARTIFICIAL (val) = 1;
-           DECL_IGNORED_P (val) = 1;
-           TREE_OPERAND (exp, 0) = val;
-           SAVE_EXPR_RESOLVED_P (exp) = 1;
+      expand_operands (treeop0, treeop1,
+                      subtarget, &op0, &op1, modifier);
 
-           if (!CONSTANT_P (ret))
-             ret = copy_to_reg (ret);
-           SET_DECL_RTL (val, ret);
-         }
+      /* Convert A - const to A + (-const).  */
+      if (CONST_INT_P (op1))
+       {
+         op1 = negate_rtx (mode, op1);
+         return REDUCE_BIT_FIELD (simplify_gen_binary (PLUS, mode, op0, op1));
+       }
 
-        return ret;
-      }
+      goto binop2;
 
-    case GOTO_EXPR:
-      if (TREE_CODE (TREE_OPERAND (exp, 0)) == LABEL_DECL)
-       expand_goto (TREE_OPERAND (exp, 0));
-      else
-       expand_computed_goto (TREE_OPERAND (exp, 0));
-      return const0_rtx;
+    case WIDEN_MULT_PLUS_EXPR:
+    case WIDEN_MULT_MINUS_EXPR:
+      expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+      op2 = expand_normal (treeop2);
+      target = expand_widen_pattern_expr (ops, op0, op1, op2,
+                                         target, unsignedp);
+      return target;
 
-    case CONSTRUCTOR:
-      /* If we don't need the result, just ensure we evaluate any
-        subexpressions.  */
-      if (ignore)
+    case WIDEN_MULT_EXPR:
+      /* If first operand is constant, swap them.
+        Thus the following special case checks need only
+        check the second operand.  */
+      if (TREE_CODE (treeop0) == INTEGER_CST)
        {
-         unsigned HOST_WIDE_INT idx;
-         tree value;
-
-         FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value)
-           expand_expr (value, const0_rtx, VOIDmode, EXPAND_NORMAL);
+         tree t1 = treeop0;
+         treeop0 = treeop1;
+         treeop1 = t1;
+       }
 
-         return const0_rtx;
+      /* First, check if we have a multiplication of one signed and one
+        unsigned operand.  */
+      if (TREE_CODE (treeop1) != INTEGER_CST
+         && (TYPE_UNSIGNED (TREE_TYPE (treeop0))
+             != TYPE_UNSIGNED (TREE_TYPE (treeop1))))
+       {
+         enum machine_mode innermode = TYPE_MODE (TREE_TYPE (treeop0));
+         this_optab = usmul_widen_optab;
+         if (mode == GET_MODE_2XWIDER_MODE (innermode))
+           {
+             if (optab_handler (this_optab, mode) != CODE_FOR_nothing)
+               {
+                 if (TYPE_UNSIGNED (TREE_TYPE (treeop0)))
+                   expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1,
+                                    EXPAND_NORMAL);
+                 else
+                   expand_operands (treeop0, treeop1, NULL_RTX, &op1, &op0,
+                                    EXPAND_NORMAL);
+                 goto binop3;
+               }
+           }
        }
+      /* Check for a multiplication with matching signedness.  */
+      else if ((TREE_CODE (treeop1) == INTEGER_CST
+               && int_fits_type_p (treeop1, TREE_TYPE (treeop0)))
+              || (TYPE_UNSIGNED (TREE_TYPE (treeop1))
+                  == TYPE_UNSIGNED (TREE_TYPE (treeop0))))
+       {
+         tree op0type = TREE_TYPE (treeop0);
+         enum machine_mode innermode = TYPE_MODE (op0type);
+         bool zextend_p = TYPE_UNSIGNED (op0type);
+         optab other_optab = zextend_p ? smul_widen_optab : umul_widen_optab;
+         this_optab = zextend_p ? umul_widen_optab : smul_widen_optab;
 
-      return expand_constructor (exp, target, modifier, false);
+         if (mode == GET_MODE_2XWIDER_MODE (innermode)
+             && TREE_CODE (treeop0) != INTEGER_CST)
+           {
+             if (optab_handler (this_optab, mode) != CODE_FOR_nothing)
+               {
+                 expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1,
+                                  EXPAND_NORMAL);
+                 temp = expand_widening_mult (mode, op0, op1, target,
+                                              unsignedp, this_optab);
+                 return REDUCE_BIT_FIELD (temp);
+               }
+             if (optab_handler (other_optab, mode) != CODE_FOR_nothing
+                 && innermode == word_mode)
+               {
+                 rtx htem, hipart;
+                 op0 = expand_normal (treeop0);
+                 if (TREE_CODE (treeop1) == INTEGER_CST)
+                   op1 = convert_modes (innermode, mode,
+                                        expand_normal (treeop1), unsignedp);
+                 else
+                   op1 = expand_normal (treeop1);
+                 temp = expand_binop (mode, other_optab, op0, op1, target,
+                                      unsignedp, OPTAB_LIB_WIDEN);
+                 hipart = gen_highpart (innermode, temp);
+                 htem = expand_mult_highpart_adjust (innermode, hipart,
+                                                     op0, op1, hipart,
+                                                     zextend_p);
+                 if (htem != hipart)
+                   emit_move_insn (hipart, htem);
+                 return REDUCE_BIT_FIELD (temp);
+               }
+           }
+       }
+      treeop0 = fold_build1 (CONVERT_EXPR, type, treeop0);
+      treeop1 = fold_build1 (CONVERT_EXPR, type, treeop1);
+      expand_operands (treeop0, treeop1, subtarget, &op0, &op1, EXPAND_NORMAL);
+      return REDUCE_BIT_FIELD (expand_mult (mode, op0, op1, target, unsignedp));
 
-    case MISALIGNED_INDIRECT_REF:
-    case ALIGN_INDIRECT_REF:
-    case INDIRECT_REF:
+    case FMA_EXPR:
       {
-       tree exp1 = TREE_OPERAND (exp, 0);
+       optab opt = fma_optab;
+       gimple def0, def2;
 
-       if (modifier != EXPAND_WRITE)
+       /* If there is no insn for FMA, emit it as __builtin_fma{,f,l}
+          call.  */
+       if (optab_handler (fma_optab, mode) == CODE_FOR_nothing)
          {
-           tree t;
+           tree fn = mathfn_built_in (TREE_TYPE (treeop0), BUILT_IN_FMA);
+           tree call_expr;
 
-           t = fold_read_from_constant_string (exp);
-           if (t)
-             return expand_expr (t, target, tmode, modifier);
+           gcc_assert (fn != NULL_TREE);
+           call_expr = build_call_expr (fn, 3, treeop0, treeop1, treeop2);
+           return expand_builtin (call_expr, target, subtarget, mode, false);
          }
 
-       op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM);
-       op0 = memory_address (mode, op0);
+       def0 = get_def_for_expr (treeop0, NEGATE_EXPR);
+       def2 = get_def_for_expr (treeop2, NEGATE_EXPR);
+
+       op0 = op2 = NULL;
 
-       if (code == ALIGN_INDIRECT_REF)
+       if (def0 && def2
+           && optab_handler (fnms_optab, mode) != CODE_FOR_nothing)
          {
-           int align = TYPE_ALIGN_UNIT (type);
-           op0 = gen_rtx_AND (Pmode, op0, GEN_INT (-align));
-           op0 = memory_address (mode, op0);
+           opt = fnms_optab;
+           op0 = expand_normal (gimple_assign_rhs1 (def0));
+           op2 = expand_normal (gimple_assign_rhs1 (def2));
          }
-
-       temp = gen_rtx_MEM (mode, op0);
-
-       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.  */
-       if (code == MISALIGNED_INDIRECT_REF)
+       else if (def0
+                && optab_handler (fnma_optab, mode) != CODE_FOR_nothing)
          {
-           int icode;
-           rtx reg, insn;
+           opt = fnma_optab;
+           op0 = expand_normal (gimple_assign_rhs1 (def0));
+         }
+       else if (def2
+                && optab_handler (fms_optab, mode) != CODE_FOR_nothing)
+         {
+           opt = fms_optab;
+           op2 = expand_normal (gimple_assign_rhs1 (def2));
+         }
 
-           gcc_assert (modifier == EXPAND_NORMAL
-                       || modifier == EXPAND_STACK_PARM);
+       if (op0 == NULL)
+         op0 = expand_expr (treeop0, subtarget, VOIDmode, EXPAND_NORMAL);
+       if (op2 == NULL)
+         op2 = expand_normal (treeop2);
+       op1 = expand_normal (treeop1);
 
-           /* The vectorizer should have already checked the mode.  */
-           icode = optab_handler (movmisalign_optab, mode)->insn_code;
-           gcc_assert (icode != CODE_FOR_nothing);
+       return expand_ternary_op (TYPE_MODE (type), opt,
+                                 op0, op1, op2, target, 0);
+      }
 
-           /* 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);
+    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;
 
-           /* Nor can the insn generator.  */
-           insn = GEN_FCN (icode) (reg, temp);
-           emit_insn (insn);
+      /* If first operand is constant, swap them.
+        Thus the following special case checks need only
+        check the second operand.  */
+      if (TREE_CODE (treeop0) == INTEGER_CST)
+       {
+         tree t1 = treeop0;
+         treeop0 = treeop1;
+         treeop1 = t1;
+       }
 
-           return reg;
-         }
+      /* Attempt to return something suitable for generating an
+        indexed address, for machines that support that.  */
 
-       return temp;
-      }
+      if (modifier == EXPAND_SUM && mode == ptr_mode
+         && host_integerp (treeop1, 0))
+       {
+         tree exp1 = treeop1;
 
-    case TARGET_MEM_REF:
-      {
-       struct mem_address addr;
+         op0 = expand_expr (treeop0, subtarget, VOIDmode,
+                            EXPAND_SUM);
 
-       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;
+         if (!REG_P (op0))
+           op0 = force_operand (op0, NULL_RTX);
+         if (!REG_P (op0))
+           op0 = copy_to_mode_reg (mode, op0);
 
-    case ARRAY_REF:
+         return REDUCE_BIT_FIELD (gen_rtx_MULT (mode, op0,
+                              gen_int_mode (tree_low_cst (exp1, 0),
+                                            TYPE_MODE (TREE_TYPE (exp1)))));
+       }
 
-      {
-       tree array = TREE_OPERAND (exp, 0);
-       tree index = TREE_OPERAND (exp, 1);
+      if (modifier == EXPAND_STACK_PARM)
+       target = 0;
 
-       /* Fold an expression like: "foo"[2].
-          This is not done in fold so it won't happen inside &.
-          Don't fold if this is for wide characters since it's too
-          difficult to do correctly and this is a very rare case.  */
+      expand_operands (treeop0, treeop1, subtarget, &op0, &op1, EXPAND_NORMAL);
+      return REDUCE_BIT_FIELD (expand_mult (mode, op0, op1, target, unsignedp));
 
-       if (modifier != EXPAND_CONST_ADDRESS
-           && modifier != EXPAND_INITIALIZER
-           && modifier != EXPAND_MEMORY)
-         {
-           tree t = fold_read_from_constant_string (exp);
+    case TRUNC_DIV_EXPR:
+    case FLOOR_DIV_EXPR:
+    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 (t)
-             return expand_expr (t, target, tmode, modifier);
-         }
+      if (modifier == EXPAND_STACK_PARM)
+       target = 0;
+      /* Possible optimization: compute the dividend with EXPAND_SUM
+        then if the divisor is constant can optimize the case
+        where some terms of the dividend have coeffs divisible by it.  */
+      expand_operands (treeop0, treeop1,
+                      subtarget, &op0, &op1, EXPAND_NORMAL);
+      return expand_divmod (0, code, mode, op0, op1, target, unsignedp);
 
-       /* If this is a constant index into a constant array,
-          just get the value from the array.  Handle both the cases when
-          we have an explicit constructor and when our operand is a variable
-          that was declared const.  */
+    case RDIV_EXPR:
+      goto binop;
 
-       if (modifier != EXPAND_CONST_ADDRESS
-           && modifier != EXPAND_INITIALIZER
-           && modifier != EXPAND_MEMORY
-           && TREE_CODE (array) == CONSTRUCTOR
-           && ! TREE_SIDE_EFFECTS (array)
-           && TREE_CODE (index) == INTEGER_CST)
-         {
-           unsigned HOST_WIDE_INT ix;
-           tree field, value;
+    case TRUNC_MOD_EXPR:
+    case FLOOR_MOD_EXPR:
+    case CEIL_MOD_EXPR:
+    case ROUND_MOD_EXPR:
+      if (modifier == EXPAND_STACK_PARM)
+       target = 0;
+      expand_operands (treeop0, treeop1,
+                      subtarget, &op0, &op1, EXPAND_NORMAL);
+      return expand_divmod (1, code, mode, op0, op1, target, unsignedp);
 
-           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;
-               }
-         }
+    case FIXED_CONVERT_EXPR:
+      op0 = expand_normal (treeop0);
+      if (target == 0 || modifier == EXPAND_STACK_PARM)
+       target = gen_reg_rtx (mode);
 
-       else if (optimize >= 1
-                && modifier != EXPAND_CONST_ADDRESS
-                && modifier != EXPAND_INITIALIZER
-                && modifier != EXPAND_MEMORY
-                && TREE_READONLY (array) && ! TREE_SIDE_EFFECTS (array)
-                && TREE_CODE (array) == VAR_DECL && DECL_INITIAL (array)
-                && TREE_CODE (DECL_INITIAL (array)) != ERROR_MARK
-                && targetm.binds_local_p (array))
-         {
-           if (TREE_CODE (index) == INTEGER_CST)
-             {
-               tree init = DECL_INITIAL (array);
+      if ((TREE_CODE (TREE_TYPE (treeop0)) == INTEGER_TYPE
+          && TYPE_UNSIGNED (TREE_TYPE (treeop0)))
+          || (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;
 
-               if (TREE_CODE (init) == CONSTRUCTOR)
-                 {
-                   unsigned HOST_WIDE_INT ix;
-                   tree field, value;
+    case FIX_TRUNC_EXPR:
+      op0 = expand_normal (treeop0);
+      if (target == 0 || modifier == EXPAND_STACK_PARM)
+       target = gen_reg_rtx (mode);
+      expand_fix (target, op0, unsignedp);
+      return target;
 
-                   FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), ix,
-                                             field, value)
-                     if (tree_int_cst_equal (field, index))
-                       {
-                         if (TREE_SIDE_EFFECTS (value))
-                           break;
+    case FLOAT_EXPR:
+      op0 = expand_normal (treeop0);
+      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.
+        So give it the correct mode.  With -O, cse will optimize this.  */
+      if (GET_MODE (op0) == VOIDmode)
+       op0 = copy_to_mode_reg (TYPE_MODE (TREE_TYPE (treeop0)),
+                               op0);
+      expand_float (target, op0,
+                   TYPE_UNSIGNED (TREE_TYPE (treeop0)));
+      return target;
 
-                         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;
-                           }
+    case NEGATE_EXPR:
+      op0 = expand_expr (treeop0, subtarget,
+                        VOIDmode, EXPAND_NORMAL);
+      if (modifier == EXPAND_STACK_PARM)
+       target = 0;
+      temp = expand_unop (mode,
+                         optab_for_tree_code (NEGATE_EXPR, type,
+                                              optab_default),
+                         op0, target, 0);
+      gcc_assert (temp);
+      return REDUCE_BIT_FIELD (temp);
 
-                         return expand_expr (fold (value), target, tmode,
-                                             modifier);
-                       }
-                 }
-               else if(TREE_CODE (init) == STRING_CST)
-                 {
-                   tree index1 = index;
-                   tree low_bound = array_ref_low_bound (exp);
-                   index1 = fold_convert_loc (loc, sizetype,
-                                              TREE_OPERAND (exp, 1));
+    case ABS_EXPR:
+      op0 = expand_expr (treeop0, subtarget,
+                        VOIDmode, EXPAND_NORMAL);
+      if (modifier == EXPAND_STACK_PARM)
+       target = 0;
 
-                   /* Optimize the special-case of a zero lower bound.
+      /* ABS_EXPR is not valid for complex arguments.  */
+      gcc_assert (GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
+                 && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT);
 
-                      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!)  */
+      /* Unsigned abs is simply the operand.  Testing here means we don't
+        risk generating incorrect code below.  */
+      if (TYPE_UNSIGNED (type))
+       return op0;
 
-                   if (! integer_zerop (low_bound))
-                     index1 = size_diffop_loc (loc, index1,
-                                           fold_convert_loc (loc, sizetype,
-                                                             low_bound));
+      return expand_abs (mode, op0, target, unsignedp,
+                        safe_from_p (target, treeop0, 1));
 
-                   if (0 > compare_tree_int (index1,
-                                             TREE_STRING_LENGTH (init)))
-                     {
-                       tree type = TREE_TYPE (TREE_TYPE (init));
-                       enum machine_mode mode = TYPE_MODE (type);
+    case MAX_EXPR:
+    case MIN_EXPR:
+      target = original_target;
+      if (target == 0
+         || modifier == EXPAND_STACK_PARM
+         || (MEM_P (target) && MEM_VOLATILE_P (target))
+         || GET_MODE (target) != mode
+         || (REG_P (target)
+             && REGNO (target) < FIRST_PSEUDO_REGISTER))
+       target = gen_reg_rtx (mode);
+      expand_operands (treeop0, treeop1,
+                      target, &op0, &op1, EXPAND_NORMAL);
 
-                       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);
-                     }
-                 }
-             }
-         }
-      }
-      goto normal_inner_ref;
+      /* 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, optab_default);
+      temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
+                          OPTAB_WIDEN);
+      if (temp != 0)
+       return temp;
 
-    case COMPONENT_REF:
-      /* If the operand is a CONSTRUCTOR, we can just extract the
-        appropriate field if it is present.  */
-      if (TREE_CODE (TREE_OPERAND (exp, 0)) == CONSTRUCTOR)
-       {
-         unsigned HOST_WIDE_INT idx;
-         tree field, value;
+      /* At this point, a MEM target is no longer useful; we will get better
+        code without it.  */
 
-         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,
-                  we must mask only the number of bits in the bitfield,
-                  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 (field)
-                   || ((GET_MODE_CLASS (DECL_MODE (field)) == MODE_INT)
-                       && (GET_MODE_BITSIZE (DECL_MODE (field))
-                           <= HOST_BITS_PER_WIDE_INT))))
-             {
-               if (DECL_BIT_FIELD (field)
-                   && modifier == EXPAND_STACK_PARM)
-                 target = 0;
-               op0 = expand_expr (value, target, tmode, modifier);
-               if (DECL_BIT_FIELD (field))
-                 {
-                   HOST_WIDE_INT bitsize = TREE_INT_CST_LOW (DECL_SIZE (field));
-                   enum machine_mode imode = TYPE_MODE (TREE_TYPE (field));
+      if (! REG_P (target))
+       target = gen_reg_rtx (mode);
 
-                   if (TYPE_UNSIGNED (TREE_TYPE (field)))
-                     {
-                       op1 = GEN_INT (((HOST_WIDE_INT) 1 << bitsize) - 1);
-                       op0 = expand_and (imode, op0, op1, target);
-                     }
-                   else
-                     {
-                       tree count
-                         = build_int_cst (NULL_TREE,
-                                          GET_MODE_BITSIZE (imode) - bitsize);
+      /* If op1 was placed in target, swap op0 and op1.  */
+      if (target != op0 && target == op1)
+       {
+         temp = op0;
+         op0 = op1;
+         op1 = temp;
+       }
 
-                       op0 = expand_shift (LSHIFT_EXPR, imode, op0, count,
-                                           target, 0);
-                       op0 = expand_shift (RSHIFT_EXPR, imode, op0, count,
-                                           target, 0);
-                     }
-                 }
-
-               return op0;
-             }
-       }
-      goto normal_inner_ref;
+      /* We generate better code and avoid problems with op1 mentioning
+        target by forcing op1 into a pseudo if it isn't a constant.  */
+      if (! CONSTANT_P (op1))
+       op1 = force_reg (mode, op1);
 
-    case BIT_FIELD_REF:
-    case ARRAY_RANGE_REF:
-    normal_inner_ref:
       {
-       enum machine_mode mode1, mode2;
-       HOST_WIDE_INT bitsize, bitpos;
-       tree offset;
-       int volatilep = 0, must_force_mem;
-       tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
-                                       &mode1, &unsignedp, &volatilep, true);
-       rtx orig_op0, memloc;
-
-       /* If we got back the original object, something is wrong.  Perhaps
-          we are evaluating an expression too early.  In any event, don't
-          infinitely recurse.  */
-       gcc_assert (tem != exp);
-
-       /* If TEM's type is a union of variable size, pass TARGET to the inner
-          computation, since it will need a temporary and TARGET is known
-          to have to do.  This occurs in unchecked conversion in Ada.  */
-       orig_op0 = op0
-         = expand_expr (tem,
-                        (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
-                         && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
-                             != INTEGER_CST)
-                         && modifier != EXPAND_STACK_PARM
-                         ? target : NULL_RTX),
-                        VOIDmode,
-                        (modifier == EXPAND_INITIALIZER
-                         || modifier == EXPAND_CONST_ADDRESS
-                         || modifier == EXPAND_STACK_PARM)
-                        ? modifier : EXPAND_NORMAL);
-
-       mode2
-         = CONSTANT_P (op0) ? TYPE_MODE (TREE_TYPE (tem)) : GET_MODE (op0);
-
-       /* If we have either an offset, a BLKmode result, or a reference
-          outside the underlying object, we must force it to memory.
-          Such a case can occur in Ada if we have unchecked conversion
-          of an expression from a scalar type to an aggregate type or
-          for an ARRAY_RANGE_REF whose type is BLKmode, or if we were
-          passed a partially uninitialized object or a view-conversion
-          to a larger size.  */
-       must_force_mem = (offset
-                         || mode1 == BLKmode
-                         || bitpos + bitsize > GET_MODE_BITSIZE (mode2));
-
-       /* If this is a constant, put it in a register if it is a legitimate
-          constant and we don't need a memory reference.  */
-       if (CONSTANT_P (op0)
-           && mode2 != BLKmode
-           && LEGITIMATE_CONSTANT_P (op0)
-           && !must_force_mem)
-         op0 = force_reg (mode2, op0);
+       enum rtx_code comparison_code;
+       rtx cmpop1 = op1;
 
-       /* Otherwise, if this is a constant, try to force it to the constant
-          pool.  Note that back-ends, e.g. MIPS, may refuse to do so if it
-          is a legitimate constant.  */
-       else if (CONSTANT_P (op0) && (memloc = force_const_mem (mode2, op0)))
-         op0 = validize_mem (memloc);
+       if (code == MAX_EXPR)
+         comparison_code = unsignedp ? GEU : GE;
+       else
+         comparison_code = unsignedp ? LEU : LE;
 
-       /* Otherwise, if this is a constant or the object is not in memory
-          and need be, put it there.  */
-       else if (CONSTANT_P (op0) || (!MEM_P (op0) && must_force_mem))
+       /* Canonicalize to comparisons against 0.  */
+       if (op1 == const1_rtx)
          {
-           tree nt = build_qualified_type (TREE_TYPE (tem),
-                                           (TYPE_QUALS (TREE_TYPE (tem))
-                                            | TYPE_QUAL_CONST));
-           memloc = assign_temp (nt, 1, 1, 1);
-           emit_move_insn (memloc, op0);
-           op0 = memloc;
+           /* 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 (offset)
+       if (op1 == constm1_rtx && !unsignedp)
          {
-           rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode,
-                                         EXPAND_SUM);
+           /* 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;
 
-           gcc_assert (MEM_P (op0));
+           /* ??? 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 ();
 
-#ifdef POINTERS_EXTEND_UNSIGNED
-           if (GET_MODE (offset_rtx) != Pmode)
-             offset_rtx = convert_to_mode (Pmode, offset_rtx, 0);
-#else
-           if (GET_MODE (offset_rtx) != ptr_mode)
-             offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
-#endif
+           start_sequence ();
 
-           if (GET_MODE (op0) == BLKmode
-               /* A constant address in OP0 can have VOIDmode, we must
-                  not try to call force_reg in that case.  */
-               && GET_MODE (XEXP (op0, 0)) != VOIDmode
-               && bitsize != 0
-               && (bitpos % bitsize) == 0
-               && (bitsize % GET_MODE_ALIGNMENT (mode1)) == 0
-               && MEM_ALIGN (op0) == GET_MODE_ALIGNMENT (mode1))
+           /* 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)
              {
-               op0 = adjust_address (op0, mode1, bitpos / BITS_PER_UNIT);
-               bitpos = 0;
+               rtx seq = get_insns ();
+               end_sequence ();
+               emit_insn (seq);
+               return target;
              }
 
-           op0 = offset_address (op0, offset_rtx,
-                                 highest_pow2_factor (offset));
+           /* Otherwise discard the sequence and fall back to code with
+              branches.  */
+           end_sequence ();
          }
+#endif
+       if (target != op0)
+         emit_move_insn (target, op0);
 
-       /* If OFFSET is making OP0 more aligned than BIGGEST_ALIGNMENT,
-          record its alignment as BIGGEST_ALIGNMENT.  */
-       if (MEM_P (op0) && bitpos == 0 && offset != 0
-           && is_aligning_offset (offset, tem))
-         set_mem_align (op0, BIGGEST_ALIGNMENT);
+       temp = gen_label_rtx ();
+       do_compare_rtx_and_jump (target, cmpop1, comparison_code,
+                                unsignedp, mode, NULL_RTX, NULL_RTX, temp,
+                                -1);
+      }
+      emit_move_insn (target, op1);
+      emit_label (temp);
+      return target;
 
-       /* Don't forget about volatility even if this is a bitfield.  */
-       if (MEM_P (op0) && volatilep && ! MEM_VOLATILE_P (op0))
-         {
-           if (op0 == orig_op0)
-             op0 = copy_rtx (op0);
+    case BIT_NOT_EXPR:
+      op0 = expand_expr (treeop0, subtarget,
+                        VOIDmode, EXPAND_NORMAL);
+      if (modifier == EXPAND_STACK_PARM)
+       target = 0;
+      temp = expand_unop (mode, one_cmpl_optab, op0, target, 1);
+      gcc_assert (temp);
+      return temp;
 
-           MEM_VOLATILE_P (op0) = 1;
-         }
+      /* ??? Can optimize bitwise operations with one arg constant.
+        Can optimize (a bitwise1 n) bitwise2 (a bitwise3 b)
+        and (a bitwise1 b) bitwise2 b (etc)
+        but that is probably not worth while.  */
 
-       /* The following code doesn't handle CONCAT.
-          Assume only bitpos == 0 can be used for CONCAT, due to
-          one element arrays having the same mode as its element.  */
-       if (GET_CODE (op0) == CONCAT)
-         {
-           gcc_assert (bitpos == 0
-                       && bitsize == GET_MODE_BITSIZE (GET_MODE (op0)));
-           return op0;
-         }
+      /* BIT_AND_EXPR is for bitwise anding.  TRUTH_AND_EXPR is for anding two
+        boolean values when we want in all cases to compute both of them.  In
+        general it is fastest to do TRUTH_AND_EXPR by computing both operands
+        as actual zero-or-1 values and then bitwise anding.  In cases where
+        there cannot be any side effects, better code would be made by
+        treating TRUTH_AND_EXPR like TRUTH_ANDIF_EXPR; but the question is
+        how to recognize those cases.  */
 
-       /* In cases where an aligned union has an unaligned object
-          as a field, we might be extracting a BLKmode value from
-          an integer-mode (e.g., SImode) object.  Handle this case
-          by doing the extract into an object as wide as the field
-          (which we know to be the width of a basic mode), then
-          storing into memory, and changing the mode to BLKmode.  */
-       if (mode1 == VOIDmode
-           || REG_P (op0) || GET_CODE (op0) == SUBREG
-           || (mode1 != BLKmode && ! direct_load[(int) mode1]
-               && GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
-               && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT
-               && modifier != EXPAND_CONST_ADDRESS
-               && modifier != EXPAND_INITIALIZER)
-           /* If the field isn't aligned enough to fetch as a memref,
-              fetch it as a bit field.  */
-           || (mode1 != BLKmode
-               && (((TYPE_ALIGN (TREE_TYPE (tem)) < GET_MODE_ALIGNMENT (mode)
-                     || (bitpos % GET_MODE_ALIGNMENT (mode) != 0)
-                     || (MEM_P (op0)
-                         && (MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (mode1)
-                             || (bitpos % GET_MODE_ALIGNMENT (mode1) != 0))))
-                    && ((modifier == EXPAND_CONST_ADDRESS
-                         || modifier == EXPAND_INITIALIZER)
-                        ? STRICT_ALIGNMENT
-                        : SLOW_UNALIGNED_ACCESS (mode1, MEM_ALIGN (op0))))
-                   || (bitpos % BITS_PER_UNIT != 0)))
-           /* If the type and the field are a constant size and the
-              size of the type isn't the same size as the bitfield,
-              we must use bitfield operations.  */
-           || (bitsize >= 0
-               && TYPE_SIZE (TREE_TYPE (exp))
-               && TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) == INTEGER_CST
-               && 0 != compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)),
-                                         bitsize)))
-         {
-           enum machine_mode ext_mode = mode;
+    case TRUTH_AND_EXPR:
+      code = BIT_AND_EXPR;
+    case BIT_AND_EXPR:
+      goto binop;
 
-           if (ext_mode == BLKmode
-               && ! (target != 0 && MEM_P (op0)
-                     && MEM_P (target)
-                     && bitpos % BITS_PER_UNIT == 0))
-             ext_mode = mode_for_size (bitsize, MODE_INT, 1);
+    case TRUTH_OR_EXPR:
+      code = BIT_IOR_EXPR;
+    case BIT_IOR_EXPR:
+      goto binop;
 
-           if (ext_mode == BLKmode)
-             {
-               if (target == 0)
-                 target = assign_temp (type, 0, 1, 1);
+    case TRUTH_XOR_EXPR:
+      code = BIT_XOR_EXPR;
+    case BIT_XOR_EXPR:
+      goto binop;
 
-               if (bitsize == 0)
-                 return target;
+    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 */
 
-               /* In this case, BITPOS must start at a byte boundary and
-                  TARGET, if specified, must be a MEM.  */
-               gcc_assert (MEM_P (op0)
-                           && (!target || MEM_P (target))
-                           && !(bitpos % BITS_PER_UNIT));
+    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;
 
-               emit_block_move (target,
-                                adjust_address (op0, VOIDmode,
-                                                bitpos / BITS_PER_UNIT),
-                                GEN_INT ((bitsize + BITS_PER_UNIT - 1)
-                                         / BITS_PER_UNIT),
-                                (modifier == EXPAND_STACK_PARM
-                                 ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
+      if (! safe_from_p (subtarget, treeop1, 1))
+       subtarget = 0;
+      if (modifier == EXPAND_STACK_PARM)
+       target = 0;
+      op0 = expand_expr (treeop0, subtarget,
+                        VOIDmode, EXPAND_NORMAL);
+      temp = expand_variable_shift (code, mode, op0, treeop1, target,
+                                   unsignedp);
+      if (code == LSHIFT_EXPR)
+       temp = REDUCE_BIT_FIELD (temp);
+      return temp;
 
-               return target;
-             }
+      /* Could determine the answer when only additive constants differ.  Also,
+        the addition of one can be handled by changing the condition.  */
+    case LT_EXPR:
+    case LE_EXPR:
+    case GT_EXPR:
+    case GE_EXPR:
+    case EQ_EXPR:
+    case NE_EXPR:
+    case UNORDERED_EXPR:
+    case ORDERED_EXPR:
+    case UNLT_EXPR:
+    case UNLE_EXPR:
+    case UNGT_EXPR:
+    case UNGE_EXPR:
+    case UNEQ_EXPR:
+    case LTGT_EXPR:
+      temp = do_store_flag (ops,
+                           modifier != EXPAND_STACK_PARM ? target : NULL_RTX,
+                           tmode != VOIDmode ? tmode : mode);
+      if (temp)
+       return temp;
 
-           op0 = validize_mem (op0);
+      /* Use a compare and a jump for BLKmode comparisons, or for function
+        type comparisons is HAVE_canonicalize_funcptr_for_compare.  */
 
-           if (MEM_P (op0) && REG_P (XEXP (op0, 0)))
-             mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
+      if ((target == 0
+          || modifier == EXPAND_STACK_PARM
+          || ! safe_from_p (target, treeop0, 1)
+          || ! safe_from_p (target, treeop1, 1)
+          /* Make sure we don't have a hard reg (such as function's return
+             value) live across basic blocks, if not optimizing.  */
+          || (!optimize && REG_P (target)
+              && REGNO (target) < FIRST_PSEUDO_REGISTER)))
+       target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
 
-           op0 = extract_bit_field (op0, bitsize, bitpos, unsignedp,
-                                    (modifier == EXPAND_STACK_PARM
-                                     ? NULL_RTX : target),
-                                    ext_mode, ext_mode);
+      emit_move_insn (target, const0_rtx);
 
-           /* If the result is a record type and BITSIZE is narrower than
-              the mode of OP0, an integral mode, and this is a big endian
-              machine, we must put the field into the high-order bits.  */
-           if (TREE_CODE (type) == RECORD_TYPE && BYTES_BIG_ENDIAN
-               && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
-               && bitsize < (HOST_WIDE_INT) GET_MODE_BITSIZE (GET_MODE (op0)))
-             op0 = expand_shift (LSHIFT_EXPR, GET_MODE (op0), op0,
-                                 size_int (GET_MODE_BITSIZE (GET_MODE (op0))
-                                           - bitsize),
-                                 op0, 1);
+      op1 = gen_label_rtx ();
+      jumpifnot_1 (code, treeop0, treeop1, op1, -1);
 
-           /* If the result type is BLKmode, store the data into a temporary
-              of the appropriate type, but with the mode corresponding to the
-              mode for the data we have (op0's mode).  It's tempting to make
-              this a constant type, since we know it's only being stored once,
-              but that can cause problems if we are taking the address of this
-              COMPONENT_REF because the MEM of any reference via that address
-              will have flags corresponding to the type, which will not
-              necessarily be constant.  */
-           if (mode == BLKmode)
-             {
-               HOST_WIDE_INT size = GET_MODE_BITSIZE (ext_mode);
-               rtx new_rtx;
+      if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type))
+       emit_move_insn (target, constm1_rtx);
+      else
+       emit_move_insn (target, const1_rtx);
 
-               /* 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_rtx = assign_stack_local (ext_mode, size, 0);
-                   set_mem_alias_set (new_rtx, get_alias_set (exp));
-                 }
-               else
-                 new_rtx = assign_stack_temp_for_type (ext_mode, size, 0, type);
+      emit_label (op1);
+      return target;
 
-               emit_move_insn (new_rtx, op0);
-               op0 = copy_rtx (new_rtx);
-               PUT_MODE (op0, BLKmode);
-               set_mem_attributes (op0, exp, 1);
-             }
+    case TRUTH_NOT_EXPR:
+      if (modifier == EXPAND_STACK_PARM)
+       target = 0;
+      op0 = expand_expr (treeop0, target,
+                        VOIDmode, EXPAND_NORMAL);
+      /* The parser is careful to generate TRUTH_NOT_EXPR
+        only with operands that are always zero or one.  */
+      temp = expand_binop (mode, xor_optab, op0, const1_rtx,
+                          target, 1, OPTAB_LIB_WIDEN);
+      gcc_assert (temp);
+      return temp;
 
-           return op0;
-         }
+    case COMPLEX_EXPR:
+      /* Get the rtx code of the operands.  */
+      op0 = expand_normal (treeop0);
+      op1 = expand_normal (treeop1);
 
-       /* If the result is BLKmode, use that to access the object
-          now as well.  */
-       if (mode == BLKmode)
-         mode1 = BLKmode;
+      if (!target)
+       target = gen_reg_rtx (TYPE_MODE (type));
 
-       /* Get a reference to just this component.  */
-       if (modifier == EXPAND_CONST_ADDRESS
-           || modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
-         op0 = adjust_address_nv (op0, mode1, bitpos / BITS_PER_UNIT);
-       else
-         op0 = adjust_address (op0, mode1, bitpos / BITS_PER_UNIT);
+      /* Move the real (op0) and imaginary (op1) parts to their location.  */
+      write_complex_part (target, op0, false);
+      write_complex_part (target, op1, true);
 
-       if (op0 == orig_op0)
-         op0 = copy_rtx (op0);
+      return target;
 
-       set_mem_attributes (op0, exp, 0);
-       if (REG_P (XEXP (op0, 0)))
-         mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
+    case WIDEN_SUM_EXPR:
+      {
+        tree oprnd0 = treeop0;
+        tree oprnd1 = treeop1;
 
-       MEM_VOLATILE_P (op0) |= volatilep;
-       if (mode == mode1 || mode1 == BLKmode || mode1 == tmode
-           || modifier == EXPAND_CONST_ADDRESS
-           || modifier == EXPAND_INITIALIZER)
-         return op0;
-       else if (target == 0)
-         target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
+        expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+        target = expand_widen_pattern_expr (ops, op0, NULL_RTX, op1,
+                                            target, unsignedp);
+        return target;
+      }
 
-       convert_move (target, op0, unsignedp);
-       return target;
+    case REDUC_MAX_EXPR:
+    case REDUC_MIN_EXPR:
+    case REDUC_PLUS_EXPR:
+      {
+        op0 = expand_normal (treeop0);
+        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 OBJ_TYPE_REF:
-      return expand_expr (OBJ_TYPE_REF_EXPR (exp), target, tmode, modifier);
+    case VEC_EXTRACT_EVEN_EXPR:
+    case VEC_EXTRACT_ODD_EXPR:
+      {
+        expand_operands (treeop0,  treeop1,
+                         NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+        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 CALL_EXPR:
-      /* 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);
+    case VEC_INTERLEAVE_HIGH_EXPR:
+    case VEC_INTERLEAVE_LOW_EXPR:
       {
-       tree fndecl = get_callee_fndecl (exp), attr;
+        expand_operands (treeop0,  treeop1,
+                         NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+        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;
+      }
 
-       if (fndecl
-           && (attr = lookup_attribute ("error",
-                                        DECL_ATTRIBUTES (fndecl))) != NULL)
-         error ("%Kcall to %qs declared with attribute error: %s",
-                exp, identifier_to_locale (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_at (tree_nonartificial_location (exp),
-                     0, "%Kcall to %qs declared with attribute warning: %s",
-                     exp, identifier_to_locale (lang_hooks.decl_printable_name (fndecl, 1)),
-                     TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr))));
+    case VEC_LSHIFT_EXPR:
+    case VEC_RSHIFT_EXPR:
+      {
+       target = expand_vec_shift_expr (ops, target);
+       return target;
+      }
 
-       /* Check for a built-in function.  */
-       if (fndecl && DECL_BUILT_IN (fndecl))
-         {
-           gcc_assert (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_FRONTEND);
-           return expand_builtin (exp, target, subtarget, tmode, ignore);
-         }
+    case VEC_UNPACK_HI_EXPR:
+    case VEC_UNPACK_LO_EXPR:
+      {
+       op0 = expand_normal (treeop0);
+       temp = expand_widen_pattern_expr (ops, op0, NULL_RTX, NULL_RTX,
+                                         target, unsignedp);
+       gcc_assert (temp);
+       return temp;
       }
-      return expand_call (exp, target, ignore);
 
-    case PAREN_EXPR:
-    CASE_CONVERT:
-      if (TREE_OPERAND (exp, 0) == error_mark_node)
-       return const0_rtx;
+    case VEC_UNPACK_FLOAT_HI_EXPR:
+    case VEC_UNPACK_FLOAT_LO_EXPR:
+      {
+       op0 = expand_normal (treeop0);
+       /* The signedness is determined from input operand.  */
+       temp = expand_widen_pattern_expr
+         (ops, op0, NULL_RTX, NULL_RTX,
+          target, TYPE_UNSIGNED (TREE_TYPE (treeop0)));
 
-      if (TREE_CODE (type) == UNION_TYPE)
-       {
-         tree valtype = TREE_TYPE (TREE_OPERAND (exp, 0));
+       gcc_assert (temp);
+       return temp;
+      }
 
-         /* If both input and output are BLKmode, this conversion isn't doing
-            anything except possibly changing memory attribute.  */
-         if (mode == BLKmode && TYPE_MODE (valtype) == BLKmode)
-           {
-             rtx result = expand_expr (TREE_OPERAND (exp, 0), target, tmode,
-                                       modifier);
+    case VEC_WIDEN_MULT_HI_EXPR:
+    case VEC_WIDEN_MULT_LO_EXPR:
+      {
+       tree oprnd0 = treeop0;
+       tree oprnd1 = treeop1;
 
-             result = copy_rtx (result);
-             set_mem_attributes (result, exp, 0);
-             return result;
-           }
+       expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+       target = expand_widen_pattern_expr (ops, op0, op1, NULL_RTX,
+                                           target, unsignedp);
+       gcc_assert (target);
+       return target;
+      }
 
-         if (target == 0)
-           {
-             if (TYPE_MODE (type) != BLKmode)
-               target = gen_reg_rtx (TYPE_MODE (type));
-             else
-               target = assign_temp (type, 0, 1, 1);
-           }
+    case VEC_PACK_TRUNC_EXPR:
+    case VEC_PACK_SAT_EXPR:
+    case VEC_PACK_FIX_TRUNC_EXPR:
+      mode = TYPE_MODE (TREE_TYPE (treeop0));
+      goto binop;
 
-         if (MEM_P (target))
-           /* Store data into beginning of memory target.  */
-           store_expr (TREE_OPERAND (exp, 0),
-                       adjust_address (target, TYPE_MODE (valtype), 0),
-                       modifier == EXPAND_STACK_PARM,
-                       false);
+    case DOT_PROD_EXPR:
+      {
+       tree oprnd0 = treeop0;
+       tree oprnd1 = treeop1;
+       tree oprnd2 = treeop2;
+       rtx op2;
 
-         else
-           {
-             gcc_assert (REG_P (target));
+       expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+       op2 = expand_normal (oprnd2);
+       target = expand_widen_pattern_expr (ops, op0, op1, op2,
+                                           target, unsignedp);
+       return target;
+      }
 
-             /* Store this field into a union of the proper type.  */
-             store_field (target,
-                          MIN ((int_size_in_bytes (TREE_TYPE
-                                                   (TREE_OPERAND (exp, 0)))
-                                * BITS_PER_UNIT),
-                               (HOST_WIDE_INT) GET_MODE_BITSIZE (mode)),
-                          0, TYPE_MODE (valtype), TREE_OPERAND (exp, 0),
-                          type, 0, false);
-           }
+    case REALIGN_LOAD_EXPR:
+      {
+        tree oprnd0 = treeop0;
+        tree oprnd1 = treeop1;
+        tree oprnd2 = treeop2;
+        rtx op2;
 
-         /* Return the entire union.  */
-         return target;
-       }
+        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);
+        gcc_assert (temp);
+        return temp;
+      }
 
-      if (mode == TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
-       {
-         op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode,
-                            modifier);
+    default:
+      gcc_unreachable ();
+    }
 
-         /* If the signedness of the conversion differs and OP0 is
-            a promoted SUBREG, clear that indication since we now
-            have to do the proper extension.  */
-         if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))) != unsignedp
-             && GET_CODE (op0) == SUBREG)
-           SUBREG_PROMOTED_VAR_P (op0) = 0;
+  /* Here to do an ordinary binary operator.  */
+ binop:
+  expand_operands (treeop0, treeop1,
+                  subtarget, &op0, &op1, EXPAND_NORMAL);
+ binop2:
+  this_optab = optab_for_tree_code (code, type, optab_default);
+ binop3:
+  if (modifier == EXPAND_STACK_PARM)
+    target = 0;
+  temp = expand_binop (mode, this_optab, op0, op1, target,
+                      unsignedp, OPTAB_LIB_WIDEN);
+  gcc_assert (temp);
+  return REDUCE_BIT_FIELD (temp);
+}
+#undef REDUCE_BIT_FIELD
 
-         return REDUCE_BIT_FIELD (op0);
-       }
+rtx
+expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
+                   enum expand_modifier modifier, rtx *alt_rtl)
+{
+  rtx op0, op1, temp, decl_rtl;
+  tree type;
+  int unsignedp;
+  enum machine_mode mode;
+  enum tree_code code = TREE_CODE (exp);
+  rtx subtarget, original_target;
+  int ignore;
+  tree context;
+  bool reduce_bit_field;
+  location_t loc = EXPR_LOCATION (exp);
+  struct separate_ops ops;
+  tree treeop0, treeop1, treeop2;
+  tree ssa_name = NULL_TREE;
+  gimple g;
 
-      op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode,
-                        modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier);
-      if (GET_MODE (op0) == mode)
-       ;
+  type = TREE_TYPE (exp);
+  mode = TYPE_MODE (type);
+  unsignedp = TYPE_UNSIGNED (type);
 
-      /* If OP0 is a constant, just convert it into the proper mode.  */
-      else if (CONSTANT_P (op0))
-       {
-         tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
-         enum machine_mode inner_mode = TYPE_MODE (inner_type);
+  treeop0 = treeop1 = treeop2 = NULL_TREE;
+  if (!VL_EXP_CLASS_P (exp))
+    switch (TREE_CODE_LENGTH (code))
+      {
+       default:
+       case 3: treeop2 = TREE_OPERAND (exp, 2);
+       case 2: treeop1 = TREE_OPERAND (exp, 1);
+       case 1: treeop0 = TREE_OPERAND (exp, 0);
+       case 0: break;
+      }
+  ops.code = code;
+  ops.type = type;
+  ops.op0 = treeop0;
+  ops.op1 = treeop1;
+  ops.op2 = treeop2;
+  ops.location = loc;
 
-         if (modifier == EXPAND_INITIALIZER)
-           op0 = simplify_gen_subreg (mode, op0, inner_mode,
-                                      subreg_lowpart_offset (mode,
-                                                             inner_mode));
-         else
-           op0=  convert_modes (mode, inner_mode, op0,
-                                TYPE_UNSIGNED (inner_type));
+  ignore = (target == const0_rtx
+           || ((CONVERT_EXPR_CODE_P (code)
+                || 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
+     not call expand_expr with anything but const0_rtx in case this
+     is an initial expansion of a size that contains a PLACEHOLDER_EXPR.  */
+
+  if (ignore)
+    {
+      if (! TREE_SIDE_EFFECTS (exp))
+       return const0_rtx;
+
+      /* Ensure we reference a volatile object even if value is ignored, but
+        don't do this if all we are doing is taking its address.  */
+      if (TREE_THIS_VOLATILE (exp)
+         && TREE_CODE (exp) != FUNCTION_DECL
+         && mode != VOIDmode && mode != BLKmode
+         && modifier != EXPAND_CONST_ADDRESS)
+       {
+         temp = expand_expr (exp, NULL_RTX, VOIDmode, modifier);
+         if (MEM_P (temp))
+           copy_to_reg (temp);
+         return const0_rtx;
        }
 
-      else if (modifier == EXPAND_INITIALIZER)
-       op0 = gen_rtx_fmt_e (unsignedp ? ZERO_EXTEND : SIGN_EXTEND, mode, op0);
+      if (TREE_CODE_CLASS (code) == tcc_unary
+         || code == COMPONENT_REF || code == INDIRECT_REF)
+       return expand_expr (treeop0, const0_rtx, VOIDmode,
+                           modifier);
 
-      else if (target == 0)
-       op0 = convert_to_mode (mode, op0,
-                              TYPE_UNSIGNED (TREE_TYPE
-                                             (TREE_OPERAND (exp, 0))));
-      else
+      else if (TREE_CODE_CLASS (code) == tcc_binary
+              || TREE_CODE_CLASS (code) == tcc_comparison
+              || code == ARRAY_REF || code == ARRAY_RANGE_REF)
        {
-         convert_move (target, op0,
-                       TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
-         op0 = target;
+         expand_expr (treeop0, const0_rtx, VOIDmode, modifier);
+         expand_expr (treeop1, const0_rtx, VOIDmode, modifier);
+         return const0_rtx;
+       }
+      else if (code == BIT_FIELD_REF)
+       {
+         expand_expr (treeop0, const0_rtx, VOIDmode, modifier);
+         expand_expr (treeop1, const0_rtx, VOIDmode, modifier);
+         expand_expr (treeop2, const0_rtx, VOIDmode, modifier);
+         return const0_rtx;
        }
 
-      return REDUCE_BIT_FIELD (op0);
+      target = 0;
+    }
 
-    case VIEW_CONVERT_EXPR:
-      op0 = NULL_RTX;
+  if (reduce_bit_field && modifier == EXPAND_STACK_PARM)
+    target = 0;
 
-      /* If we are converting to BLKmode, try to avoid an intermediate
-        temporary by fetching an inner memory reference.  */
-      if (mode == BLKmode
-         && TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) == INTEGER_CST
-         && TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))) != BLKmode
-         && handled_component_p (TREE_OPERAND (exp, 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:
       {
-       enum machine_mode mode1;
-       HOST_WIDE_INT bitsize, bitpos;
-       tree offset;
-       int unsignedp;
-       int volatilep = 0;
-       tree tem
-         = get_inner_reference (TREE_OPERAND (exp, 0), &bitsize, &bitpos,
-                                &offset, &mode1, &unsignedp, &volatilep,
-                                true);
-       rtx orig_op0;
+       tree function = decl_function_context (exp);
 
-       /* ??? We should work harder and deal with non-zero offsets.  */
-       if (!offset
-           && (bitpos % BITS_PER_UNIT) == 0
-           && bitsize >= 0
-           && compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)), bitsize) == 0)
-         {
-           /* See the normal_inner_ref case for the rationale.  */
-           orig_op0
-             = expand_expr (tem,
-                            (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
-                             && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
-                                 != INTEGER_CST)
-                             && modifier != EXPAND_STACK_PARM
-                             ? target : NULL_RTX),
-                            VOIDmode,
-                            (modifier == EXPAND_INITIALIZER
-                             || modifier == EXPAND_CONST_ADDRESS
-                             || modifier == EXPAND_STACK_PARM)
-                            ? modifier : EXPAND_NORMAL);
+       temp = label_rtx (exp);
+       temp = gen_rtx_LABEL_REF (Pmode, temp);
 
-           if (MEM_P (orig_op0))
-             {
-               op0 = orig_op0;
+       if (function != current_function_decl
+           && function != 0)
+         LABEL_REF_NONLOCAL_P (temp) = 1;
 
-               /* Get a reference to just this component.  */
-               if (modifier == EXPAND_CONST_ADDRESS
-                   || modifier == EXPAND_SUM
-                   || modifier == EXPAND_INITIALIZER)
-                 op0 = adjust_address_nv (op0, mode, bitpos / BITS_PER_UNIT);
-               else
-                 op0 = adjust_address (op0, mode, bitpos / BITS_PER_UNIT);
+       temp = gen_rtx_MEM (FUNCTION_MODE, temp);
+       return temp;
+      }
 
-               if (op0 == orig_op0)
-                 op0 = copy_rtx (op0);
+    case SSA_NAME:
+      /* ??? ivopts calls expander, without any preparation from
+         out-of-ssa.  So fake instructions as if this was an access to the
+        base variable.  This unnecessarily allocates a pseudo, see how we can
+        reuse it, if partition base vars have it set already.  */
+      if (!currently_expanding_to_rtl)
+       return expand_expr_real_1 (SSA_NAME_VAR (exp), target, tmode, modifier,
+                                  NULL);
+
+      g = get_gimple_for_ssa_name (exp);
+      /* For EXPAND_INITIALIZER try harder to get something simpler.  */
+      if (g == NULL
+         && modifier == EXPAND_INITIALIZER
+         && !SSA_NAME_IS_DEFAULT_DEF (exp)
+         && (optimize || DECL_IGNORED_P (SSA_NAME_VAR (exp)))
+         && stmt_is_replaceable_p (SSA_NAME_DEF_STMT (exp)))
+       g = SSA_NAME_DEF_STMT (exp);
+      if (g)
+       return expand_expr_real (gimple_assign_rhs_to_tree (g), target, tmode,
+                                modifier, NULL);
+
+      ssa_name = exp;
+      decl_rtl = get_rtx_for_ssa_name (ssa_name);
+      exp = SSA_NAME_VAR (ssa_name);
+      goto expand_decl_rtl;
 
-               set_mem_attributes (op0, TREE_OPERAND (exp, 0), 0);
-               if (REG_P (XEXP (op0, 0)))
-                 mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
+    case PARM_DECL:
+    case VAR_DECL:
+      /* If a static var's type was incomplete when the decl was written,
+        but the type is complete now, lay out the decl now.  */
+      if (DECL_SIZE (exp) == 0
+         && COMPLETE_OR_UNBOUND_ARRAY_TYPE_P (TREE_TYPE (exp))
+         && (TREE_STATIC (exp) || DECL_EXTERNAL (exp)))
+       layout_decl (exp, 0);
 
-               MEM_VOLATILE_P (op0) |= volatilep;
-             }
-         }
-      }
+      /* ... fall through ...  */
 
-      if (!op0)
-       op0 = expand_expr (TREE_OPERAND (exp, 0),
-                          NULL_RTX, VOIDmode, modifier);
+    case FUNCTION_DECL:
+    case RESULT_DECL:
+      decl_rtl = DECL_RTL (exp);
+    expand_decl_rtl:
+      gcc_assert (decl_rtl);
+      decl_rtl = copy_rtx (decl_rtl);
+      /* Record writes to register variables.  */
+      if (modifier == EXPAND_WRITE
+         && REG_P (decl_rtl)
+         && HARD_REGISTER_P (decl_rtl))
+        add_to_hard_reg_set (&crtl->asm_clobbers,
+                            GET_MODE (decl_rtl), REGNO (decl_rtl));
 
-      /* If the input and output modes are both the same, we are done.  */
-      if (mode == GET_MODE (op0))
-       ;
-      /* If neither mode is BLKmode, and both modes are the same size
-        then we can use gen_lowpart.  */
-      else if (mode != BLKmode && GET_MODE (op0) != BLKmode
-              && GET_MODE_SIZE (mode) == GET_MODE_SIZE (GET_MODE (op0))
-              && !COMPLEX_MODE_P (GET_MODE (op0)))
+      /* 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
+        definition.  */
+      if (! TREE_USED (exp))
        {
-         if (GET_CODE (op0) == SUBREG)
-           op0 = force_reg (GET_MODE (op0), op0);
-         op0 = gen_lowpart (mode, op0);
+         assemble_external (exp);
+         TREE_USED (exp) = 1;
        }
-      /* 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 (mode))
-       op0 = convert_modes (mode, 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 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));
 
-         gcc_assert (!TREE_ADDRESSABLE (exp));
+      /* Show we haven't gotten RTL for this yet.  */
+      temp = 0;
 
-         if (target == 0 || GET_MODE (target) != TYPE_MODE (inner_type))
-           target
-             = assign_stack_temp_for_type
-               (TYPE_MODE (inner_type),
-                GET_MODE_SIZE (TYPE_MODE (inner_type)), 0, inner_type);
+      /* Variables inherited from containing functions should have
+        been lowered by this point.  */
+      context = decl_function_context (exp);
+      gcc_assert (!context
+                 || context == current_function_decl
+                 || TREE_STATIC (exp)
+                 || DECL_EXTERNAL (exp)
+                 /* ??? C++ creates functions that are not TREE_STATIC.  */
+                 || TREE_CODE (exp) == FUNCTION_DECL);
 
-         emit_move_insn (target, op0);
-         op0 = target;
-       }
+      /* This is the case of an array whose size is to be determined
+        from its initializer, while the initializer is still being parsed.
+        See expand_decl.  */
 
-      /* At this point, OP0 is in the correct mode.  If the output type is
-        such that the operand is known to be aligned, indicate that it is.
-        Otherwise, we need only be concerned about alignment for non-BLKmode
-        results.  */
-      if (MEM_P (op0))
+      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 the
+        address is not valid, get the address into a register.  */
+
+      else if (MEM_P (decl_rtl) && modifier != EXPAND_INITIALIZER)
        {
-         op0 = copy_rtx (op0);
+         if (alt_rtl)
+           *alt_rtl = decl_rtl;
+         decl_rtl = use_anchored_address (decl_rtl);
+         if (modifier != EXPAND_CONST_ADDRESS
+             && modifier != EXPAND_SUM
+             && !memory_address_addr_space_p (DECL_MODE (exp),
+                                              XEXP (decl_rtl, 0),
+                                              MEM_ADDR_SPACE (decl_rtl)))
+           temp = replace_equiv_address (decl_rtl,
+                                         copy_rtx (XEXP (decl_rtl, 0)));
+       }
 
-         if (TYPE_ALIGN_OK (type))
-           set_mem_align (op0, MAX (MEM_ALIGN (op0), TYPE_ALIGN (type)));
-         else if (STRICT_ALIGNMENT
-                  && mode != BLKmode
-                  && MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (mode))
-           {
-             tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
-             HOST_WIDE_INT temp_size
-               = MAX (int_size_in_bytes (inner_type),
-                      (HOST_WIDE_INT) GET_MODE_SIZE (mode));
-             rtx new_rtx
-               = assign_stack_temp_for_type (mode, temp_size, 0, type);
-             rtx new_with_op0_mode
-               = adjust_address (new_rtx, GET_MODE (op0), 0);
+      /* If we got something, return it.  But first, set the alignment
+        if the address is a register.  */
+      if (temp != 0)
+       {
+         if (MEM_P (temp) && REG_P (XEXP (temp, 0)))
+           mark_reg_pointer (XEXP (temp, 0), DECL_ALIGN (exp));
 
-             gcc_assert (!TREE_ADDRESSABLE (exp));
+         return temp;
+       }
 
-             if (GET_MODE (op0) == BLKmode)
-               emit_block_move (new_with_op0_mode, op0,
-                                GEN_INT (GET_MODE_SIZE (mode)),
-                                (modifier == EXPAND_STACK_PARM
-                                 ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
-             else
-               emit_move_insn (new_with_op0_mode, op0);
+      /* If the mode of DECL_RTL does not match that of the decl, it
+        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) && GET_MODE (decl_rtl) != DECL_MODE (exp))
+       {
+         enum machine_mode pmode;
 
-             op0 = new_rtx;
+         /* Get the signedness to be used for this variable.  Ensure we get
+            the same mode we got when the variable was declared.  */
+         if (code == SSA_NAME
+             && (g = SSA_NAME_DEF_STMT (ssa_name))
+             && gimple_code (g) == GIMPLE_CALL)
+           {
+             gcc_assert (!gimple_call_internal_p (g));
+             pmode = promote_function_mode (type, mode, &unsignedp,
+                                            gimple_call_fntype (g),
+                                            2);
            }
+         else
+           pmode = promote_decl_mode (exp, &unsignedp);
+         gcc_assert (GET_MODE (decl_rtl) == pmode);
 
-         op0 = adjust_address (op0, mode, 0);
+         temp = gen_lowpart_SUBREG (mode, decl_rtl);
+         SUBREG_PROMOTED_VAR_P (temp) = 1;
+         SUBREG_PROMOTED_UNSIGNED_SET (temp, unsignedp);
+         return temp;
        }
 
-      return op0;
+      return decl_rtl;
 
-    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.  */
-      /* Make sure to sign-extend the sizetype offset in a POINTER_PLUS_EXPR
-         if sizetype precision is smaller than pointer precision.  */
-      if (TYPE_PRECISION (sizetype) < TYPE_PRECISION (type))
-       exp
-         = build2 (PLUS_EXPR, type,
-                   TREE_OPERAND (exp, 0),
-                   fold_convert_loc (loc, type,
-                                     fold_convert_loc (loc, ssizetype,
-                                                       TREE_OPERAND (exp, 1))));
-    case PLUS_EXPR:
+    case INTEGER_CST:
+      temp = immed_double_const (TREE_INT_CST_LOW (exp),
+                                TREE_INT_CST_HIGH (exp), mode);
 
-      /* Check if this is a case for multiplication and addition.  */
-      if ((TREE_CODE (type) == INTEGER_TYPE
-          || TREE_CODE (type) == FIXED_POINT_TYPE)
-         && (subexp0_def = get_def_for_expr (TREE_OPERAND (exp, 0),
-                                             MULT_EXPR)))
-       {
-         tree subsubexp0, subsubexp1;
-         gimple subsubexp0_def, subsubexp1_def;
-         enum tree_code this_code;
-
-         this_code = TREE_CODE (type) == INTEGER_TYPE ? NOP_EXPR
-                                                      : FIXED_CONVERT_EXPR;
-         subsubexp0 = gimple_assign_rhs1 (subexp0_def);
-         subsubexp0_def = get_def_for_expr (subsubexp0, this_code);
-         subsubexp1 = gimple_assign_rhs2 (subexp0_def);
-         subsubexp1_def = get_def_for_expr (subsubexp1, this_code);
-         if (subsubexp0_def && subsubexp1_def
-             && (top0 = gimple_assign_rhs1 (subsubexp0_def))
-             && (top1 = gimple_assign_rhs1 (subsubexp1_def))
-             && (TYPE_PRECISION (TREE_TYPE (top0))
-                 < TYPE_PRECISION (TREE_TYPE (subsubexp0)))
-             && (TYPE_PRECISION (TREE_TYPE (top0))
-                 == TYPE_PRECISION (TREE_TYPE (top1)))
-             && (TYPE_UNSIGNED (TREE_TYPE (top0))
-                 == TYPE_UNSIGNED (TREE_TYPE (top1))))
-           {
-             tree op0type = TREE_TYPE (top0);
-             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 (top0, top1, 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);
-               }
-           }
-       }
+      return 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
-        reduction and doing it this way will produce better code if the
-        frame pointer or argument pointer is eliminated.
+    case VECTOR_CST:
+      {
+       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_loc (loc, 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);
+      }
 
-        fold-const.c will ensure that the constant is always in the inner
-        PLUS_EXPR, so the only case we need to do anything about is if
-        sp, ap, or fp is our second argument, in which case we must swap
-        the innermost first argument and our second argument.  */
+    case CONST_DECL:
+      return expand_expr (DECL_INITIAL (exp), target, VOIDmode, modifier);
 
-      if (TREE_CODE (TREE_OPERAND (exp, 0)) == PLUS_EXPR
-         && TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 1)) == INTEGER_CST
-         && TREE_CODE (TREE_OPERAND (exp, 1)) == VAR_DECL
-         && (DECL_RTL (TREE_OPERAND (exp, 1)) == frame_pointer_rtx
-             || DECL_RTL (TREE_OPERAND (exp, 1)) == stack_pointer_rtx
-             || DECL_RTL (TREE_OPERAND (exp, 1)) == arg_pointer_rtx))
-       {
-         tree t = TREE_OPERAND (exp, 1);
+    case REAL_CST:
+      /* If optimized, generate immediate CONST_DOUBLE
+        which will be turned into memory by reload if necessary.
 
-         TREE_OPERAND (exp, 1) = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
-         TREE_OPERAND (TREE_OPERAND (exp, 0), 0) = t;
-       }
+        We used to force a register so that loop.c could see it.  But
+        this does not allow gen_* patterns to perform optimizations with
+        the constants.  It also produces two insns in cases like "x = 1.0;".
+        On most machines, floating-point constants are not permitted in
+        many insns, so we'd end up copying it to a register in any case.
 
-      /* If the result is to be ptr_mode and we are adding an integer to
-        something, we might be forming a constant.  So try to use
-        plus_constant.  If it produces a sum and we can't accept it,
-        use force_operand.  This allows P = &ARR[const] to generate
-        efficient code on machines where a SYMBOL_REF is not a valid
-        address.
+        Now, we do the copying in expand_binop, if appropriate.  */
+      return CONST_DOUBLE_FROM_REAL_VALUE (TREE_REAL_CST (exp),
+                                          TYPE_MODE (TREE_TYPE (exp)));
 
-        If this is an EXPAND_SUM call, always return the sum.  */
-      if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER
-         || (mode == ptr_mode && (unsignedp || ! flag_trapv)))
+    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)
        {
-         if (modifier == EXPAND_STACK_PARM)
-           target = 0;
-         if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST
-             && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
-             && TREE_CONSTANT (TREE_OPERAND (exp, 1)))
-           {
-             rtx constant_part;
+         enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
+         rtx rtarg, itarg;
 
-             op1 = expand_expr (TREE_OPERAND (exp, 1), subtarget, VOIDmode,
-                                EXPAND_SUM);
-             /* Use immed_double_const to ensure that the constant is
-                truncated according to the mode of OP1, then sign extended
-                to a HOST_WIDE_INT.  Using the constant directly can result
-                in non-canonical RTL in a 64x32 cross compile.  */
-             constant_part
-               = immed_double_const (TREE_INT_CST_LOW (TREE_OPERAND (exp, 0)),
-                                     (HOST_WIDE_INT) 0,
-                                     TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 1))));
-             op1 = plus_constant (op1, INTVAL (constant_part));
-             if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
-               op1 = force_operand (op1, target);
-             return REDUCE_BIT_FIELD (op1);
-           }
+         rtarg = XEXP (original_target, 0);
+         itarg = XEXP (original_target, 1);
 
-         else if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
-                  && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
-                  && TREE_CONSTANT (TREE_OPERAND (exp, 0)))
-           {
-             rtx constant_part;
+         /* Move the real and imaginary parts separately.  */
+         op0 = expand_expr (TREE_REALPART (exp), rtarg, mode, EXPAND_NORMAL);
+         op1 = expand_expr (TREE_IMAGPART (exp), itarg, mode, EXPAND_NORMAL);
 
-             op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode,
-                                (modifier == EXPAND_INITIALIZER
-                                ? EXPAND_INITIALIZER : EXPAND_SUM));
-             if (! CONSTANT_P (op0))
-               {
-                 op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX,
-                                    VOIDmode, modifier);
-                 /* Return a PLUS if modifier says it's OK.  */
-                 if (modifier == EXPAND_SUM
-                     || modifier == EXPAND_INITIALIZER)
-                   return simplify_gen_binary (PLUS, mode, op0, op1);
-                 goto binop2;
-               }
-             /* Use immed_double_const to ensure that the constant is
-                truncated according to the mode of OP1, then sign extended
-                to a HOST_WIDE_INT.  Using the constant directly can result
-                in non-canonical RTL in a 64x32 cross compile.  */
-             constant_part
-               = immed_double_const (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)),
-                                     (HOST_WIDE_INT) 0,
-                                     TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))));
-             op0 = plus_constant (op0, INTVAL (constant_part));
-             if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
-               op0 = force_operand (op0, target);
-             return REDUCE_BIT_FIELD (op0);
-           }
-       }
+         if (op0 != rtarg)
+           emit_move_insn (rtarg, op0);
+         if (op1 != itarg)
+           emit_move_insn (itarg, op1);
 
-      /* No sense saving up arithmetic to be done
-        if it's all in the wrong mode to form part of an address.
-        And force_operand won't know whether to sign-extend or
-        zero-extend.  */
-      if ((modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
-         || mode != ptr_mode)
-       {
-         expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
-                          subtarget, &op0, &op1, EXPAND_NORMAL);
-         if (op0 == const0_rtx)
-           return op1;
-         if (op1 == const0_rtx)
-           return op0;
-         goto binop2;
+         return original_target;
        }
 
-      expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
-                      subtarget, &op0, &op1, modifier);
-      return REDUCE_BIT_FIELD (simplify_gen_binary (PLUS, mode, op0, op1));
+      /* ... fall through ...  */
 
-    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)
-         && (subexp1_def = get_def_for_expr (TREE_OPERAND (exp, 1),
-                                             MULT_EXPR)))
-       {
-         tree subsubexp0, subsubexp1;
-         gimple subsubexp0_def, subsubexp1_def;
-         enum tree_code this_code;
-
-         this_code = TREE_CODE (type) == INTEGER_TYPE ? NOP_EXPR
-                                                      : FIXED_CONVERT_EXPR;
-         subsubexp0 = gimple_assign_rhs1 (subexp1_def);
-         subsubexp0_def = get_def_for_expr (subsubexp0, this_code);
-         subsubexp1 = gimple_assign_rhs2 (subexp1_def);
-         subsubexp1_def = get_def_for_expr (subsubexp1, this_code);
-         if (subsubexp0_def && subsubexp1_def
-             && (top0 = gimple_assign_rhs1 (subsubexp0_def))
-             && (top1 = gimple_assign_rhs1 (subsubexp1_def))
-             && (TYPE_PRECISION (TREE_TYPE (top0))
-                 < TYPE_PRECISION (TREE_TYPE (subsubexp0)))
-             && (TYPE_PRECISION (TREE_TYPE (top0))
-                 == TYPE_PRECISION (TREE_TYPE (top1)))
-             && (TYPE_UNSIGNED (TREE_TYPE (top0))
-                 == TYPE_UNSIGNED (TREE_TYPE (top1))))
-           {
-             tree op0type = TREE_TYPE (top0);
-             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 (top0, top1, 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);
-               }
-           }
-       }
+    case STRING_CST:
+      temp = expand_expr_constant (exp, 1, modifier);
 
-      /* For initializers, we are allowed to return a MINUS of two
-        symbolic constants.  Here we handle all cases when both operands
-        are constant.  */
-      /* Handle difference of two symbolic constants,
-        for the sake of an initializer.  */
-      if ((modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
-         && really_constant_p (TREE_OPERAND (exp, 0))
-         && really_constant_p (TREE_OPERAND (exp, 1)))
-       {
-         expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
-                          NULL_RTX, &op0, &op1, modifier);
-
-         /* If the last operand is a CONST_INT, use plus_constant of
-            the negated constant.  Else make the MINUS.  */
-         if (CONST_INT_P (op1))
-           return REDUCE_BIT_FIELD (plus_constant (op0, - INTVAL (op1)));
-         else
-           return REDUCE_BIT_FIELD (gen_rtx_MINUS (mode, op0, op1));
-       }
-
-      /* No sense saving up arithmetic to be done
-        if it's all in the wrong mode to form part of an address.
-        And force_operand won't know whether to sign-extend or
-        zero-extend.  */
-      if ((modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
-         || mode != ptr_mode)
-       goto binop;
+      /* temp contains a constant address.
+        On RISC machines where a constant address isn't valid,
+        make some insns to get that address into a register.  */
+      if (modifier != EXPAND_CONST_ADDRESS
+         && modifier != EXPAND_INITIALIZER
+         && modifier != EXPAND_SUM
+         && ! memory_address_addr_space_p (mode, XEXP (temp, 0),
+                                           MEM_ADDR_SPACE (temp)))
+       return replace_equiv_address (temp,
+                                     copy_rtx (XEXP (temp, 0)));
+      return temp;
 
-      expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
-                      subtarget, &op0, &op1, modifier);
+    case SAVE_EXPR:
+      {
+       tree val = treeop0;
+       rtx ret = expand_expr_real_1 (val, target, tmode, modifier, alt_rtl);
 
-      /* Convert A - const to A + (-const).  */
-      if (CONST_INT_P (op1))
-       {
-         op1 = negate_rtx (mode, op1);
-         return REDUCE_BIT_FIELD (simplify_gen_binary (PLUS, mode, op0, op1));
-       }
+       if (!SAVE_EXPR_RESOLVED_P (exp))
+         {
+           /* We can indeed still hit this case, typically via builtin
+              expanders calling save_expr immediately before expanding
+              something.  Assume this means that we only have to deal
+              with non-BLKmode values.  */
+           gcc_assert (GET_MODE (ret) != BLKmode);
 
-      goto binop2;
+           val = build_decl (EXPR_LOCATION (exp),
+                             VAR_DECL, NULL, TREE_TYPE (exp));
+           DECL_ARTIFICIAL (val) = 1;
+           DECL_IGNORED_P (val) = 1;
+           treeop0 = val;
+           TREE_OPERAND (exp, 0) = treeop0;
+           SAVE_EXPR_RESOLVED_P (exp) = 1;
 
-    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 (!CONSTANT_P (ret))
+             ret = copy_to_reg (ret);
+           SET_DECL_RTL (val, ret);
+         }
 
-      /* If first operand is constant, swap them.
-        Thus the following special case checks need only
-        check the second operand.  */
-      if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST)
-       {
-         tree t1 = TREE_OPERAND (exp, 0);
-         TREE_OPERAND (exp, 0) = TREE_OPERAND (exp, 1);
-         TREE_OPERAND (exp, 1) = t1;
-       }
+        return ret;
+      }
 
-      /* Attempt to return something suitable for generating an
-        indexed address, for machines that support that.  */
 
-      if (modifier == EXPAND_SUM && mode == ptr_mode
-         && host_integerp (TREE_OPERAND (exp, 1), 0))
+    case CONSTRUCTOR:
+      /* If we don't need the result, just ensure we evaluate any
+        subexpressions.  */
+      if (ignore)
        {
-         tree exp1 = TREE_OPERAND (exp, 1);
-
-         op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode,
-                            EXPAND_SUM);
+         unsigned HOST_WIDE_INT idx;
+         tree value;
 
-         if (!REG_P (op0))
-           op0 = force_operand (op0, NULL_RTX);
-         if (!REG_P (op0))
-           op0 = copy_to_mode_reg (mode, op0);
+         FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value)
+           expand_expr (value, const0_rtx, VOIDmode, EXPAND_NORMAL);
 
-         return REDUCE_BIT_FIELD (gen_rtx_MULT (mode, op0,
-                              gen_int_mode (tree_low_cst (exp1, 0),
-                                            TYPE_MODE (TREE_TYPE (exp1)))));
+         return const0_rtx;
        }
 
-      if (modifier == EXPAND_STACK_PARM)
-       target = 0;
+      return expand_constructor (exp, target, modifier, false);
 
-      /* Check for multiplying things that have been extended
-        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.  */
+    case TARGET_MEM_REF:
+      {
+       addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (exp));
+       struct mem_address addr;
+       int icode, align;
 
-      subexp0 = TREE_OPERAND (exp, 0);
-      subexp1 = TREE_OPERAND (exp, 1);
-      subexp0_def = get_def_for_expr (subexp0, NOP_EXPR);
-      subexp1_def = get_def_for_expr (subexp1, NOP_EXPR);
-      top0 = top1 = NULL_TREE;
+       get_address_description (exp, &addr);
+       op0 = addr_for_mem_ref (&addr, as, true);
+       op0 = memory_address_addr_space (mode, op0, as);
+       temp = gen_rtx_MEM (mode, op0);
+       set_mem_attributes (temp, exp, 0);
+       set_mem_addr_space (temp, as);
+       align = MAX (TYPE_ALIGN (TREE_TYPE (exp)),
+                    get_object_alignment (exp, BIGGEST_ALIGNMENT));
+       if (mode != BLKmode
+           && (unsigned) align < GET_MODE_ALIGNMENT (mode)
+           /* If the target does not have special handling for unaligned
+              loads of mode then it can use regular moves for them.  */
+           && ((icode = optab_handler (movmisalign_optab, mode))
+               != CODE_FOR_nothing))
+         {
+           rtx reg, insn;
 
-      /* First, check if we have a multiplication of one signed and one
-        unsigned operand.  */
-      if (subexp0_def
-         && (top0 = gimple_assign_rhs1 (subexp0_def))
-         && subexp1_def
-         && (top1 = gimple_assign_rhs1 (subexp1_def))
-         && TREE_CODE (type) == INTEGER_TYPE
-         && (TYPE_PRECISION (TREE_TYPE (top0))
-             < TYPE_PRECISION (TREE_TYPE (subexp0)))
-         && (TYPE_PRECISION (TREE_TYPE (top0))
-             == TYPE_PRECISION (TREE_TYPE (top1)))
-         && (TYPE_UNSIGNED (TREE_TYPE (top0))
-             != TYPE_UNSIGNED (TREE_TYPE (top1))))
-       {
-         enum machine_mode innermode
-           = TYPE_MODE (TREE_TYPE (top0));
-         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 (top0)))
-                   expand_operands (top0, top1, NULL_RTX, &op0, &op1,
-                                    EXPAND_NORMAL);
-                 else
-                   expand_operands (top0, top1, NULL_RTX, &op1, &op0,
-                                    EXPAND_NORMAL);
+           /* 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);
 
-                 goto binop3;
-               }
-           }
-       }
-      /* Check for a multiplication with matching signedness.  If
-        valid, TOP0 and TOP1 were set in the previous if
-        condition.  */
-      else if (top0
-         && TREE_CODE (type) == INTEGER_TYPE
-         && (TYPE_PRECISION (TREE_TYPE (top0))
-             < TYPE_PRECISION (TREE_TYPE (subexp0)))
-         && ((TREE_CODE (subexp1) == INTEGER_CST
-              && int_fits_type_p (subexp1, TREE_TYPE (top0))
-              /* Don't use a widening multiply if a shift will do.  */
-              && ((GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (subexp1)))
-                   > HOST_BITS_PER_WIDE_INT)
-                  || exact_log2 (TREE_INT_CST_LOW (subexp1)) < 0))
-             ||
-             (top1
-              && (TYPE_PRECISION (TREE_TYPE (top1))
-                  == TYPE_PRECISION (TREE_TYPE (top0))
-              /* If both operands are extended, they must either both
-                 be zero-extended or both be sign-extended.  */
-              && (TYPE_UNSIGNED (TREE_TYPE (top1))
-                  == TYPE_UNSIGNED (TREE_TYPE (top0)))))))
-       {
-         tree op0type = TREE_TYPE (top0);
-         enum machine_mode innermode = TYPE_MODE (op0type);
-         bool zextend_p = TYPE_UNSIGNED (op0type);
-         optab other_optab = zextend_p ? smul_widen_optab : umul_widen_optab;
-         this_optab = zextend_p ? umul_widen_optab : smul_widen_optab;
+           /* Nor can the insn generator.  */
+           insn = GEN_FCN (icode) (reg, temp);
+           gcc_assert (insn != NULL_RTX);
+           emit_insn (insn);
 
-         if (mode == GET_MODE_2XWIDER_MODE (innermode))
-           {
-             if (optab_handler (this_optab, mode)->insn_code != CODE_FOR_nothing)
-               {
-                 if (TREE_CODE (subexp1) == INTEGER_CST)
-                   expand_operands (top0, subexp1, NULL_RTX, &op0, &op1,
-                                    EXPAND_NORMAL);
-                 else
-                   expand_operands (top0, top1, NULL_RTX, &op0, &op1,
-                                    EXPAND_NORMAL);
-                 goto binop3;
-               }
-             else if (optab_handler (other_optab, mode)->insn_code != CODE_FOR_nothing
-                      && innermode == word_mode)
-               {
-                 rtx htem, hipart;
-                 op0 = expand_normal (top0);
-                 if (TREE_CODE (subexp1) == INTEGER_CST)
-                   op1 = convert_modes (innermode, mode,
-                                        expand_normal (subexp1), unsignedp);
-                 else
-                   op1 = expand_normal (top1);
-                 temp = expand_binop (mode, other_optab, op0, op1, target,
-                                      unsignedp, OPTAB_LIB_WIDEN);
-                 hipart = gen_highpart (innermode, temp);
-                 htem = expand_mult_highpart_adjust (innermode, hipart,
-                                                     op0, op1, hipart,
-                                                     zextend_p);
-                 if (htem != hipart)
-                   emit_move_insn (hipart, htem);
-                 return REDUCE_BIT_FIELD (temp);
-               }
-           }
-       }
-      expand_operands (subexp0, subexp1, subtarget, &op0, &op1, EXPAND_NORMAL);
-      return REDUCE_BIT_FIELD (expand_mult (mode, op0, op1, target, unsignedp));
+           return reg;
+         }
+       return temp;
+      }
 
-    case TRUNC_DIV_EXPR:
-    case FLOOR_DIV_EXPR:
-    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;
+    case MEM_REF:
+      {
+       addr_space_t as
+         = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 1))));
+       enum machine_mode address_mode;
+       tree base = TREE_OPERAND (exp, 0);
+       gimple def_stmt;
+       int icode, align;
+       /* Handle expansion of non-aliased memory with non-BLKmode.  That
+          might end up in a register.  */
+       if (TREE_CODE (base) == ADDR_EXPR)
+         {
+           HOST_WIDE_INT offset = mem_ref_offset (exp).low;
+           tree bit_offset;
+           base = TREE_OPERAND (base, 0);
+           if (!DECL_P (base))
+             {
+               HOST_WIDE_INT off;
+               base = get_addr_base_and_unit_offset (base, &off);
+               gcc_assert (base);
+               offset += off;
+             }
+           /* If we are expanding a MEM_REF of a non-BLKmode non-addressable
+              decl we must use bitfield operations.  */
+           if (DECL_P (base)
+               && !TREE_ADDRESSABLE (base)
+               && DECL_MODE (base) != BLKmode
+               && DECL_RTL_SET_P (base)
+               && !MEM_P (DECL_RTL (base)))
+             {
+               tree bftype;
+               if (offset == 0
+                   && host_integerp (TYPE_SIZE (TREE_TYPE (exp)), 1)
+                   && (GET_MODE_BITSIZE (DECL_MODE (base))
+                       == TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (exp)))))
+                 return expand_expr (build1 (VIEW_CONVERT_EXPR,
+                                             TREE_TYPE (exp), base),
+                                     target, tmode, modifier);
+               bit_offset = bitsize_int (offset * BITS_PER_UNIT);
+               bftype = TREE_TYPE (base);
+               if (TYPE_MODE (TREE_TYPE (exp)) != BLKmode)
+                 bftype = TREE_TYPE (exp);
+               return expand_expr (build3 (BIT_FIELD_REF, bftype,
+                                           base,
+                                           TYPE_SIZE (TREE_TYPE (exp)),
+                                           bit_offset),
+                                   target, tmode, modifier);
+             }
+         }
+       address_mode = targetm.addr_space.address_mode (as);
+       base = TREE_OPERAND (exp, 0);
+       if ((def_stmt = get_def_for_expr (base, BIT_AND_EXPR)))
+         {
+           tree mask = gimple_assign_rhs2 (def_stmt);
+           base = build2 (BIT_AND_EXPR, TREE_TYPE (base),
+                          gimple_assign_rhs1 (def_stmt), mask);
+           TREE_OPERAND (exp, 0) = base;
+         }
+       align = MAX (TYPE_ALIGN (TREE_TYPE (exp)),
+                    get_object_alignment (exp, BIGGEST_ALIGNMENT));
+       op0 = expand_expr (base, NULL_RTX, VOIDmode, EXPAND_SUM);
+       op0 = memory_address_addr_space (address_mode, op0, as);
+       if (!integer_zerop (TREE_OPERAND (exp, 1)))
+         {
+           rtx off
+             = immed_double_int_const (mem_ref_offset (exp), address_mode);
+           op0 = simplify_gen_binary (PLUS, address_mode, op0, off);
+         }
+       op0 = memory_address_addr_space (mode, op0, as);
+       temp = gen_rtx_MEM (mode, op0);
+       set_mem_attributes (temp, exp, 0);
+       set_mem_addr_space (temp, as);
+       if (TREE_THIS_VOLATILE (exp))
+         MEM_VOLATILE_P (temp) = 1;
+       if (mode != BLKmode
+           && (unsigned) align < GET_MODE_ALIGNMENT (mode)
+           /* If the target does not have special handling for unaligned
+              loads of mode then it can use regular moves for them.  */
+           && ((icode = optab_handler (movmisalign_optab, mode))
+               != CODE_FOR_nothing))
+         {
+           rtx reg, insn;
 
-      if (modifier == EXPAND_STACK_PARM)
-       target = 0;
-      /* Possible optimization: compute the dividend with EXPAND_SUM
-        then if the divisor is constant can optimize the case
-        where some terms of the dividend have coeffs divisible by it.  */
-      expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
-                      subtarget, &op0, &op1, EXPAND_NORMAL);
-      return expand_divmod (0, code, mode, op0, op1, target, unsignedp);
+           /* 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);
 
-    case RDIV_EXPR:
-      goto binop;
+           /* Nor can the insn generator.  */
+           insn = GEN_FCN (icode) (reg, temp);
+           emit_insn (insn);
 
-    case TRUNC_MOD_EXPR:
-    case FLOOR_MOD_EXPR:
-    case CEIL_MOD_EXPR:
-    case ROUND_MOD_EXPR:
-      if (modifier == EXPAND_STACK_PARM)
-       target = 0;
-      expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
-                      subtarget, &op0, &op1, EXPAND_NORMAL);
-      return expand_divmod (1, code, mode, op0, op1, target, unsignedp);
+           return reg;
+         }
+       return temp;
+      }
 
-    case FIXED_CONVERT_EXPR:
-      op0 = expand_normal (TREE_OPERAND (exp, 0));
-      if (target == 0 || modifier == EXPAND_STACK_PARM)
-       target = gen_reg_rtx (mode);
+    case ARRAY_REF:
 
-      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;
+      {
+       tree array = treeop0;
+       tree index = treeop1;
 
-    case FIX_TRUNC_EXPR:
-      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;
+       /* Fold an expression like: "foo"[2].
+          This is not done in fold so it won't happen inside &.
+          Don't fold if this is for wide characters since it's too
+          difficult to do correctly and this is a very rare case.  */
 
-    case FLOAT_EXPR:
-      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.
-        So give it the correct mode.  With -O, cse will optimize this.  */
-      if (GET_MODE (op0) == VOIDmode)
-       op0 = copy_to_mode_reg (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))),
-                               op0);
-      expand_float (target, op0,
-                   TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
-      return target;
+       if (modifier != EXPAND_CONST_ADDRESS
+           && modifier != EXPAND_INITIALIZER
+           && modifier != EXPAND_MEMORY)
+         {
+           tree t = fold_read_from_constant_string (exp);
 
-    case NEGATE_EXPR:
-      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_default),
-                         op0, target, 0);
-      gcc_assert (temp);
-      return REDUCE_BIT_FIELD (temp);
+           if (t)
+             return expand_expr (t, target, tmode, modifier);
+         }
 
-    case ABS_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget,
-                        VOIDmode, EXPAND_NORMAL);
-      if (modifier == EXPAND_STACK_PARM)
-       target = 0;
+       /* If this is a constant index into a constant array,
+          just get the value from the array.  Handle both the cases when
+          we have an explicit constructor and when our operand is a variable
+          that was declared const.  */
 
-      /* ABS_EXPR is not valid for complex arguments.  */
-      gcc_assert (GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
-                 && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT);
+       if (modifier != EXPAND_CONST_ADDRESS
+           && modifier != EXPAND_INITIALIZER
+           && modifier != EXPAND_MEMORY
+           && TREE_CODE (array) == CONSTRUCTOR
+           && ! TREE_SIDE_EFFECTS (array)
+           && TREE_CODE (index) == INTEGER_CST)
+         {
+           unsigned HOST_WIDE_INT ix;
+           tree field, value;
 
-      /* Unsigned abs is simply the operand.  Testing here means we don't
-        risk generating incorrect code below.  */
-      if (TYPE_UNSIGNED (type))
-       return op0;
+           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;
+               }
+         }
 
-      return expand_abs (mode, op0, target, unsignedp,
-                        safe_from_p (target, TREE_OPERAND (exp, 0), 1));
+       else if (optimize >= 1
+                && modifier != EXPAND_CONST_ADDRESS
+                && modifier != EXPAND_INITIALIZER
+                && modifier != EXPAND_MEMORY
+                && TREE_READONLY (array) && ! TREE_SIDE_EFFECTS (array)
+                && TREE_CODE (array) == VAR_DECL && DECL_INITIAL (array)
+                && TREE_CODE (DECL_INITIAL (array)) != ERROR_MARK
+                && const_value_known_p (array))
+         {
+           if (TREE_CODE (index) == INTEGER_CST)
+             {
+               tree init = DECL_INITIAL (array);
 
-    case MAX_EXPR:
-    case MIN_EXPR:
-      target = original_target;
-      if (target == 0
-         || modifier == EXPAND_STACK_PARM
-         || (MEM_P (target) && MEM_VOLATILE_P (target))
-         || GET_MODE (target) != mode
-         || (REG_P (target)
-             && REGNO (target) < FIRST_PSEUDO_REGISTER))
-       target = gen_reg_rtx (mode);
-      expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
-                      target, &op0, &op1, EXPAND_NORMAL);
+               if (TREE_CODE (init) == CONSTRUCTOR)
+                 {
+                   unsigned HOST_WIDE_INT ix;
+                   tree field, value;
 
-      /* 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, optab_default);
-      temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
-                          OPTAB_WIDEN);
-      if (temp != 0)
-       return temp;
+                   FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), ix,
+                                             field, value)
+                     if (tree_int_cst_equal (field, index))
+                       {
+                         if (TREE_SIDE_EFFECTS (value))
+                           break;
 
-      /* At this point, a MEM target is no longer useful; we will get better
-        code without it.  */
+                         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)
+                 {
+                   tree index1 = index;
+                   tree low_bound = array_ref_low_bound (exp);
+                   index1 = fold_convert_loc (loc, sizetype,
+                                              treeop1);
+
+                   /* 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_loc (loc, index1,
+                                           fold_convert_loc (loc, 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);
+                     }
+                 }
+             }
+         }
+      }
+      goto normal_inner_ref;
+
+    case COMPONENT_REF:
+      /* If the operand is a CONSTRUCTOR, we can just extract the
+        appropriate field if it is present.  */
+      if (TREE_CODE (treeop0) == CONSTRUCTOR)
+       {
+         unsigned HOST_WIDE_INT idx;
+         tree field, value;
+
+         FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (treeop0),
+                                   idx, field, value)
+           if (field == treeop1
+               /* 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,
+                  we must mask only the number of bits in the bitfield,
+                  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 (field)
+                   || ((GET_MODE_CLASS (DECL_MODE (field)) == MODE_INT)
+                       && (GET_MODE_BITSIZE (DECL_MODE (field))
+                           <= HOST_BITS_PER_WIDE_INT))))
+             {
+               if (DECL_BIT_FIELD (field)
+                   && modifier == EXPAND_STACK_PARM)
+                 target = 0;
+               op0 = expand_expr (value, target, tmode, modifier);
+               if (DECL_BIT_FIELD (field))
+                 {
+                   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 (field)))
+                     {
+                       op1 = GEN_INT (((HOST_WIDE_INT) 1 << bitsize) - 1);
+                       op0 = expand_and (imode, op0, op1, target);
+                     }
+                   else
+                     {
+                       int count = GET_MODE_BITSIZE (imode) - bitsize;
+
+                       op0 = expand_shift (LSHIFT_EXPR, imode, op0, count,
+                                           target, 0);
+                       op0 = expand_shift (RSHIFT_EXPR, imode, op0, count,
+                                           target, 0);
+                     }
+                 }
+
+               return op0;
+             }
+       }
+      goto normal_inner_ref;
+
+    case BIT_FIELD_REF:
+    case ARRAY_RANGE_REF:
+    normal_inner_ref:
+      {
+       enum machine_mode mode1, mode2;
+       HOST_WIDE_INT bitsize, bitpos;
+       tree offset;
+       int volatilep = 0, must_force_mem;
+       bool packedp = false;
+       tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
+                                       &mode1, &unsignedp, &volatilep, true);
+       rtx orig_op0, memloc;
+
+       /* If we got back the original object, something is wrong.  Perhaps
+          we are evaluating an expression too early.  In any event, don't
+          infinitely recurse.  */
+       gcc_assert (tem != exp);
+
+       if (TYPE_PACKED (TREE_TYPE (TREE_OPERAND (exp, 0)))
+           || (TREE_CODE (TREE_OPERAND (exp, 1)) == FIELD_DECL
+               && DECL_PACKED (TREE_OPERAND (exp, 1))))
+         packedp = true;
+
+       /* If TEM's type is a union of variable size, pass TARGET to the inner
+          computation, since it will need a temporary and TARGET is known
+          to have to do.  This occurs in unchecked conversion in Ada.  */
+       orig_op0 = op0
+         = expand_expr (tem,
+                        (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
+                         && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
+                             != INTEGER_CST)
+                         && modifier != EXPAND_STACK_PARM
+                         ? target : NULL_RTX),
+                        VOIDmode,
+                        (modifier == EXPAND_INITIALIZER
+                         || modifier == EXPAND_CONST_ADDRESS
+                         || modifier == EXPAND_STACK_PARM)
+                        ? modifier : EXPAND_NORMAL);
+
+
+       /* If the bitfield is volatile, we want to access it in the
+          field's mode, not the computed mode.
+          If a MEM has VOIDmode (external with incomplete type),
+          use BLKmode for it instead.  */
+       if (MEM_P (op0))
+         {
+           if (volatilep && flag_strict_volatile_bitfields > 0)
+             op0 = adjust_address (op0, mode1, 0);
+           else if (GET_MODE (op0) == VOIDmode)
+             op0 = adjust_address (op0, BLKmode, 0);
+         }
+
+       mode2
+         = CONSTANT_P (op0) ? TYPE_MODE (TREE_TYPE (tem)) : GET_MODE (op0);
+
+       /* If we have either an offset, a BLKmode result, or a reference
+          outside the underlying object, we must force it to memory.
+          Such a case can occur in Ada if we have unchecked conversion
+          of an expression from a scalar type to an aggregate type or
+          for an ARRAY_RANGE_REF whose type is BLKmode, or if we were
+          passed a partially uninitialized object or a view-conversion
+          to a larger size.  */
+       must_force_mem = (offset
+                         || mode1 == BLKmode
+                         || bitpos + bitsize > GET_MODE_BITSIZE (mode2));
+
+       /* Handle CONCAT first.  */
+       if (GET_CODE (op0) == CONCAT && !must_force_mem)
+         {
+           if (bitpos == 0
+               && bitsize == GET_MODE_BITSIZE (GET_MODE (op0)))
+             return op0;
+           if (bitpos == 0
+               && bitsize == GET_MODE_BITSIZE (GET_MODE (XEXP (op0, 0)))
+               && bitsize)
+             {
+               op0 = XEXP (op0, 0);
+               mode2 = GET_MODE (op0);
+             }
+           else if (bitpos == GET_MODE_BITSIZE (GET_MODE (XEXP (op0, 0)))
+                    && bitsize == GET_MODE_BITSIZE (GET_MODE (XEXP (op0, 1)))
+                    && bitpos
+                    && bitsize)
+             {
+               op0 = XEXP (op0, 1);
+               bitpos = 0;
+               mode2 = GET_MODE (op0);
+             }
+           else
+             /* Otherwise force into memory.  */
+             must_force_mem = 1;
+         }
+
+       /* If this is a constant, put it in a register if it is a legitimate
+          constant and we don't need a memory reference.  */
+       if (CONSTANT_P (op0)
+           && mode2 != BLKmode
+           && targetm.legitimate_constant_p (mode2, op0)
+           && !must_force_mem)
+         op0 = force_reg (mode2, op0);
+
+       /* Otherwise, if this is a constant, try to force it to the constant
+          pool.  Note that back-ends, e.g. MIPS, may refuse to do so if it
+          is a legitimate constant.  */
+       else if (CONSTANT_P (op0) && (memloc = force_const_mem (mode2, op0)))
+         op0 = validize_mem (memloc);
+
+       /* Otherwise, if this is a constant or the object is not in memory
+          and need be, put it there.  */
+       else if (CONSTANT_P (op0) || (!MEM_P (op0) && must_force_mem))
+         {
+           tree nt = build_qualified_type (TREE_TYPE (tem),
+                                           (TYPE_QUALS (TREE_TYPE (tem))
+                                            | TYPE_QUAL_CONST));
+           memloc = assign_temp (nt, 1, 1, 1);
+           emit_move_insn (memloc, op0);
+           op0 = memloc;
+         }
+
+       if (offset)
+         {
+           enum machine_mode address_mode;
+           rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode,
+                                         EXPAND_SUM);
+
+           gcc_assert (MEM_P (op0));
+
+           address_mode
+             = targetm.addr_space.address_mode (MEM_ADDR_SPACE (op0));
+           if (GET_MODE (offset_rtx) != address_mode)
+             offset_rtx = convert_to_mode (address_mode, offset_rtx, 0);
+
+           if (GET_MODE (op0) == BLKmode
+               /* A constant address in OP0 can have VOIDmode, we must
+                  not try to call force_reg in that case.  */
+               && GET_MODE (XEXP (op0, 0)) != VOIDmode
+               && bitsize != 0
+               && (bitpos % bitsize) == 0
+               && (bitsize % GET_MODE_ALIGNMENT (mode1)) == 0
+               && MEM_ALIGN (op0) == GET_MODE_ALIGNMENT (mode1))
+             {
+               op0 = adjust_address (op0, mode1, bitpos / BITS_PER_UNIT);
+               bitpos = 0;
+             }
+
+           op0 = offset_address (op0, offset_rtx,
+                                 highest_pow2_factor (offset));
+         }
+
+       /* If OFFSET is making OP0 more aligned than BIGGEST_ALIGNMENT,
+          record its alignment as BIGGEST_ALIGNMENT.  */
+       if (MEM_P (op0) && bitpos == 0 && offset != 0
+           && is_aligning_offset (offset, tem))
+         set_mem_align (op0, BIGGEST_ALIGNMENT);
+
+       /* Don't forget about volatility even if this is a bitfield.  */
+       if (MEM_P (op0) && volatilep && ! MEM_VOLATILE_P (op0))
+         {
+           if (op0 == orig_op0)
+             op0 = copy_rtx (op0);
+
+           MEM_VOLATILE_P (op0) = 1;
+         }
+
+       /* In cases where an aligned union has an unaligned object
+          as a field, we might be extracting a BLKmode value from
+          an integer-mode (e.g., SImode) object.  Handle this case
+          by doing the extract into an object as wide as the field
+          (which we know to be the width of a basic mode), then
+          storing into memory, and changing the mode to BLKmode.  */
+       if (mode1 == VOIDmode
+           || REG_P (op0) || GET_CODE (op0) == SUBREG
+           || (mode1 != BLKmode && ! direct_load[(int) mode1]
+               && GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
+               && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT
+               && modifier != EXPAND_CONST_ADDRESS
+               && modifier != EXPAND_INITIALIZER)
+           /* If the field is volatile, we always want an aligned
+              access.  Only do this if the access is not already naturally
+              aligned, otherwise "normal" (non-bitfield) volatile fields
+              become non-addressable.  */
+           || (volatilep && flag_strict_volatile_bitfields > 0
+               && (bitpos % GET_MODE_ALIGNMENT (mode) != 0))
+           /* If the field isn't aligned enough to fetch as a memref,
+              fetch it as a bit field.  */
+           || (mode1 != BLKmode
+               && (((TYPE_ALIGN (TREE_TYPE (tem)) < GET_MODE_ALIGNMENT (mode)
+                     || (bitpos % GET_MODE_ALIGNMENT (mode) != 0)
+                     || (MEM_P (op0)
+                         && (MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (mode1)
+                             || (bitpos % GET_MODE_ALIGNMENT (mode1) != 0))))
+                    && ((modifier == EXPAND_CONST_ADDRESS
+                         || modifier == EXPAND_INITIALIZER)
+                        ? STRICT_ALIGNMENT
+                        : SLOW_UNALIGNED_ACCESS (mode1, MEM_ALIGN (op0))))
+                   || (bitpos % BITS_PER_UNIT != 0)))
+           /* If the type and the field are a constant size and the
+              size of the type isn't the same size as the bitfield,
+              we must use bitfield operations.  */
+           || (bitsize >= 0
+               && TYPE_SIZE (TREE_TYPE (exp))
+               && TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) == INTEGER_CST
+               && 0 != compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)),
+                                         bitsize)))
+         {
+           enum machine_mode ext_mode = mode;
+
+           if (ext_mode == BLKmode
+               && ! (target != 0 && MEM_P (op0)
+                     && MEM_P (target)
+                     && bitpos % BITS_PER_UNIT == 0))
+             ext_mode = mode_for_size (bitsize, MODE_INT, 1);
+
+           if (ext_mode == BLKmode)
+             {
+               if (target == 0)
+                 target = assign_temp (type, 0, 1, 1);
+
+               if (bitsize == 0)
+                 return target;
+
+               /* In this case, BITPOS must start at a byte boundary and
+                  TARGET, if specified, must be a MEM.  */
+               gcc_assert (MEM_P (op0)
+                           && (!target || MEM_P (target))
+                           && !(bitpos % BITS_PER_UNIT));
+
+               emit_block_move (target,
+                                adjust_address (op0, VOIDmode,
+                                                bitpos / BITS_PER_UNIT),
+                                GEN_INT ((bitsize + BITS_PER_UNIT - 1)
+                                         / BITS_PER_UNIT),
+                                (modifier == EXPAND_STACK_PARM
+                                 ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
+
+               return target;
+             }
+
+           op0 = validize_mem (op0);
+
+           if (MEM_P (op0) && REG_P (XEXP (op0, 0)))
+             mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
+
+           op0 = extract_bit_field (op0, bitsize, bitpos, unsignedp, packedp,
+                                    (modifier == EXPAND_STACK_PARM
+                                     ? NULL_RTX : target),
+                                    ext_mode, ext_mode);
+
+           /* If the result is a record type and BITSIZE is narrower than
+              the mode of OP0, an integral mode, and this is a big endian
+              machine, we must put the field into the high-order bits.  */
+           if (TREE_CODE (type) == RECORD_TYPE && BYTES_BIG_ENDIAN
+               && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
+               && bitsize < (HOST_WIDE_INT) GET_MODE_BITSIZE (GET_MODE (op0)))
+             op0 = expand_shift (LSHIFT_EXPR, GET_MODE (op0), op0,
+                                 GET_MODE_BITSIZE (GET_MODE (op0))
+                                 - bitsize, op0, 1);
+
+           /* If the result type is BLKmode, store the data into a temporary
+              of the appropriate type, but with the mode corresponding to the
+              mode for the data we have (op0's mode).  It's tempting to make
+              this a constant type, since we know it's only being stored once,
+              but that can cause problems if we are taking the address of this
+              COMPONENT_REF because the MEM of any reference via that address
+              will have flags corresponding to the type, which will not
+              necessarily be constant.  */
+           if (mode == BLKmode)
+             {
+               HOST_WIDE_INT size = GET_MODE_BITSIZE (ext_mode);
+               rtx new_rtx;
+
+               /* 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_rtx = assign_stack_local (ext_mode, size, 0);
+                   set_mem_alias_set (new_rtx, get_alias_set (exp));
+                 }
+               else
+                 new_rtx = assign_stack_temp_for_type (ext_mode, size, 0, type);
+
+               emit_move_insn (new_rtx, op0);
+               op0 = copy_rtx (new_rtx);
+               PUT_MODE (op0, BLKmode);
+               set_mem_attributes (op0, exp, 1);
+             }
+
+           return op0;
+         }
+
+       /* If the result is BLKmode, use that to access the object
+          now as well.  */
+       if (mode == BLKmode)
+         mode1 = BLKmode;
+
+       /* Get a reference to just this component.  */
+       if (modifier == EXPAND_CONST_ADDRESS
+           || modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
+         op0 = adjust_address_nv (op0, mode1, bitpos / BITS_PER_UNIT);
+       else
+         op0 = adjust_address (op0, mode1, bitpos / BITS_PER_UNIT);
+
+       if (op0 == orig_op0)
+         op0 = copy_rtx (op0);
+
+       set_mem_attributes (op0, exp, 0);
+       if (REG_P (XEXP (op0, 0)))
+         mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
 
-      if (! REG_P (target))
-       target = gen_reg_rtx (mode);
+       MEM_VOLATILE_P (op0) |= volatilep;
+       if (mode == mode1 || mode1 == BLKmode || mode1 == tmode
+           || modifier == EXPAND_CONST_ADDRESS
+           || modifier == EXPAND_INITIALIZER)
+         return op0;
+       else if (target == 0)
+         target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
 
-      /* If op1 was placed in target, swap op0 and op1.  */
-      if (target != op0 && target == op1)
-       {
-         temp = op0;
-         op0 = op1;
-         op1 = temp;
-       }
+       convert_move (target, op0, unsignedp);
+       return target;
+      }
 
-      /* We generate better code and avoid problems with op1 mentioning
-        target by forcing op1 into a pseudo if it isn't a constant.  */
-      if (! CONSTANT_P (op1))
-       op1 = force_reg (mode, op1);
+    case OBJ_TYPE_REF:
+      return expand_expr (OBJ_TYPE_REF_EXPR (exp), target, tmode, modifier);
 
+    case CALL_EXPR:
+      /* 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);
       {
-       enum rtx_code comparison_code;
-       rtx cmpop1 = op1;
+       tree fndecl = get_callee_fndecl (exp), attr;
 
-       if (code == MAX_EXPR)
-         comparison_code = unsignedp ? GEU : GE;
-       else
-         comparison_code = unsignedp ? LEU : LE;
+       if (fndecl
+           && (attr = lookup_attribute ("error",
+                                        DECL_ATTRIBUTES (fndecl))) != NULL)
+         error ("%Kcall to %qs declared with attribute error: %s",
+                exp, identifier_to_locale (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_at (tree_nonartificial_location (exp),
+                     0, "%Kcall to %qs declared with attribute warning: %s",
+                     exp, identifier_to_locale (lang_hooks.decl_printable_name (fndecl, 1)),
+                     TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr))));
 
-       /* 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)
+       /* Check for a built-in function.  */
+       if (fndecl && DECL_BUILT_IN (fndecl))
          {
-           /* 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;
+           gcc_assert (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_FRONTEND);
+           return expand_builtin (exp, target, subtarget, tmode, ignore);
          }
-#ifdef HAVE_conditional_move
-       /* Use a conditional move if possible.  */
-       if (can_conditionally_move_p (mode))
-         {
-           rtx insn;
+      }
+      return expand_call (exp, target, ignore);
 
-           /* ??? 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 ();
+    case VIEW_CONVERT_EXPR:
+      op0 = NULL_RTX;
 
-           start_sequence ();
+      /* If we are converting to BLKmode, try to avoid an intermediate
+        temporary by fetching an inner memory reference.  */
+      if (mode == BLKmode
+         && TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) == INTEGER_CST
+         && TYPE_MODE (TREE_TYPE (treeop0)) != BLKmode
+         && handled_component_p (treeop0))
+      {
+       enum machine_mode mode1;
+       HOST_WIDE_INT bitsize, bitpos;
+       tree offset;
+       int unsignedp;
+       int volatilep = 0;
+       tree tem
+         = get_inner_reference (treeop0, &bitsize, &bitpos,
+                                &offset, &mode1, &unsignedp, &volatilep,
+                                true);
+       rtx orig_op0;
 
-           /* Try to emit the conditional move.  */
-           insn = emit_conditional_move (target, comparison_code,
-                                         op0, cmpop1, mode,
-                                         op0, op1, mode,
-                                         unsignedp);
+       /* ??? We should work harder and deal with non-zero offsets.  */
+       if (!offset
+           && (bitpos % BITS_PER_UNIT) == 0
+           && bitsize >= 0
+           && compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)), bitsize) == 0)
+         {
+           /* See the normal_inner_ref case for the rationale.  */
+           orig_op0
+             = expand_expr (tem,
+                            (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
+                             && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
+                                 != INTEGER_CST)
+                             && modifier != EXPAND_STACK_PARM
+                             ? target : NULL_RTX),
+                            VOIDmode,
+                            (modifier == EXPAND_INITIALIZER
+                             || modifier == EXPAND_CONST_ADDRESS
+                             || modifier == EXPAND_STACK_PARM)
+                            ? modifier : EXPAND_NORMAL);
 
-           /* If we could do the conditional move, emit the sequence,
-              and return.  */
-           if (insn)
+           if (MEM_P (orig_op0))
              {
-               rtx seq = get_insns ();
-               end_sequence ();
-               emit_insn (seq);
-               return target;
-             }
+               op0 = orig_op0;
 
-           /* Otherwise discard the sequence and fall back to code with
-              branches.  */
-           end_sequence ();
-         }
-#endif
-       if (target != op0)
-         emit_move_insn (target, op0);
+               /* Get a reference to just this component.  */
+               if (modifier == EXPAND_CONST_ADDRESS
+                   || modifier == EXPAND_SUM
+                   || modifier == EXPAND_INITIALIZER)
+                 op0 = adjust_address_nv (op0, mode, bitpos / BITS_PER_UNIT);
+               else
+                 op0 = adjust_address (op0, mode, bitpos / BITS_PER_UNIT);
 
-       temp = gen_label_rtx ();
-       do_compare_rtx_and_jump (target, cmpop1, comparison_code,
-                                unsignedp, mode, NULL_RTX, NULL_RTX, temp);
+               if (op0 == orig_op0)
+                 op0 = copy_rtx (op0);
+
+               set_mem_attributes (op0, treeop0, 0);
+               if (REG_P (XEXP (op0, 0)))
+                 mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
+
+               MEM_VOLATILE_P (op0) |= volatilep;
+             }
+         }
       }
-      emit_move_insn (target, op1);
-      emit_label (temp);
-      return target;
 
-    case BIT_NOT_EXPR:
-      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);
-      gcc_assert (temp);
-      return temp;
+      if (!op0)
+       op0 = expand_expr (treeop0,
+                          NULL_RTX, VOIDmode, modifier);
 
-      /* ??? Can optimize bitwise operations with one arg constant.
-        Can optimize (a bitwise1 n) bitwise2 (a bitwise3 b)
-        and (a bitwise1 b) bitwise2 b (etc)
-        but that is probably not worth while.  */
+      /* If the input and output modes are both the same, we are done.  */
+      if (mode == GET_MODE (op0))
+       ;
+      /* If neither mode is BLKmode, and both modes are the same size
+        then we can use gen_lowpart.  */
+      else if (mode != BLKmode && GET_MODE (op0) != BLKmode
+              && GET_MODE_SIZE (mode) == GET_MODE_SIZE (GET_MODE (op0))
+              && !COMPLEX_MODE_P (GET_MODE (op0)))
+       {
+         if (GET_CODE (op0) == SUBREG)
+           op0 = force_reg (GET_MODE (op0), op0);
+         temp = gen_lowpart_common (mode, op0);
+         if (temp)
+           op0 = temp;
+         else
+           {
+             if (!REG_P (op0) && !MEM_P (op0))
+               op0 = force_reg (GET_MODE (op0), op0);
+             op0 = gen_lowpart (mode, op0);
+           }
+       }
+      /* If both types are integral, convert from one mode to the other.  */
+      else if (INTEGRAL_TYPE_P (type) && INTEGRAL_TYPE_P (TREE_TYPE (treeop0)))
+       op0 = convert_modes (mode, GET_MODE (op0), op0,
+                            TYPE_UNSIGNED (TREE_TYPE (treeop0)));
+      /* 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 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 (treeop0);
 
-      /* BIT_AND_EXPR is for bitwise anding.  TRUTH_AND_EXPR is for anding two
-        boolean values when we want in all cases to compute both of them.  In
-        general it is fastest to do TRUTH_AND_EXPR by computing both operands
-        as actual zero-or-1 values and then bitwise anding.  In cases where
-        there cannot be any side effects, better code would be made by
-        treating TRUTH_AND_EXPR like TRUTH_ANDIF_EXPR; but the question is
-        how to recognize those cases.  */
+         gcc_assert (!TREE_ADDRESSABLE (exp));
 
-    case TRUTH_AND_EXPR:
-      code = BIT_AND_EXPR;
-    case BIT_AND_EXPR:
-      goto binop;
+         if (target == 0 || GET_MODE (target) != TYPE_MODE (inner_type))
+           target
+             = assign_stack_temp_for_type
+               (TYPE_MODE (inner_type),
+                GET_MODE_SIZE (TYPE_MODE (inner_type)), 0, inner_type);
 
-    case TRUTH_OR_EXPR:
-      code = BIT_IOR_EXPR;
-    case BIT_IOR_EXPR:
-      goto binop;
+         emit_move_insn (target, op0);
+         op0 = target;
+       }
 
-    case TRUTH_XOR_EXPR:
-      code = BIT_XOR_EXPR;
-    case BIT_XOR_EXPR:
-      goto binop;
+      /* At this point, OP0 is in the correct mode.  If the output type is
+        such that the operand is known to be aligned, indicate that it is.
+        Otherwise, we need only be concerned about alignment for non-BLKmode
+        results.  */
+      if (MEM_P (op0))
+       {
+         op0 = copy_rtx (op0);
 
-    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 */
+         if (TYPE_ALIGN_OK (type))
+           set_mem_align (op0, MAX (MEM_ALIGN (op0), TYPE_ALIGN (type)));
+         else if (STRICT_ALIGNMENT
+                  && mode != BLKmode
+                  && MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (mode))
+           {
+             tree inner_type = TREE_TYPE (treeop0);
+             HOST_WIDE_INT temp_size
+               = MAX (int_size_in_bytes (inner_type),
+                      (HOST_WIDE_INT) GET_MODE_SIZE (mode));
+             rtx new_rtx
+               = assign_stack_temp_for_type (mode, temp_size, 0, type);
+             rtx new_with_op0_mode
+               = adjust_address (new_rtx, GET_MODE (op0), 0);
+
+             gcc_assert (!TREE_ADDRESSABLE (exp));
+
+             if (GET_MODE (op0) == BLKmode)
+               emit_block_move (new_with_op0_mode, op0,
+                                GEN_INT (GET_MODE_SIZE (mode)),
+                                (modifier == EXPAND_STACK_PARM
+                                 ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
+             else
+               emit_move_insn (new_with_op0_mode, op0);
 
-    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;
+             op0 = new_rtx;
+           }
 
-      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, 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;
+         op0 = adjust_address (op0, mode, 0);
+       }
 
-      /* Could determine the answer when only additive constants differ.  Also,
-        the addition of one can be handled by changing the condition.  */
-    case LT_EXPR:
-    case LE_EXPR:
-    case GT_EXPR:
-    case GE_EXPR:
-    case EQ_EXPR:
-    case NE_EXPR:
-    case UNORDERED_EXPR:
-    case ORDERED_EXPR:
-    case UNLT_EXPR:
-    case UNLE_EXPR:
-    case UNGT_EXPR:
-    case UNGE_EXPR:
-    case UNEQ_EXPR:
-    case LTGT_EXPR:
-      temp = do_store_flag (exp,
-                           modifier != EXPAND_STACK_PARM ? target : NULL_RTX,
-                           tmode != VOIDmode ? tmode : mode);
-      if (temp)
-       return temp;
+      return op0;
 
       /* Use a compare and a jump for BLKmode comparisons, or for function
         type comparisons is HAVE_canonicalize_funcptr_for_compare.  */
@@ -9122,7 +9514,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       if (! ignore
          && (target == 0
              || modifier == EXPAND_STACK_PARM
-             || ! safe_from_p (target, exp, 1)
+             || ! safe_from_p (target, treeop0, 1)
+             || ! safe_from_p (target, treeop1, 1)
              /* Make sure we don't have a hard reg (such as function's return
                 value) live across basic blocks, if not optimizing.  */
              || (!optimize && REG_P (target)
@@ -9133,7 +9526,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
        emit_move_insn (target, const0_rtx);
 
       op1 = gen_label_rtx ();
-      jumpifnot (exp, op1);
+      jumpifnot_1 (code, treeop0, treeop1, op1, -1);
 
       if (target)
        emit_move_insn (target, const1_rtx);
@@ -9141,18 +9534,6 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       emit_label (op1);
       return ignore ? const0_rtx : target;
 
-    case TRUTH_NOT_EXPR:
-      if (modifier == EXPAND_STACK_PARM)
-       target = 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,
-                          target, 1, OPTAB_LIB_WIDEN);
-      gcc_assert (temp);
-      return temp;
-
     case STATEMENT_LIST:
       {
        tree_stmt_iterator iter;
@@ -9168,7 +9549,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       /* A COND_EXPR with its type being VOID_TYPE represents a
         conditional jump and is handled in
         expand_gimple_cond_expr.  */
-      gcc_assert (!VOID_TYPE_P (TREE_TYPE (exp)));
+      gcc_assert (!VOID_TYPE_P (type));
 
         /* Note that COND_EXPRs whose type is a structure or union
         are required to be constructed to contain assignments of
@@ -9177,8 +9558,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
         gcc_assert (!TREE_ADDRESSABLE (type)
                    && !ignore
-                   && TREE_TYPE (TREE_OPERAND (exp, 1)) != void_type_node
-                   && TREE_TYPE (TREE_OPERAND (exp, 2)) != void_type_node);
+                   && TREE_TYPE (treeop1) != void_type_node
+                   && TREE_TYPE (treeop2) != void_type_node);
 
        /* If we are not to produce a result, we have no target.  Otherwise,
         if a target was specified use it; it will not be used as an
@@ -9187,7 +9568,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
        if (modifier != EXPAND_STACK_PARM
          && original_target
-         && safe_from_p (original_target, TREE_OPERAND (exp, 0), 1)
+         && safe_from_p (original_target, treeop0, 1)
          && GET_MODE (original_target) == mode
 #ifdef HAVE_conditional_move
          && (! can_conditionally_move_p (mode)
@@ -9202,15 +9583,15 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
        NO_DEFER_POP;
        op0 = gen_label_rtx ();
        op1 = gen_label_rtx ();
-       jumpifnot (TREE_OPERAND (exp, 0), op0);
-       store_expr (TREE_OPERAND (exp, 1), temp,
+       jumpifnot (treeop0, op0, -1);
+       store_expr (treeop1, temp,
                  modifier == EXPAND_STACK_PARM,
                  false);
 
        emit_jump_insn (gen_jump (op1));
        emit_barrier ();
        emit_label (op0);
-       store_expr (TREE_OPERAND (exp, 2), temp,
+       store_expr (treeop2, temp,
                  modifier == EXPAND_STACK_PARM,
                  false);
 
@@ -9219,13 +9600,13 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
        return temp;
 
     case VEC_COND_EXPR:
-       target = expand_vec_cond_expr (exp, target);
-       return target;
+      target = expand_vec_cond_expr (type, treeop0, treeop1, treeop2, target);
+      return target;
 
     case MODIFY_EXPR:
       {
-       tree lhs = TREE_OPERAND (exp, 0);
-       tree rhs = TREE_OPERAND (exp, 1);
+       tree lhs = treeop0;
+       tree rhs = treeop1;
        gcc_assert (ignore);
 
        /* Check for |= or &= of a bitfield of size one into another bitfield
@@ -9248,7 +9629,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
            int value = TREE_CODE (rhs) == BIT_IOR_EXPR;
            do_jump (TREE_OPERAND (rhs, 1),
                     value ? label : 0,
-                    value ? 0 : label);
+                    value ? 0 : label, -1);
            expand_assignment (lhs, build_int_cst (TREE_TYPE (rhs), value),
                               MOVE_NONTEMPORAL (exp));
            do_pending_stack_adjust ();
@@ -9260,41 +9641,24 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
        return const0_rtx;
       }
 
-    case RETURN_EXPR:
-      if (!TREE_OPERAND (exp, 0))
-       expand_null_return ();
-      else
-       expand_return (TREE_OPERAND (exp, 0));
-      return const0_rtx;
-
     case ADDR_EXPR:
       return expand_expr_addr_expr (exp, target, tmode, modifier);
 
-    case COMPLEX_EXPR:
-      /* Get the rtx code of the operands.  */
-      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)));
-
-      /* Move the real (op0) and imaginary (op1) parts to their location.  */
-      write_complex_part (target, op0, false);
-      write_complex_part (target, op1, true);
-
-      return target;
-
     case REALPART_EXPR:
-      op0 = expand_normal (TREE_OPERAND (exp, 0));
+      op0 = expand_normal (treeop0);
       return read_complex_part (op0, false);
 
     case IMAGPART_EXPR:
-      op0 = expand_normal (TREE_OPERAND (exp, 0));
+      op0 = expand_normal (treeop0);
       return read_complex_part (op0, true);
 
-    case RESX_EXPR:
-      expand_resx_expr (exp);
-      return const0_rtx;
+    case RETURN_EXPR:
+    case LABEL_EXPR:
+    case GOTO_EXPR:
+    case SWITCH_EXPR:
+    case ASM_EXPR:
+      /* Expanded in cfgexpand.c.  */
+      gcc_unreachable ();
 
     case TRY_CATCH_EXPR:
     case CATCH_EXPR:
@@ -9321,164 +9685,17 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       /* Lowered by gimplify.c.  */
       gcc_unreachable ();
 
-    case EXC_PTR_EXPR:
-      return get_exception_pointer ();
-
-    case FILTER_EXPR:
-      return get_exception_filter ();
-
     case FDESC_EXPR:
       /* Function descriptors are not valid except for as
         initialization constants, and should not be expanded.  */
       gcc_unreachable ();
 
-    case SWITCH_EXPR:
-      expand_case (exp);
-      return const0_rtx;
-
-    case LABEL_EXPR:
-      expand_label (TREE_OPERAND (exp, 0));
-      return const0_rtx;
-
-    case ASM_EXPR:
-      expand_asm_expr (exp);
-      return const0_rtx;
-
     case WITH_SIZE_EXPR:
       /* WITH_SIZE_EXPR expands to its first argument.  The caller should
         have pulled out the size to use in whatever context it needed.  */
-      return expand_expr_real (TREE_OPERAND (exp, 0), original_target, tmode,
+      return expand_expr_real (treeop0, original_target, tmode,
                               modifier, alt_rtl);
 
-    case REALIGN_LOAD_EXPR:
-      {
-        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, 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);
-        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, EXPAND_NORMAL);
-        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, EXPAND_NORMAL);
-        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, EXPAND_NORMAL);
-        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, EXPAND_NORMAL);
-       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 COMPOUND_LITERAL_EXPR:
       {
        /* Initialize the anonymous variable declared in the compound
@@ -9501,24 +9718,9 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       }
 
     default:
-      gcc_unreachable ();
+      return expand_expr_real_2 (&ops, target, tmode, modifier);
     }
-
-  /* Here to do an ordinary binary operator.  */
- binop:
-  expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
-                  subtarget, &op0, &op1, EXPAND_NORMAL);
- binop2:
-  this_optab = optab_for_tree_code (code, type, optab_default);
- binop3:
-  if (modifier == EXPAND_STACK_PARM)
-    target = 0;
-  temp = expand_binop (mode, this_optab, op0, op1, target,
-                      unsignedp, OPTAB_LIB_WIDEN);
-  gcc_assert (temp);
-  return REDUCE_BIT_FIELD (temp);
 }
-#undef REDUCE_BIT_FIELD
 \f
 /* Subroutine of above: reduce EXP to the precision of TYPE (in the
    signedness of TYPE), possibly returning the result in TARGET.  */
@@ -9537,23 +9739,17 @@ reduce_to_bit_field_precision (rtx exp, rtx target, tree type)
     }
   else if (TYPE_UNSIGNED (type))
     {
-      rtx mask;
-      if (prec < HOST_BITS_PER_WIDE_INT)
-       mask = immed_double_const (((unsigned HOST_WIDE_INT) 1 << prec) - 1, 0,
-                                  GET_MODE (exp));
-      else
-       mask = immed_double_const ((unsigned HOST_WIDE_INT) -1,
-                                  ((unsigned HOST_WIDE_INT) 1
-                                   << (prec - HOST_BITS_PER_WIDE_INT)) - 1,
-                                  GET_MODE (exp));
+      rtx mask = immed_double_int_const (double_int_mask (prec),
+                                        GET_MODE (exp));
       return expand_and (GET_MODE (exp), exp, mask, target);
     }
   else
     {
-      tree count = build_int_cst (NULL_TREE,
-                                 GET_MODE_BITSIZE (GET_MODE (exp)) - prec);
-      exp = expand_shift (LSHIFT_EXPR, GET_MODE (exp), exp, count, target, 0);
-      return expand_shift (RSHIFT_EXPR, GET_MODE (exp), exp, count, target, 0);
+      int count = GET_MODE_BITSIZE (GET_MODE (exp)) - prec;
+      exp = expand_shift (LSHIFT_EXPR, GET_MODE (exp),
+                         exp, count, target, 0);
+      return expand_shift (RSHIFT_EXPR, GET_MODE (exp),
+                          exp, count, target, 0);
     }
 }
 \f
@@ -9675,21 +9871,17 @@ string_constant (tree arg, tree *ptr_offset)
       *ptr_offset = fold_convert (sizetype, offset);
       return array;
     }
-  else if (TREE_CODE (array) == VAR_DECL)
+  else if (TREE_CODE (array) == VAR_DECL
+          || TREE_CODE (array) == CONST_DECL)
     {
       int length;
 
       /* Variables initialized to string literals can be handled too.  */
-      if (DECL_INITIAL (array) == NULL_TREE
+      if (!const_value_known_p (array)
+         || !DECL_INITIAL (array)
          || TREE_CODE (DECL_INITIAL (array)) != STRING_CST)
        return 0;
 
-      /* If they are read-only, non-volatile and bind locally.  */
-      if (! TREE_READONLY (array)
-         || TREE_SIDE_EFFECTS (array)
-         || ! targetm.binds_local_p (array))
-       return 0;
-
       /* Avoid const char foo[4] = "abcde";  */
       if (DECL_SIZE_UNIT (array) == NULL_TREE
          || TREE_CODE (DECL_SIZE_UNIT (array)) != INTEGER_CST
@@ -9712,8 +9904,9 @@ string_constant (tree arg, tree *ptr_offset)
   return 0;
 }
 \f
-/* Generate code to calculate EXP using a store-flag instruction
-   and return an rtx for the result.  EXP is a comparison.
+/* Generate code to calculate OPS, and exploded expression
+   using a store-flag instruction and return an rtx for the result.
+   OPS reflects a comparison.
 
    If TARGET is nonzero, store the result there if convenient.
 
@@ -9729,7 +9922,7 @@ string_constant (tree arg, tree *ptr_offset)
    set/jump/set sequence.  */
 
 static rtx
-do_store_flag (tree exp, rtx target, enum machine_mode mode)
+do_store_flag (sepops ops, rtx target, enum machine_mode mode)
 {
   enum rtx_code code;
   tree arg0, arg1, type;
@@ -9738,10 +9931,10 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode)
   int unsignedp;
   rtx op0, op1;
   rtx subtarget = target;
-  location_t loc = EXPR_LOCATION (exp);
+  location_t loc = ops->location;
 
-  arg0 = TREE_OPERAND (exp, 0);
-  arg1 = TREE_OPERAND (exp, 1);
+  arg0 = ops->op0;
+  arg1 = ops->op1;
 
   /* Don't crash if the comparison was erroneous.  */
   if (arg0 == error_mark_node || arg1 == error_mark_node)
@@ -9760,11 +9953,11 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode)
      when function pointers must be canonicalized before comparisons.  */
 #ifdef HAVE_canonicalize_funcptr_for_compare
   if (HAVE_canonicalize_funcptr_for_compare
-      && ((TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == POINTER_TYPE
-          && (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))))
+      && ((TREE_CODE (TREE_TYPE (arg0)) == POINTER_TYPE
+          && (TREE_CODE (TREE_TYPE (TREE_TYPE (arg0)))
               == FUNCTION_TYPE))
-         || (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 1))) == POINTER_TYPE
-             && (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 1))))
+         || (TREE_CODE (TREE_TYPE (arg1)) == POINTER_TYPE
+             && (TREE_CODE (TREE_TYPE (TREE_TYPE (arg1)))
                  == FUNCTION_TYPE))))
     return 0;
 #endif
@@ -9779,7 +9972,7 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode)
      tests will not catch constants in the first operand, but constants
      are rarely passed as the first operand.  */
 
-  switch (TREE_CODE (exp))
+  switch (ops->code)
     {
     case EQ_EXPR:
       code = EQ;
@@ -9860,7 +10053,8 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode)
 
   if ((code == NE || code == EQ)
       && TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1)
-      && integer_pow2p (TREE_OPERAND (arg0, 1)))
+      && integer_pow2p (TREE_OPERAND (arg0, 1))
+      && (TYPE_PRECISION (ops->type) != 1 || TYPE_UNSIGNED (ops->type)))
     {
       tree type = lang_hooks.types.type_for_mode (mode, unsignedp);
       return expand_expr (fold_single_bit_test (loc,
@@ -9880,7 +10074,9 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode)
 
   /* Try a cstore if possible.  */
   return emit_store_flag_force (target, code, op0, op1,
-                               operand_mode, unsignedp, 1);
+                               operand_mode, unsignedp,
+                               (TYPE_PRECISION (ops->type) == 1
+                                && !TYPE_UNSIGNED (ops->type)) ? -1 : 1);
 }
 \f
 
@@ -9898,10 +10094,10 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range,
            rtx table_label ATTRIBUTE_UNUSED, rtx default_label,
            rtx fallback_label ATTRIBUTE_UNUSED)
 {
+  struct expand_operand ops[5];
   enum machine_mode index_mode = SImode;
   int index_bits = GET_MODE_BITSIZE (index_mode);
   rtx op1, op2, index;
-  enum machine_mode op_mode;
 
   if (! HAVE_casesi)
     return 0;
@@ -9936,32 +10132,17 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range,
 
   do_pending_stack_adjust ();
 
-  op_mode = insn_data[(int) CODE_FOR_casesi].operand[0].mode;
-  if (! (*insn_data[(int) CODE_FOR_casesi].operand[0].predicate)
-      (index, op_mode))
-    index = copy_to_mode_reg (op_mode, index);
-
   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)),
-                      op1, TYPE_UNSIGNED (TREE_TYPE (minval)));
-  if (! (*insn_data[(int) CODE_FOR_casesi].operand[1].predicate)
-      (op1, op_mode))
-    op1 = copy_to_mode_reg (op_mode, op1);
-
   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)),
-                      op2, TYPE_UNSIGNED (TREE_TYPE (range)));
-  if (! (*insn_data[(int) CODE_FOR_casesi].operand[2].predicate)
-      (op2, op_mode))
-    op2 = copy_to_mode_reg (op_mode, op2);
-
-  emit_jump_insn (gen_casesi (index, op1, op2,
-                             table_label, !default_label
-                                          ? fallback_label : default_label));
+  create_input_operand (&ops[0], index, index_mode);
+  create_convert_operand_from_type (&ops[1], op1, TREE_TYPE (minval));
+  create_convert_operand_from_type (&ops[2], op2, TREE_TYPE (range));
+  create_fixed_operand (&ops[3], table_label);
+  create_fixed_operand (&ops[4], (default_label
+                                 ? default_label
+                                 : fallback_label));
+  expand_jump_insn (CODE_FOR_casesi, 5, ops);
   return 1;
 }
 
@@ -10066,39 +10247,6 @@ try_tablejump (tree index_type, tree index_expr, tree minval, tree range,
   return 1;
 }
 
-/* Nonzero if the mode is a valid vector mode for this architecture.
-   This returns nonzero even if there is no hardware support for the
-   vector mode, but we can emulate with narrower modes.  */
-
-int
-vector_mode_valid_p (enum machine_mode mode)
-{
-  enum mode_class mclass = GET_MODE_CLASS (mode);
-  enum machine_mode innermode;
-
-  /* Doh!  What's going on?  */
-  if (mclass != MODE_VECTOR_INT
-      && mclass != MODE_VECTOR_FLOAT
-      && mclass != MODE_VECTOR_FRACT
-      && mclass != MODE_VECTOR_UFRACT
-      && mclass != MODE_VECTOR_ACCUM
-      && mclass != MODE_VECTOR_UACCUM)
-    return 0;
-
-  /* Hardware support.  Woo hoo!  */
-  if (targetm.vector_mode_supported_p (mode))
-    return 1;
-
-  innermode = GET_MODE_INNER (mode);
-
-  /* We should probably return 1 if requesting V4DI and we have no DI,
-     but we have V2DI, but this is probably very unlikely.  */
-
-  /* If we have support for the inner mode, we can safely emulate it.
-     We may not have V2DI, but me can emulate with a pair of DIs.  */
-  return targetm.scalar_mode_supported_p (innermode);
-}
-
 /* Return a CONST_VECTOR rtx for a VECTOR_CST tree.  */
 static rtx
 const_vector_from_tree (tree exp)
@@ -10130,9 +10278,8 @@ const_vector_from_tree (tree exp)
        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),
-                                              inner);
+       RTVEC_ELT (v, i) = immed_double_int_const (tree_to_double_int (elt),
+                                                  inner);
     }
 
   /* Initialize remaining elements to 0.  */
@@ -10141,4 +10288,70 @@ const_vector_from_tree (tree exp)
 
   return gen_rtx_CONST_VECTOR (mode, v);
 }
+
+/* Build a decl for a personality function given a language prefix.  */
+
+tree
+build_personality_function (const char *lang)
+{
+  const char *unwind_and_version;
+  tree decl, type;
+  char *name;
+
+  switch (targetm.except_unwind_info (&global_options))
+    {
+    case UI_NONE:
+      return NULL;
+    case UI_SJLJ:
+      unwind_and_version = "_sj0";
+      break;
+    case UI_DWARF2:
+    case UI_TARGET:
+      unwind_and_version = "_v0";
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  name = ACONCAT (("__", lang, "_personality", unwind_and_version, NULL));
+
+  type = build_function_type_list (integer_type_node, integer_type_node,
+                                  long_long_unsigned_type_node,
+                                  ptr_type_node, ptr_type_node, NULL_TREE);
+  decl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL,
+                    get_identifier (name), type);
+  DECL_ARTIFICIAL (decl) = 1;
+  DECL_EXTERNAL (decl) = 1;
+  TREE_PUBLIC (decl) = 1;
+
+  /* Zap the nonsensical SYMBOL_REF_DECL for this.  What we're left with
+     are the flags assigned by targetm.encode_section_info.  */
+  SET_SYMBOL_REF_DECL (XEXP (DECL_RTL (decl), 0), NULL);
+
+  return decl;
+}
+
+/* Extracts the personality function of DECL and returns the corresponding
+   libfunc.  */
+
+rtx
+get_personality_function (tree decl)
+{
+  tree personality = DECL_FUNCTION_PERSONALITY (decl);
+  enum eh_personality_kind pk;
+
+  pk = function_needs_eh_personality (DECL_STRUCT_FUNCTION (decl));
+  if (pk == eh_personality_none)
+    return NULL;
+
+  if (!personality
+      && pk == eh_personality_any)
+    personality = lang_hooks.eh_personality ();
+
+  if (pk == eh_personality_lang)
+    gcc_assert (personality != NULL_TREE);
+
+  return XEXP (DECL_RTL (personality), 0);
+}
+
 #include "gt-expr.h"