OSDN Git Service

PR middle-end/44337
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index e7c24e2..6b2feb6 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
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
    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"
@@ -54,6 +52,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "timevar.h"
 #include "df.h"
 #include "diagnostic.h"
+#include "ssaexpand.h"
 
 /* Decide whether a function's arguments should be processed
    from first to last or from last to first.
@@ -90,7 +89,7 @@ int cse_not_expected;
 
 /* This structure is used by move_by_pieces to describe the move to
    be performed.  */
-struct move_by_pieces
+struct move_by_pieces_d
 {
   rtx to;
   rtx to_addr;
@@ -108,7 +107,7 @@ struct move_by_pieces
 /* This structure is used by store_by_pieces to describe the clear to
    be performed.  */
 
-struct store_by_pieces
+struct store_by_pieces_d
 {
   rtx to;
   rtx to_addr;
@@ -125,16 +124,16 @@ static unsigned HOST_WIDE_INT move_by_pieces_ninsns (unsigned HOST_WIDE_INT,
                                                     unsigned int,
                                                     unsigned int);
 static void move_by_pieces_1 (rtx (*) (rtx, ...), enum machine_mode,
-                             struct move_by_pieces *);
+                             struct move_by_pieces_d *);
 static bool block_move_libcall_safe_for_call_parm (void);
 static bool emit_block_move_via_movmem (rtx, rtx, rtx, unsigned, unsigned, HOST_WIDE_INT);
 static tree emit_block_move_libcall_fn (int);
 static void emit_block_move_via_loop (rtx, rtx, rtx, unsigned);
 static rtx clear_by_pieces_1 (void *, HOST_WIDE_INT, enum machine_mode);
 static void clear_by_pieces (rtx, unsigned HOST_WIDE_INT, unsigned int);
-static void store_by_pieces_1 (struct store_by_pieces *, unsigned int);
+static void store_by_pieces_1 (struct store_by_pieces_d *, unsigned int);
 static void store_by_pieces_2 (rtx (*) (rtx, ...), enum machine_mode,
-                              struct store_by_pieces *);
+                              struct store_by_pieces_d *);
 static tree clear_storage_libcall_fn (int);
 static rtx compress_float_constant (rtx, rtx);
 static rtx get_subtarget (rtx);
@@ -151,7 +150,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, int);
+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
@@ -175,7 +174,7 @@ static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
 #ifndef MOVE_BY_PIECES_P
 #define MOVE_BY_PIECES_P(SIZE, ALIGN) \
   (move_by_pieces_ninsns (SIZE, ALIGN, MOVE_MAX_PIECES + 1) \
-   < (unsigned int) MOVE_RATIO)
+   < (unsigned int) MOVE_RATIO (optimize_insn_for_speed_p ()))
 #endif
 
 /* This macro is used to determine whether clear_by_pieces should be
@@ -183,7 +182,7 @@ static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
 #ifndef CLEAR_BY_PIECES_P
 #define CLEAR_BY_PIECES_P(SIZE, ALIGN) \
   (move_by_pieces_ninsns (SIZE, ALIGN, STORE_MAX_PIECES + 1) \
-   < (unsigned int) CLEAR_RATIO)
+   < (unsigned int) CLEAR_RATIO (optimize_insn_for_speed_p ()))
 #endif
 
 /* This macro is used to determine whether store_by_pieces should be
@@ -191,7 +190,7 @@ static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
 #ifndef SET_BY_PIECES_P
 #define SET_BY_PIECES_P(SIZE, ALIGN) \
   (move_by_pieces_ninsns (SIZE, ALIGN, STORE_MAX_PIECES + 1) \
-   < (unsigned int) SET_RATIO)
+   < (unsigned int) SET_RATIO (optimize_insn_for_speed_p ()))
 #endif
 
 /* This macro is used to determine whether store_by_pieces should be
@@ -199,7 +198,7 @@ static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
 #ifndef STORE_BY_PIECES_P
 #define STORE_BY_PIECES_P(SIZE, ALIGN) \
   (move_by_pieces_ninsns (SIZE, ALIGN, STORE_MAX_PIECES + 1) \
-   < (unsigned int) MOVE_RATIO)
+   < (unsigned int) MOVE_RATIO (optimize_insn_for_speed_p ()))
 #endif
 
 /* This array records the insn_code of insns to perform block moves.  */
@@ -234,7 +233,6 @@ enum insn_code sync_new_and_optab[NUM_MACHINE_MODES];
 enum insn_code sync_new_xor_optab[NUM_MACHINE_MODES];
 enum insn_code sync_new_nand_optab[NUM_MACHINE_MODES];
 enum insn_code sync_compare_and_swap[NUM_MACHINE_MODES];
-enum insn_code sync_compare_and_swap_cc[NUM_MACHINE_MODES];
 enum insn_code sync_lock_test_and_set[NUM_MACHINE_MODES];
 enum insn_code sync_lock_release[NUM_MACHINE_MODES];
 
@@ -268,7 +266,7 @@ init_expr_target (void)
   reg = gen_rtx_REG (VOIDmode, -1);
 
   insn = rtx_alloc (INSN);
-  pat = gen_rtx_SET (0, NULL_RTX, NULL_RTX);
+  pat = gen_rtx_SET (VOIDmode, NULL_RTX, NULL_RTX);
   PATTERN (insn) = pat;
 
   for (mode = VOIDmode; (int) mode < NUM_MACHINE_MODES;
@@ -588,27 +586,9 @@ convert_move (rtx to, rtx from, int unsignedp)
       if (unsignedp)
        fill_value = const0_rtx;
       else
-       {
-#ifdef HAVE_slt
-         if (HAVE_slt
-             && insn_data[(int) CODE_FOR_slt].operand[0].mode == word_mode
-             && STORE_FLAG_VALUE == -1)
-           {
-             emit_cmp_insn (lowfrom, const0_rtx, NE, NULL_RTX,
-                            lowpart_mode, 0);
-             fill_value = gen_reg_rtx (word_mode);
-             emit_insn (gen_slt (fill_value));
-           }
-         else
-#endif
-           {
-             fill_value
-               = expand_shift (RSHIFT_EXPR, lowpart_mode, lowfrom,
-                               size_int (GET_MODE_BITSIZE (lowpart_mode) - 1),
-                               NULL_RTX, 0);
-             fill_value = convert_to_mode (word_mode, fill_value, 1);
-           }
-       }
+       fill_value = emit_store_flag (gen_reg_rtx (word_mode),
+                                     LT, lowfrom, const0_rtx,
+                                     VOIDmode, 0, -1);
 
       /* Fill the remaining words.  */
       for (i = GET_MODE_SIZE (lowpart_mode) / UNITS_PER_WORD; i < nwords; i++)
@@ -790,20 +770,15 @@ convert_modes (enum machine_mode mode, enum machine_mode oldmode, rtx x, int uns
 
   if (unsignedp && GET_MODE_CLASS (mode) == MODE_INT
       && GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT
-      && GET_CODE (x) == CONST_INT && INTVAL (x) < 0)
+      && CONST_INT_P (x) && INTVAL (x) < 0)
     {
-      HOST_WIDE_INT val = INTVAL (x);
+      double_int val = uhwi_to_double_int (INTVAL (x));
 
-      if (oldmode != VOIDmode
-         && HOST_BITS_PER_WIDE_INT > GET_MODE_BITSIZE (oldmode))
-       {
-         int width = GET_MODE_BITSIZE (oldmode);
-
-         /* 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
@@ -811,7 +786,7 @@ convert_modes (enum machine_mode mode, enum machine_mode oldmode, rtx x, int uns
      non-volatile MEM.  Except for the constant case where MODE is no
      wider than HOST_BITS_PER_WIDE_INT, we must be narrowing the operand.  */
 
-  if ((GET_CODE (x) == CONST_INT
+  if ((CONST_INT_P (x)
        && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
       || (GET_MODE_CLASS (mode) == MODE_INT
          && GET_MODE_CLASS (oldmode) == MODE_INT
@@ -828,7 +803,7 @@ convert_modes (enum machine_mode mode, enum machine_mode oldmode, rtx x, int uns
       /* ?? If we don't know OLDMODE, we have to assume here that
         X does not need sign- or zero-extension.   This may not be
         the case, but it's the best we can do.  */
-      if (GET_CODE (x) == CONST_INT && oldmode != VOIDmode
+      if (CONST_INT_P (x) && oldmode != VOIDmode
          && GET_MODE_SIZE (mode) > GET_MODE_SIZE (oldmode))
        {
          HOST_WIDE_INT val = INTVAL (x);
@@ -894,7 +869,9 @@ rtx
 move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len,
                unsigned int align, int endp)
 {
-  struct move_by_pieces data;
+  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;
@@ -906,6 +883,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
@@ -916,6 +894,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;
@@ -951,32 +930,34 @@ move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len,
 
       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);
@@ -1031,7 +1012,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,
@@ -1106,7 +1088,7 @@ move_by_pieces_ninsns (unsigned HOST_WIDE_INT l, unsigned int align,
 
 static void
 move_by_pieces_1 (rtx (*genfun) (rtx, ...), enum machine_mode mode,
-                 struct move_by_pieces *data)
+                 struct move_by_pieces_d *data)
 {
   unsigned int size = GET_MODE_SIZE (mode);
   rtx to1 = NULL_RTX, from1;
@@ -1205,6 +1187,7 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method,
     }
 
   align = MIN (MEM_ALIGN (x), MEM_ALIGN (y));
+  gcc_assert (align >= BITS_PER_UNIT);
 
   gcc_assert (MEM_P (x));
   gcc_assert (MEM_P (y));
@@ -1217,7 +1200,7 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method,
 
   /* Set MEM_SIZE as appropriate for this block copy.  The main place this
      can be incorrect is coming from __builtin_memcpy.  */
-  if (GET_CODE (size) == CONST_INT)
+  if (CONST_INT_P (size))
     {
       if (INTVAL (size) == 0)
        return 0;
@@ -1228,12 +1211,14 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method,
       set_mem_size (y, size);
     }
 
-  if (GET_CODE (size) == CONST_INT && MOVE_BY_PIECES_P (INTVAL (size), align))
+  if (CONST_INT_P (size) && MOVE_BY_PIECES_P (INTVAL (size), align))
     move_by_pieces (x, y, INTVAL (size), align, 0);
   else if (emit_block_move_via_movmem (x, y, size, align,
                                       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
@@ -1270,6 +1255,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;
@@ -1331,7 +1319,7 @@ emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align,
             here because if SIZE is less than the mode mask, as it is
             returned by the macro, it will definitely be less than the
             actual mode mask.  */
-         && ((GET_CODE (size) == CONST_INT
+         && ((CONST_INT_P (size)
               && ((unsigned HOST_WIDE_INT) INTVAL (size)
                   <= (GET_MODE_MASK (mode) >> 1)))
              || GET_MODE_BITSIZE (mode) >= BITS_PER_WORD)
@@ -1442,7 +1430,7 @@ init_block_move_fn (const char *asmspec)
                                       const_ptr_type_node, sizetype,
                                       NULL_TREE);
 
-      fn = build_decl (FUNCTION_DECL, fn, args);
+      fn = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL, fn, args);
       DECL_EXTERNAL (fn) = 1;
       TREE_PUBLIC (fn) = 1;
       DECL_ARTIFICIAL (fn) = 1;
@@ -1484,6 +1472,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);
@@ -1503,9 +1495,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);
 
@@ -2039,10 +2035,55 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
       HOST_WIDE_INT bytepos = INTVAL (XEXP (XVECEXP (src, 0, i), 1));
       enum machine_mode mode = GET_MODE (tmps[i]);
       unsigned int bytelen = GET_MODE_SIZE (mode);
+      unsigned int adj_bytelen = bytelen;
       rtx dest = dst;
 
       /* Handle trailing fragments that run over the size of the struct.  */
       if (ssize >= 0 && bytepos + (HOST_WIDE_INT) bytelen > ssize)
+       adj_bytelen = ssize - bytepos;
+
+      if (GET_CODE (dst) == CONCAT)
+       {
+         if (bytepos + adj_bytelen
+             <= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0))))
+           dest = XEXP (dst, 0);
+         else if (bytepos >= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0))))
+           {
+             bytepos -= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0)));
+             dest = XEXP (dst, 1);
+           }
+         else
+           {
+             enum machine_mode dest_mode = GET_MODE (dest);
+             enum machine_mode tmp_mode = GET_MODE (tmps[i]);
+
+             gcc_assert (bytepos == 0 && XVECLEN (src, 0));
+
+             if (GET_MODE_ALIGNMENT (dest_mode)
+                 >= GET_MODE_ALIGNMENT (tmp_mode))
+               {
+                 dest = assign_stack_temp (dest_mode,
+                                           GET_MODE_SIZE (dest_mode),
+                                           0);
+                 emit_move_insn (adjust_address (dest,
+                                                 tmp_mode,
+                                                 bytepos),
+                                 tmps[i]);
+                 dst = dest;
+               }
+             else
+               {
+                 dest = assign_stack_temp (tmp_mode,
+                                           GET_MODE_SIZE (tmp_mode),
+                                           0);
+                 emit_move_insn (dest, tmps[i]);
+                 dst = adjust_address (dest, dest_mode, bytepos);
+               }
+             break;
+           }
+       }
+
+      if (ssize >= 0 && bytepos + (HOST_WIDE_INT) bytelen > ssize)
        {
          /* store_bit_field always takes its value from the lsb.
             Move the fragment to the lsb if it's not already there.  */
@@ -2060,28 +2101,7 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
                                      build_int_cst (NULL_TREE, shift),
                                      tmps[i], 0);
            }
-         bytelen = ssize - bytepos;
-       }
-
-      if (GET_CODE (dst) == CONCAT)
-       {
-         if (bytepos + bytelen <= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0))))
-           dest = XEXP (dst, 0);
-         else if (bytepos >= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0))))
-           {
-             bytepos -= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0)));
-             dest = XEXP (dst, 1);
-           }
-         else
-           {
-             gcc_assert (bytepos == 0 && XVECLEN (src, 0));
-             dest = assign_stack_temp (GET_MODE (dest),
-                                       GET_MODE_SIZE (GET_MODE (dest)), 0);
-             emit_move_insn (adjust_address (dest, GET_MODE (tmps[i]), bytepos),
-                             tmps[i]);
-             dst = dest;
-             break;
-           }
+         bytelen = adj_bytelen;
        }
 
       /* Optimize the access just a bit.  */
@@ -2243,6 +2263,26 @@ use_group_regs (rtx *call_fusage, rtx regs)
        use_reg (call_fusage, reg);
     }
 }
+
+/* Return the defining gimple statement for SSA_NAME NAME if it is an
+   assigment and the code of the expresion on the RHS is CODE.  Return
+   NULL otherwise.  */
+
+static gimple
+get_def_for_expr (tree name, enum tree_code code)
+{
+  gimple def_stmt;
+
+  if (TREE_CODE (name) != SSA_NAME)
+    return NULL;
+
+  def_stmt = get_gimple_for_ssa_name (name);
+  if (!def_stmt
+      || gimple_assign_rhs_code (def_stmt) != code)
+    return NULL;
+
+  return def_stmt;
+}
 \f
 
 /* Determine whether the LEN bytes generated by CONSTFUN can be
@@ -2268,7 +2308,7 @@ can_store_by_pieces (unsigned HOST_WIDE_INT len,
   if (len == 0)
     return 1;
 
-  if (! (memsetp 
+  if (! (memsetp
         ? SET_BY_PIECES_P (len, align)
         : STORE_BY_PIECES_P (len, align)))
     return 0;
@@ -2356,7 +2396,9 @@ 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)
 {
-  struct store_by_pieces data;
+  enum machine_mode to_addr_mode
+    = targetm.addr_space.address_mode (MEM_ADDR_SPACE (to));
+  struct store_by_pieces_d data;
 
   if (len == 0)
     {
@@ -2384,7 +2426,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,
@@ -2408,7 +2451,7 @@ store_by_pieces (rtx to, unsigned HOST_WIDE_INT len,
 static void
 clear_by_pieces (rtx to, unsigned HOST_WIDE_INT len, unsigned int align)
 {
-  struct store_by_pieces data;
+  struct store_by_pieces_d data;
 
   if (len == 0)
     return;
@@ -2436,9 +2479,11 @@ clear_by_pieces_1 (void *data ATTRIBUTE_UNUSED,
    rtx with BLKmode).  ALIGN is maximum alignment we can assume.  */
 
 static void
-store_by_pieces_1 (struct store_by_pieces *data ATTRIBUTE_UNUSED,
+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;
@@ -2470,7 +2515,8 @@ store_by_pieces_1 (struct store_by_pieces *data ATTRIBUTE_UNUSED,
 
       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;
        }
@@ -2478,13 +2524,13 @@ store_by_pieces_1 (struct store_by_pieces *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);
@@ -2534,7 +2580,7 @@ store_by_pieces_1 (struct store_by_pieces *data ATTRIBUTE_UNUSED,
 
 static void
 store_by_pieces_2 (rtx (*genfun) (rtx, ...), enum machine_mode mode,
-                  struct store_by_pieces *data)
+                  struct store_by_pieces_d *data)
 {
   unsigned int size = GET_MODE_SIZE (mode);
   rtx to1, cst;
@@ -2582,7 +2628,7 @@ clear_storage_hints (rtx object, rtx size, enum block_op_methods method,
   /* If OBJECT is not BLKmode and SIZE is the same size as its mode,
      just move a zero.  Otherwise, do this a piece at a time.  */
   if (mode != BLKmode
-      && GET_CODE (size) == CONST_INT
+      && CONST_INT_P (size)
       && INTVAL (size) == (HOST_WIDE_INT) GET_MODE_SIZE (mode))
     {
       rtx zero = CONST0_RTX (mode);
@@ -2609,15 +2655,17 @@ clear_storage_hints (rtx object, rtx size, enum block_op_methods method,
 
   align = MEM_ALIGN (object);
 
-  if (GET_CODE (size) == CONST_INT
+  if (CONST_INT_P (size)
       && CLEAR_BY_PIECES_P (INTVAL (size), align))
     clear_by_pieces (object, INTVAL (size), align);
   else if (set_storage_via_setmem (object, size, const0_rtx, align,
                                   expected_align, expected_size))
     ;
-  else
+  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;
 }
@@ -2655,14 +2703,13 @@ set_storage_via_libcall (rtx object, rtx size, rtx val, bool tailcall)
      for returning pointers, we could end up generating incorrect code.  */
 
   object_tree = make_tree (ptr_type_node, object);
-  if (GET_CODE (val) != CONST_INT)
+  if (!CONST_INT_P (val))
     val = convert_to_mode (TYPE_MODE (integer_type_node), val, 1);
   size_tree = make_tree (sizetype, size);
   val_tree = make_tree (integer_type_node, val);
 
   fn = clear_storage_libcall_fn (true);
-  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);
@@ -2674,7 +2721,7 @@ set_storage_via_libcall (rtx object, rtx size, rtx val, bool tailcall)
    for the function we use for block clears.  The first time FOR_CALL
    is true, we call assemble_external.  */
 
-static GTY(()) tree block_clear_fn;
+tree block_clear_fn;
 
 void
 init_block_clear_fn (const char *asmspec)
@@ -2688,7 +2735,7 @@ init_block_clear_fn (const char *asmspec)
                                       integer_type_node, sizetype,
                                       NULL_TREE);
 
-      fn = build_decl (FUNCTION_DECL, fn, args);
+      fn = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL, fn, args);
       DECL_EXTERNAL (fn) = 1;
       TREE_PUBLIC (fn) = 1;
       DECL_ARTIFICIAL (fn) = 1;
@@ -2748,7 +2795,7 @@ set_storage_via_setmem (rtx object, rtx size, rtx val, unsigned int align,
             BITS_PER_HOST_WIDE_INT here because if SIZE is less than
             the mode mask, as it is returned by the macro, it will
             definitely be less than the actual mode mask.  */
-         && ((GET_CODE (size) == CONST_INT
+         && ((CONST_INT_P (size)
               && ((unsigned HOST_WIDE_INT) INTVAL (size)
                   <= (GET_MODE_MASK (mode) >> 1)))
              || GET_MODE_BITSIZE (mode) >= BITS_PER_WORD)
@@ -3020,7 +3067,7 @@ emit_move_resolve_push (enum machine_mode mode, rtx x)
       HOST_WIDE_INT val;
 
       gcc_assert (GET_CODE (expr) == PLUS || GET_CODE (expr) == MINUS);
-      gcc_assert (GET_CODE (XEXP (expr, 1)) == CONST_INT);
+      gcc_assert (CONST_INT_P (XEXP (expr, 1)));
       val = INTVAL (XEXP (expr, 1));
       if (GET_CODE (expr) == MINUS)
        val = -val;
@@ -3406,12 +3453,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);
@@ -3439,13 +3488,14 @@ compress_float_constant (rtx x, rtx y)
   enum machine_mode srcmode;
   REAL_VALUE_TYPE r;
   int oldcost, newcost;
+  bool speed = optimize_insn_for_speed_p ();
 
   REAL_VALUE_FROM_CONST_DOUBLE (r, y);
 
   if (LEGITIMATE_CONSTANT_P (y))
-    oldcost = rtx_cost (y, SET);
+    oldcost = rtx_cost (y, SET, speed);
   else
-    oldcost = rtx_cost (force_const_mem (dstmode, y), SET);
+    oldcost = rtx_cost (force_const_mem (dstmode, y), SET, speed);
 
   for (srcmode = GET_CLASS_NARROWEST_MODE (GET_MODE_CLASS (orig_srcmode));
        srcmode != orig_srcmode;
@@ -3472,7 +3522,7 @@ compress_float_constant (rtx x, rtx y)
          if (! (*insn_data[ic].operand[1].predicate) (trunc_y, srcmode))
            continue;
          /* This is valid, but may not be cheaper than the original. */
-         newcost = rtx_cost (gen_rtx_FLOAT_EXTEND (dstmode, trunc_y), SET);
+         newcost = rtx_cost (gen_rtx_FLOAT_EXTEND (dstmode, trunc_y), SET, speed);
          if (oldcost < newcost)
            continue;
        }
@@ -3480,7 +3530,7 @@ compress_float_constant (rtx x, rtx y)
        {
          trunc_y = force_const_mem (srcmode, trunc_y);
          /* This is valid, but may not be cheaper than the original. */
-         newcost = rtx_cost (gen_rtx_FLOAT_EXTEND (dstmode, trunc_y), SET);
+         newcost = rtx_cost (gen_rtx_FLOAT_EXTEND (dstmode, trunc_y), SET, speed);
          if (oldcost < newcost)
            continue;
          trunc_y = validize_mem (trunc_y);
@@ -3545,7 +3595,7 @@ push_block (rtx size, int extra, int below)
     }
   else
     {
-      if (GET_CODE (size) == CONST_INT)
+      if (CONST_INT_P (size))
        temp = plus_constant (virtual_outgoing_args_rtx,
                              -INTVAL (size) - (below ? 0 : extra));
       else if (extra != 0 && !below)
@@ -3756,7 +3806,7 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
         on the stack for alignment purposes.  */
       if (args_addr == 0
          && PUSH_ARGS
-         && GET_CODE (size) == CONST_INT
+         && CONST_INT_P (size)
          && skip == 0
          && MEM_ALIGN (xinner) >= align
          && (MOVE_BY_PIECES_P ((unsigned) INTVAL (size) - used, align))
@@ -3789,7 +3839,7 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
          /* Deduct words put into registers from the size we must copy.  */
          if (partial != 0)
            {
-             if (GET_CODE (size) == CONST_INT)
+             if (CONST_INT_P (size))
                size = GEN_INT (INTVAL (size) - used);
              else
                size = expand_binop (GET_MODE (size), sub_optab, size,
@@ -3805,7 +3855,7 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
              temp = push_block (size, extra, where_pad == downward);
              extra = 0;
            }
-         else if (GET_CODE (args_so_far) == CONST_INT)
+         else if (CONST_INT_P (args_so_far))
            temp = memory_address (BLKmode,
                                   plus_constant (args_addr,
                                                  skip + INTVAL (args_so_far)));
@@ -3921,7 +3971,7 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
       else
 #endif
        {
-         if (GET_CODE (args_so_far) == CONST_INT)
+         if (CONST_INT_P (args_so_far))
            addr
              = memory_address (mode,
                                plus_constant (args_addr,
@@ -4181,6 +4231,7 @@ expand_assignment (tree to, tree from, bool nontemporal)
 
       if (offset != 0)
        {
+         enum machine_mode address_mode;
          rtx offset_rtx;
 
          if (!MEM_P (to_rtx))
@@ -4193,13 +4244,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.  */
@@ -4220,10 +4268,21 @@ 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 (TREE_CODE (TREE_TYPE (from)) == COMPLEX_TYPE)
+         if (COMPLEX_MODE_P (TYPE_MODE (TREE_TYPE (from))))
            {
              gcc_assert (bitpos == 0);
              result = store_expr (from, to_rtx, false, nontemporal);
@@ -4269,6 +4328,41 @@ expand_assignment (tree to, tree from, bool nontemporal)
       return;
     }
 
+   else if (TREE_CODE (to) == MISALIGNED_INDIRECT_REF)
+     {
+       addr_space_t as = ADDR_SPACE_GENERIC;
+       enum machine_mode mode, op_mode1;
+       enum insn_code icode;
+       rtx reg, addr, mem, insn;
+
+       if (POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (to, 0))))
+        as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (to, 0))));
+
+       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_addr_space (mode, addr, as);
+       mem = gen_rtx_MEM (mode, addr);
+
+       set_mem_attributes (mem, to, 0);
+       set_mem_addr_space (mem, as);
+
+       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
@@ -4278,11 +4372,13 @@ expand_assignment (tree to, tree from, bool nontemporal)
      Don't do this if TO is a VAR_DECL or PARM_DECL whose DECL_RTL is REG
      since it might be a promoted variable where the zero- or sign- extension
      needs to be done.  Handling this in the normal way is safe because no
-     computation is done before the call.  */
+     computation is done before the call.  The same is true for SSA names.  */
   if (TREE_CODE (from) == CALL_EXPR && ! aggregate_value_p (from, from)
+      && COMPLETE_TYPE_P (TREE_TYPE (from))
       && TREE_CODE (TYPE_SIZE (TREE_TYPE (from))) == INTEGER_CST
-      && ! ((TREE_CODE (to) == VAR_DECL || TREE_CODE (to) == PARM_DECL)
-           && REG_P (DECL_RTL (to))))
+      && ! (((TREE_CODE (to) == VAR_DECL || TREE_CODE (to) == PARM_DECL)
+            && REG_P (DECL_RTL (to)))
+           || TREE_CODE (to) == SSA_NAME))
     {
       rtx value;
 
@@ -4301,7 +4397,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);
@@ -4340,7 +4439,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)
     {
@@ -4376,7 +4479,7 @@ 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;
@@ -4418,7 +4521,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
@@ -4426,7 +4529,7 @@ 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)))
     {
@@ -4457,7 +4560,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));
@@ -4502,13 +4605,13 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
                  (TYPE_MODE (TREE_TYPE (exp)),
                   SUBREG_PROMOTED_UNSIGNED_P (target));
 
-             exp = fold_convert (ntype, exp);
+             exp = fold_convert_loc (loc, ntype, exp);
            }
 
-         exp = fold_convert (lang_hooks.types.type_for_mode
-                               (GET_MODE (SUBREG_REG (target)),
-                                SUBREG_PROMOTED_UNSIGNED_P (target)),
-                             exp);
+         exp = fold_convert_loc (loc, lang_hooks.types.type_for_mode
+                                 (GET_MODE (SUBREG_REG (target)),
+                                  SUBREG_PROMOTED_UNSIGNED_P (target)),
+                                 exp);
 
          inner_target = SUBREG_REG (target);
        }
@@ -4586,19 +4689,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
@@ -4647,15 +4737,7 @@ 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
+         if (GET_MODE (target) == BLKmode
                   || GET_MODE (temp) == BLKmode)
            emit_block_move (target, temp, expr_size (exp),
                             (call_param_p
@@ -4673,18 +4755,23 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
             type of the string, which is actually the size of the target.  */
          rtx size = expr_size (exp);
 
-         if (GET_CODE (size) == CONST_INT
+         if (CONST_INT_P (size)
              && INTVAL (size) < TREE_STRING_LENGTH (exp))
            emit_block_move (target, temp, size,
                             (call_param_p
                              ? 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 (MIN_EXPR,
-                             make_tree (sizetype, size),
-                             size_int (TREE_STRING_LENGTH (exp)));
+               = size_binop_loc (loc, MIN_EXPR,
+                                 make_tree (sizetype, size),
+                                 size_int (TREE_STRING_LENGTH (exp)));
              rtx copy_size_rtx
                = expand_expr (copy_size, NULL_RTX, VOIDmode,
                               (call_param_p
@@ -4692,15 +4779,15 @@ 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.  */
-             if (GET_CODE (copy_size_rtx) == CONST_INT)
+                Do all calculations in pointer_mode.  */
+             if (CONST_INT_P (copy_size_rtx))
                {
                  size = plus_constant (size, -INTVAL (copy_size_rtx));
                  target = adjust_address (target, BLKmode,
@@ -4712,11 +4799,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));
@@ -4779,9 +4865,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);
@@ -4843,12 +4928,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;
        }
     }
@@ -4995,6 +5085,9 @@ count_type_elements (const_tree type, bool allow_flexarr)
     case REFERENCE_TYPE:
       return 1;
 
+    case ERROR_MARK:
+      return 0;
+
     case VOID_TYPE:
     case METHOD_TYPE:
     case FUNCTION_TYPE:
@@ -5203,6 +5296,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
 
            if (offset)
              {
+               enum machine_mode address_mode;
                rtx offset_rtx;
 
                offset
@@ -5213,13 +5307,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));
@@ -5372,13 +5463,11 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
            enum machine_mode mode;
            HOST_WIDE_INT bitsize;
            HOST_WIDE_INT bitpos;
-           int unsignedp;
            rtx xtarget = target;
 
            if (cleared && initializer_zerop (value))
              continue;
 
-           unsignedp = TYPE_UNSIGNED (elttype);
            mode = TYPE_MODE (elttype);
            if (mode == BLKmode)
              bitsize = (host_integerp (TYPE_SIZE (elttype), 1)
@@ -5434,13 +5523,10 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                    tree exit_cond;
 
                    expand_normal (hi_index);
-                   unsignedp = TYPE_UNSIGNED (domain);
 
-                   index = build_decl (VAR_DECL, NULL_TREE, domain);
-
-                   index_r
-                     = gen_reg_rtx (promote_mode (domain, DECL_MODE (index),
-                                                  &unsignedp, 0));
+                   index = build_decl (EXPR_LOCATION (exp),
+                                       VAR_DECL, NULL_TREE, domain);
+                   index_r = gen_reg_rtx (promote_decl_mode (index, NULL));
                    SET_DECL_RTL (index, index_r);
                    store_expr (lo_index, index_r, 0, false);
 
@@ -5474,7 +5560,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.  */
@@ -5550,6 +5636,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
        HOST_WIDE_INT bitpos;
        rtvec vector = NULL;
        unsigned n_elts;
+       alias_set_type alias;
 
        gcc_assert (eltmode != BLKmode);
 
@@ -5601,7 +5688,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
        if (need_to_clear && size > 0 && !vector)
          {
            if (REG_P (target))
-             emit_move_insn (target,  CONST0_RTX (GET_MODE (target)));
+             emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
            else
              clear_storage (target, GEN_INT (size), BLOCK_OP_NORMAL);
            cleared = 1;
@@ -5611,6 +5698,11 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
        if (!cleared && !vector && REG_P (target))
          emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
 
+        if (MEM_P (target))
+         alias = MEM_ALIAS_SET (target);
+       else
+         alias = get_alias_set (elttype);
+
         /* Store each element of the constructor into the corresponding
           element of TARGET, determined by counting the elements.  */
        for (idx = 0, i = 0;
@@ -5646,7 +5738,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                bitpos = eltpos * elt_size;
                store_constructor_field (target, bitsize, bitpos,
                                         value_mode, value, type,
-                                        cleared, get_alias_set (elttype));
+                                        cleared, alias);
              }
          }
 
@@ -5675,7 +5767,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
@@ -5683,8 +5775,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;
 
@@ -5692,8 +5782,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
@@ -5758,22 +5846,25 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
          && compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)), bitsize) != 0))
     {
       rtx temp;
+      gimple nop_def;
 
       /* If EXP is a NOP_EXPR of precision less than its mode, then that
         implies a mask operation.  If the precision is the same size as
         the field we're storing into, that mask is redundant.  This is
         particularly common with bit field assignments generated by the
         C front end.  */
-      if (TREE_CODE (exp) == NOP_EXPR)
+      nop_def = get_def_for_expr (exp, NOP_EXPR);
+      if (nop_def)
        {
          tree type = TREE_TYPE (exp);
          if (INTEGRAL_TYPE_P (type)
              && TYPE_PRECISION (type) < GET_MODE_BITSIZE (TYPE_MODE (type))
              && bitsize == TYPE_PRECISION (type))
            {
-             type = TREE_TYPE (TREE_OPERAND (exp, 0));
+             tree op = gimple_assign_rhs1 (nop_def);
+             type = TREE_TYPE (op);
              if (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) >= bitsize)
-               exp = TREE_OPERAND (exp, 0);
+               exp = op;
            }
        }
 
@@ -5890,6 +5981,7 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
 
   /* 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);
@@ -6050,9 +6142,9 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
   return exp;
 }
 
-/* Given an expression EXP that may be a COMPONENT_REF or an ARRAY_REF,
-   look for whether EXP or any nested component-refs within EXP is marked
-   as PACKED.  */
+/* Given an expression EXP that may be a COMPONENT_REF, an ARRAY_REF or an
+   ARRAY_RANGE_REF, look for whether EXP or any nested component-refs within
+   EXP is marked as PACKED.  */
 
 bool
 contains_packed_reference (const_tree exp)
@@ -6066,7 +6158,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)
@@ -6092,13 +6184,14 @@ contains_packed_reference (const_tree exp)
 }
 
 /* Return a tree of sizetype representing the size, in bytes, of the element
-   of EXP, an ARRAY_REF.  */
+   of EXP, an ARRAY_REF or an ARRAY_RANGE_REF.  */
 
 tree
 array_ref_element_size (tree exp)
 {
   tree aligned_size = TREE_OPERAND (exp, 3);
   tree elmt_type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0)));
+  location_t loc = EXPR_LOCATION (exp);
 
   /* If a size was specified in the ARRAY_REF, it's the size measured
      in alignment units of the element type.  So multiply by that value.  */
@@ -6107,9 +6200,9 @@ array_ref_element_size (tree exp)
       /* ??? tree_ssa_useless_type_conversion will eliminate casts to
         sizetype from another type of the same width and signedness.  */
       if (TREE_TYPE (aligned_size) != sizetype)
-       aligned_size = fold_convert (sizetype, aligned_size);
-      return size_binop (MULT_EXPR, aligned_size,
-                        size_int (TYPE_ALIGN_UNIT (elmt_type)));
+       aligned_size = fold_convert_loc (loc, sizetype, aligned_size);
+      return size_binop_loc (loc, MULT_EXPR, aligned_size,
+                            size_int (TYPE_ALIGN_UNIT (elmt_type)));
     }
 
   /* Otherwise, take the size from that of the element type.  Substitute
@@ -6119,7 +6212,7 @@ array_ref_element_size (tree exp)
 }
 
 /* Return a tree representing the lower bound of the array mentioned in
-   EXP, an ARRAY_REF.  */
+   EXP, an ARRAY_REF or an ARRAY_RANGE_REF.  */
 
 tree
 array_ref_low_bound (tree exp)
@@ -6140,7 +6233,7 @@ array_ref_low_bound (tree exp)
 }
 
 /* Return a tree representing the upper bound of the array mentioned in
-   EXP, an ARRAY_REF.  */
+   EXP, an ARRAY_REF or an ARRAY_RANGE_REF.  */
 
 tree
 array_ref_up_bound (tree exp)
@@ -6164,6 +6257,7 @@ component_ref_field_offset (tree exp)
 {
   tree aligned_offset = TREE_OPERAND (exp, 2);
   tree field = TREE_OPERAND (exp, 1);
+  location_t loc = EXPR_LOCATION (exp);
 
   /* If an offset was specified in the COMPONENT_REF, it's the offset measured
      in units of DECL_OFFSET_ALIGN / BITS_PER_UNIT.  So multiply by that
@@ -6173,9 +6267,10 @@ component_ref_field_offset (tree exp)
       /* ??? tree_ssa_useless_type_conversion will eliminate casts to
         sizetype from another type of the same width and signedness.  */
       if (TREE_TYPE (aligned_offset) != sizetype)
-       aligned_offset = fold_convert (sizetype, aligned_offset);
-      return size_binop (MULT_EXPR, aligned_offset,
-                        size_int (DECL_OFFSET_ALIGN (field) / BITS_PER_UNIT));
+       aligned_offset = fold_convert_loc (loc, sizetype, aligned_offset);
+      return size_binop_loc (loc, MULT_EXPR, aligned_offset,
+                            size_int (DECL_OFFSET_ALIGN (field)
+                                      / BITS_PER_UNIT));
     }
 
   /* Otherwise, take the offset from that of the field.  Substitute
@@ -6184,26 +6279,44 @@ component_ref_field_offset (tree exp)
     return SUBSTITUTE_PLACEHOLDER_IN_EXPR (DECL_FIELD_OFFSET (field), exp);
 }
 
-/* Return 1 if T is an expression that get_inner_reference handles.  */
+/* Alignment in bits the TARGET of an assignment may be assumed to have.  */
 
-int
-handled_component_p (const_tree t)
+static unsigned HOST_WIDE_INT
+target_align (const_tree target)
 {
-  switch (TREE_CODE (t))
+  /* We might have a chain of nested references with intermediate misaligning
+     bitfields components, so need to recurse to find out.  */
+
+  unsigned HOST_WIDE_INT this_align, outer_align;
+
+  switch (TREE_CODE (target))
     {
     case BIT_FIELD_REF:
+      return 1;
+
     case COMPONENT_REF:
+      this_align = DECL_ALIGN (TREE_OPERAND (target, 1));
+      outer_align = target_align (TREE_OPERAND (target, 0));
+      return MIN (this_align, outer_align);
+
     case ARRAY_REF:
     case ARRAY_RANGE_REF:
+      this_align = TYPE_ALIGN (TREE_TYPE (target));
+      outer_align = target_align (TREE_OPERAND (target, 0));
+      return MIN (this_align, outer_align);
+
+    CASE_CONVERT:
+    case NON_LVALUE_EXPR:
     case VIEW_CONVERT_EXPR:
-    case REALPART_EXPR:
-    case IMAGPART_EXPR:
-      return 1;
+      this_align = TYPE_ALIGN (TREE_TYPE (target));
+      outer_align = target_align (TREE_OPERAND (target, 0));
+      return MAX (this_align, outer_align);
 
     default:
-      return 0;
+      return TYPE_ALIGN (TREE_TYPE (target));
     }
 }
+
 \f
 /* Given an rtx VALUE that may contain additions and multiplications, return
    an equivalent value that just refers to a register, memory, or constant.
@@ -6253,7 +6366,7 @@ force_operand (rtx value, rtx target)
       op2 = XEXP (value, 1);
       if (!CONSTANT_P (op2) && !(REG_P (op2) && op2 != subtarget))
        subtarget = 0;
-      if (code == MINUS && GET_CODE (op2) == CONST_INT)
+      if (code == MINUS && CONST_INT_P (op2))
        {
          code = PLUS;
          op2 = negate_rtx (GET_MODE (value), op2);
@@ -6265,7 +6378,7 @@ force_operand (rtx value, rtx target)
          constant first and then add the other value.  This allows virtual
          register instantiation to simply modify the constant rather than
          creating another one around this addition.  */
-      if (code == PLUS && GET_CODE (op2) == CONST_INT
+      if (code == PLUS && CONST_INT_P (op2)
          && GET_CODE (XEXP (value, 0)) == PLUS
          && REG_P (XEXP (XEXP (value, 0), 0))
          && REGNO (XEXP (XEXP (value, 0), 0)) >= FIRST_VIRTUAL_REGISTER
@@ -6539,9 +6652,6 @@ safe_from_p (const_rtx x, tree exp, int top_p)
     case tcc_type:
       /* Should never get a type here.  */
       gcc_unreachable ();
-
-    case tcc_gimple_stmt:
-      gcc_unreachable ();
     }
 
   /* If we have an rtl, find any enclosed object.  Then see if we conflict
@@ -6653,14 +6763,10 @@ highest_pow2_factor (const_tree exp)
 static unsigned HOST_WIDE_INT
 highest_pow2_factor_for_target (const_tree target, const_tree exp)
 {
-  unsigned HOST_WIDE_INT target_align, factor;
+  unsigned HOST_WIDE_INT talign = target_align (target) / BITS_PER_UNIT;
+  unsigned HOST_WIDE_INT factor = highest_pow2_factor (exp);
 
-  factor = highest_pow2_factor (exp);
-  if (TREE_CODE (target) == COMPONENT_REF)
-    target_align = DECL_ALIGN_UNIT (TREE_OPERAND (target, 1));
-  else
-    target_align = TYPE_ALIGN_UNIT (TREE_TYPE (target));
-  return MAX (factor, target_align);
+  return MAX (factor, talign);
 }
 \f
 /* Return &VAR expression for emulated thread local VAR.  */
@@ -6672,7 +6778,7 @@ emutls_var_address (tree var)
   tree fn = built_in_decls [BUILT_IN_EMUTLS_GET_ADDRESS];
   tree arg = build_fold_addr_expr_with_type (emuvar, ptr_type_node);
   tree arglist = build_tree_list (NULL_TREE, arg);
-  tree call = build_function_call_expr (fn, arglist);
+  tree call = build_function_call_expr (UNKNOWN_LOCATION, fn, arglist);
   return fold_convert (build_pointer_type (TREE_TYPE (var)), call);
 }
 \f
@@ -6724,7 +6830,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;
@@ -6749,9 +6855,8 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
       return expand_expr (TREE_OPERAND (exp, 0), 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
@@ -6789,9 +6894,10 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
         CONSTRUCTORs too, which should yield a memory reference for the
         constructor's contents.  Assume language specific tree nodes can
         be expanded in some interesting way.  */
+      gcc_assert (TREE_CODE (exp) < LAST_AND_UNUSED_TREE_CODE);
       if (DECL_P (exp)
          || TREE_CODE (exp) == CONSTRUCTOR
-         || TREE_CODE (exp) >= LAST_AND_UNUSED_TREE_CODE)
+         || TREE_CODE (exp) == COMPOUND_LITERAL_EXPR)
        {
          result = expand_expr (exp, target, tmode,
                                modifier == EXPAND_INITIALIZER
@@ -6830,7 +6936,17 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
   gcc_assert (inner != exp);
 
   subtarget = offset || bitpos ? NULL_RTX : target;
-  result = expand_expr_addr_expr_1 (inner, subtarget, tmode, modifier);
+  /* For VIEW_CONVERT_EXPR, where the outer alignment is bigger than
+     inner alignment, force the inner to be sufficiently aligned.  */
+  if (CONSTANT_CLASS_P (inner)
+      && TYPE_ALIGN (TREE_TYPE (inner)) < TYPE_ALIGN (TREE_TYPE (exp)))
+    {
+      inner = copy_node (inner);
+      TREE_TYPE (inner) = copy_node (TREE_TYPE (inner));
+      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, as);
 
   if (offset)
     {
@@ -6838,12 +6954,12 @@ 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);
@@ -6876,6 +6992,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;
 
@@ -6883,14 +7002,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
@@ -6899,7 +7025,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;
 }
@@ -7036,33 +7162,20 @@ 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
-      || TREE_CODE (exp) == PREDICT_EXPR
-      || (!GIMPLE_TUPLE_P (exp) && TREE_CODE (TREE_TYPE (exp)) == ERROR_MARK))
+      || (TREE_CODE (TREE_TYPE (exp)) == ERROR_MARK))
     {
       ret = CONST0_RTX (tmode);
       return ret ? ret : const0_rtx;
     }
 
-  if (flag_non_call_exceptions)
-    {
-      rn = lookup_stmt_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.
 
@@ -7074,6 +7187,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);
 
@@ -7083,127 +7198,67 @@ 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 = ops->location;
+  tree treeop0, treeop1;
 #define REDUCE_BIT_FIELD(expr) (reduce_bit_field                         \
                                 ? reduce_to_bit_field_precision ((expr), \
                                                                  target, \
                                                                  type)   \
                                 : (expr))
 
-  if (GIMPLE_STMT_P (exp))
-    {
-      type = void_type_node;
-      mode = VOIDmode;
-      unsignedp = 0;
-    }
-  else
-    {
-      type = TREE_TYPE (exp);
-      mode = TYPE_MODE (type);
-      unsignedp = TYPE_UNSIGNED (type);
-    }
+  type = ops->type;
+  mode = TYPE_MODE (type);
+  unsignedp = TYPE_UNSIGNED (type);
+
+  treeop0 = ops->op0;
+  treeop1 = ops->op1;
+
+  /* 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);
 
   ignore = (target == const0_rtx
-           || ((code == NOP_EXPR || code == CONVERT_EXPR 
+           || ((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 (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;
 
@@ -7213,1779 +7268,2163 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
   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:
-      return expand_expr_real_1 (SSA_NAME_VAR (exp), target, tmode, modifier,
-                                NULL);
+             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 (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);
-      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);
-
-      /* 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 (MEM_P (decl_rtl) && REG_P (XEXP (decl_rtl, 0)))
-       temp = validize_mem (decl_rtl);
+      if (mode == TYPE_MODE (TREE_TYPE (treeop0)))
+       {
+         op0 = expand_expr (treeop0, target, VOIDmode,
+                            modifier);
 
-      /* If DECL_RTL is memory, we are in the normal case and the
-        address is not valid, get the address into a register.  */
+         /* 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;
 
-      else if (MEM_P (decl_rtl) && modifier != EXPAND_INITIALIZER)
-       {
-         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)));
+         return REDUCE_BIT_FIELD (op0);
        }
 
-      /* If we got something, return it.  But first, set the alignment
-        if the address is a register.  */
-      if (temp != 0)
+      op0 = expand_expr (treeop0, NULL_RTX, mode,
+                        modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier);
+      if (GET_MODE (op0) == mode)
+       ;
+
+      /* If OP0 is a constant, just convert it into the proper mode.  */
+      else if (CONSTANT_P (op0))
        {
-         if (MEM_P (temp) && REG_P (XEXP (temp, 0)))
-           mark_reg_pointer (XEXP (temp, 0), DECL_ALIGN (exp));
+         tree inner_type = TREE_TYPE (treeop0);
+         enum machine_mode 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_mode (type, DECL_MODE (exp), &unsignedp,
-                               (TREE_CODE (exp) == RESULT_DECL
-                                || TREE_CODE (exp) == PARM_DECL) ? 1 : 0);
-         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 (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);
+
+       /* 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 CONST_DECL:
-      return expand_expr (DECL_INITIAL (exp), target, VOIDmode, modifier);
+    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:
 
-    case REAL_CST:
-      /* If optimized, generate immediate CONST_DOUBLE
-        which will be turned into memory by reload if necessary.
+      /* 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 (treeop0,
+                                             MULT_EXPR)))
+       {
+         tree subsubexp0, subsubexp1;
+         gimple subsubexp0_def, subsubexp1_def;
+         enum tree_code this_code;
 
-        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.
+         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 (treeop1, subtarget,
+                                    VOIDmode, EXPAND_NORMAL);
+                 temp = expand_ternary_op (mode, this_optab, op0, op1, op2,
+                                           target, unsignedp);
+                 gcc_assert (temp);
+                 return REDUCE_BIT_FIELD (temp);
+               }
+           }
+       }
 
-        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 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 FIXED_CST:
-      return CONST_FIXED_FROM_FIXED_VALUE (TREE_FIXED_CST (exp),
-                                          TYPE_MODE (TREE_TYPE (exp)));
+        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 COMPLEX_CST:
-      /* Handle evaluating a complex constant in a CONCAT target.  */
-      if (original_target && GET_CODE (original_target) == CONCAT)
+      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))
        {
-         enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
-         rtx rtarg, itarg;
-
-         rtarg = XEXP (original_target, 0);
-         itarg = XEXP (original_target, 1);
-
-         /* 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);
+         tree t = treeop1;
 
-         if (op0 != rtarg)
-           emit_move_insn (rtarg, op0);
-         if (op1 != itarg)
-           emit_move_insn (itarg, op1);
-
-         return original_target;
+         treeop1 = TREE_OPERAND (treeop0, 0);
+         TREE_OPERAND (treeop0, 0) = t;
        }
 
-      /* ... fall through ...  */
-
-    case STRING_CST:
-      temp = expand_expr_constant (exp, 1, modifier);
-
-      /* 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;
+      /* 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.
 
-    case SAVE_EXPR:
-      {
-       tree val = TREE_OPERAND (exp, 0);
-       rtx ret = expand_expr_real_1 (val, target, tmode, modifier, alt_rtl);
+        If this is an EXPAND_SUM call, always return the sum.  */
+      if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER
+         || (mode == ptr_mode && (unsignedp || ! flag_trapv)))
+       {
+         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;
 
-       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);
+             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);
+           }
 
-           val = build_decl (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;
+         else if (TREE_CODE (treeop1) == INTEGER_CST
+                  && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+                  && TREE_CONSTANT (treeop0))
+           {
+             rtx constant_part;
 
-           if (!CONSTANT_P (ret))
-             ret = copy_to_reg (ret);
-           SET_DECL_RTL (val, ret);
-         }
+             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 ret;
-      }
+      /* 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 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;
+      expand_operands (treeop0, treeop1,
+                      subtarget, &op0, &op1, modifier);
+      return REDUCE_BIT_FIELD (simplify_gen_binary (PLUS, mode, op0, op1));
 
-    case CONSTRUCTOR:
-      /* If we don't need the result, just ensure we evaluate any
-        subexpressions.  */
-      if (ignore)
+    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 (treeop1,
+                                             MULT_EXPR)))
        {
-         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 subsubexp0, subsubexp1;
+         gimple subsubexp0_def, subsubexp1_def;
+         enum tree_code this_code;
 
-         return const0_rtx;
+         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 (treeop0, 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 expand_constructor (exp, target, modifier, false);
+      /* 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 MISALIGNED_INDIRECT_REF:
-    case ALIGN_INDIRECT_REF:
-    case INDIRECT_REF:
-      {
-       tree exp1 = TREE_OPERAND (exp, 0);
+         /* 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 (modifier != EXPAND_WRITE)
-         {
-           tree t;
+      /* 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;
 
-           t = fold_read_from_constant_string (exp);
-           if (t)
-             return expand_expr (t, target, tmode, modifier);
-         }
+      expand_operands (treeop0, treeop1,
+                      subtarget, &op0, &op1, modifier);
 
-       op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM);
-       op0 = memory_address (mode, op0);
+      /* 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 (code == ALIGN_INDIRECT_REF)
-         {
-           int align = TYPE_ALIGN_UNIT (type);
-           op0 = gen_rtx_AND (Pmode, op0, GEN_INT (-align));
-           op0 = memory_address (mode, op0);
-         }
+      goto binop2;
 
-       temp = gen_rtx_MEM (mode, op0);
+    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)
+       {
+         tree t1 = treeop0;
+         treeop0 = treeop1;
+         treeop1 = t1;
+       }
 
-       set_mem_attributes (temp, exp, 0);
+      /* 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)->insn_code != CODE_FOR_nothing)
+               {
+                 if (TYPE_UNSIGNED (TREE_TYPE (treeop0)))
+                   expand_operands (treeop0, treeop1, subtarget, &op0, &op1,
+                                    EXPAND_NORMAL);
+                 else
+                   expand_operands (treeop0, treeop1, subtarget, &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;
 
-       /* Resolve the misalignment now, so that we don't have to remember
-          to resolve it later.  Of course, this only works for reads.  */
-       /* ??? When we get around to supporting writes, we'll have to handle
-          this in store_expr directly.  The vectorizer isn't generating
-          those yet, however.  */
-       if (code == MISALIGNED_INDIRECT_REF)
-         {
-           int icode;
-           rtx reg, insn;
+         if (mode == GET_MODE_2XWIDER_MODE (innermode))
+           {
+             if (optab_handler (this_optab, mode)->insn_code != 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)->insn_code != 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));
 
-           gcc_assert (modifier == EXPAND_NORMAL
-                       || modifier == EXPAND_STACK_PARM);
+    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;
 
-           /* The vectorizer should have already checked the mode.  */
-           icode = optab_handler (movmisalign_optab, mode)->insn_code;
-           gcc_assert (icode != CODE_FOR_nothing);
+      /* 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;
+       }
 
-           /* 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);
+      /* Attempt to return something suitable for generating an
+        indexed address, for machines that support that.  */
 
-           /* Nor can the insn generator.  */
-           insn = GEN_FCN (icode) (reg, temp);
-           emit_insn (insn);
+      if (modifier == EXPAND_SUM && mode == ptr_mode
+         && host_integerp (treeop1, 0))
+       {
+         tree exp1 = treeop1;
 
-           return reg;
-         }
+         op0 = expand_expr (treeop0, subtarget, VOIDmode,
+                            EXPAND_SUM);
 
-       return temp;
-      }
+         if (!REG_P (op0))
+           op0 = force_operand (op0, NULL_RTX);
+         if (!REG_P (op0))
+           op0 = copy_to_mode_reg (mode, op0);
 
-    case TARGET_MEM_REF:
-      {
-       struct mem_address addr;
+         return REDUCE_BIT_FIELD (gen_rtx_MULT (mode, op0,
+                              gen_int_mode (tree_low_cst (exp1, 0),
+                                            TYPE_MODE (TREE_TYPE (exp1)))));
+       }
 
-       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 (modifier == EXPAND_STACK_PARM)
+       target = 0;
 
-    case ARRAY_REF:
+      expand_operands (treeop0, treeop1, subtarget, &op0, &op1, EXPAND_NORMAL);
+      return REDUCE_BIT_FIELD (expand_mult (mode, op0, op1, target, unsignedp));
 
-      {
-       tree array = TREE_OPERAND (exp, 0);
-       tree index = TREE_OPERAND (exp, 1);
+    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;
 
-       /* 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.  */
+      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 (modifier != EXPAND_CONST_ADDRESS
-           && modifier != EXPAND_INITIALIZER
-           && modifier != EXPAND_MEMORY)
-         {
-           tree t = fold_read_from_constant_string (exp);
+    case RDIV_EXPR:
+      goto binop;
 
-           if (t)
-             return expand_expr (t, target, tmode, modifier);
-         }
+    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);
 
-       /* 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 FIXED_CONVERT_EXPR:
+      op0 = expand_normal (treeop0);
+      if (target == 0 || modifier == EXPAND_STACK_PARM)
+       target = gen_reg_rtx (mode);
 
-       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;
+      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;
 
-           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 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;
 
-       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);
+    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 (init) == CONSTRUCTOR)
-                 {
-                   unsigned HOST_WIDE_INT ix;
-                   tree field, value;
+    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);
 
-                   FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), ix,
-                                             field, value)
-                     if (tree_int_cst_equal (field, index))
-                       {
-                         if (TREE_SIDE_EFFECTS (value))
-                           break;
+    case ABS_EXPR:
+      op0 = expand_expr (treeop0, subtarget,
+                        VOIDmode, EXPAND_NORMAL);
+      if (modifier == EXPAND_STACK_PARM)
+       target = 0;
 
-                         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;
-                           }
+      /* ABS_EXPR is not valid for complex arguments.  */
+      gcc_assert (GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
+                 && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT);
 
-                         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 (sizetype, TREE_OPERAND (exp, 1));
+      /* Unsigned abs is simply the operand.  Testing here means we don't
+        risk generating incorrect code below.  */
+      if (TYPE_UNSIGNED (type))
+       return op0;
 
-                   /* Optimize the special-case of a zero lower bound.
+      return expand_abs (mode, op0, target, unsignedp,
+                        safe_from_p (target, treeop0, 1));
 
-                      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!)  */
+    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 (! integer_zerop (low_bound))
-                     index1 = size_diffop (index1, fold_convert (sizetype,
-                                                                 low_bound));
+      /* 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;
 
-                   if (0 > compare_tree_int (index1,
-                                             TREE_STRING_LENGTH (init)))
-                     {
-                       tree type = TREE_TYPE (TREE_TYPE (init));
-                       enum machine_mode mode = TYPE_MODE (type);
+      /* At this point, a MEM target is no longer useful; we will get better
+        code without it.  */
 
-                       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;
+      if (! REG_P (target))
+       target = gen_reg_rtx (mode);
 
-    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)
+      /* If op1 was placed in target, swap op0 and op1.  */
+      if (target != op0 && target == op1)
        {
-         unsigned HOST_WIDE_INT idx;
-         tree field, value;
-
-         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 (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);
-
-                       op0 = expand_shift (LSHIFT_EXPR, imode, op0, count,
-                                           target, 0);
-                       op0 = expand_shift (RSHIFT_EXPR, imode, op0, count,
-                                           target, 0);
-                     }
-                 }
-
-               return op0;
-             }
+         temp = op0;
+         op0 = op1;
+         op1 = temp;
        }
-      goto normal_inner_ref;
 
-    case BIT_FIELD_REF:
-    case ARRAY_RANGE_REF:
-    normal_inner_ref:
-      {
-       enum machine_mode mode1;
-       HOST_WIDE_INT bitsize, bitpos;
-       tree offset;
-       int volatilep = 0;
-       tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
-                                       &mode1, &unsignedp, &volatilep, true);
-       rtx orig_op0;
+      /* 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);
 
-       /* 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);
+      {
+       enum rtx_code comparison_code;
+       rtx cmpop1 = op1;
 
-       /* 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.  */
+       if (code == MAX_EXPR)
+         comparison_code = unsignedp ? GEU : GE;
+       else
+         comparison_code = unsignedp ? LEU : LE;
 
-       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 this is a constant, put it into a register if it is a legitimate
-          constant, OFFSET is 0, and we won't try to extract outside the
-          register (in case we were passed a partially uninitialized object
-          or a view_conversion to a larger size) or a BLKmode piece of it
-          (e.g. if it is unchecked-converted to a record type in Ada).  Force
-          the constant to memory otherwise.  */
-       if (CONSTANT_P (op0))
+       /* Canonicalize to comparisons against 0.  */
+       if (op1 == const1_rtx)
          {
-           enum machine_mode mode = TYPE_MODE (TREE_TYPE (tem));
-           if (mode != BLKmode && LEGITIMATE_CONSTANT_P (op0)
-               && offset == 0
-               && mode1 != BLKmode
-               && bitpos + bitsize <= GET_MODE_BITSIZE (mode))
-             op0 = force_reg (mode, op0);
-           else
-             op0 = validize_mem (force_const_mem (mode, op0));
+           /* 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;
          }
-
-       /* Otherwise, if this object not in memory and we either have an
-          offset, a BLKmode result, or a reference outside the object, put it
-          there.  Such cases can occur in Ada if we have unchecked conversion
-          of an expression from a scalar type to an array or record type or
-          for an ARRAY_RANGE_REF whose type is BLKmode.  */
-       else if (!MEM_P (op0)
-                && (offset != 0
-                    || mode1 == BLKmode
-                    || (bitpos + bitsize
-                        > GET_MODE_BITSIZE (GET_MODE (op0)))))
+       if (op1 == constm1_rtx && !unsignedp)
          {
-           tree nt = build_qualified_type (TREE_TYPE (tem),
-                                           (TYPE_QUALS (TREE_TYPE (tem))
-                                            | TYPE_QUAL_CONST));
-           rtx memloc = assign_temp (nt, 1, 1, 1);
-
-           emit_move_insn (memloc, op0);
-           op0 = memloc;
+           /* 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;
          }
-
-       if (offset != 0)
+#ifdef HAVE_conditional_move
+       /* Use a conditional move if possible.  */
+       if (can_conditionally_move_p (mode))
          {
-           rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode,
-                                         EXPAND_SUM);
+           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_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 ((target == 0
+          || modifier == EXPAND_STACK_PARM
+          || ! safe_from_p (target, treeop0, 1)
+          || ! safe_from_p (target, treeop1, 1)
+          /* Make sure we don't have a hard reg (such as function's return
+             value) live across basic blocks, if not optimizing.  */
+          || (!optimize && REG_P (target)
+              && REGNO (target) < FIRST_PSEUDO_REGISTER)))
+       target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
 
-           if (MEM_P (op0) && REG_P (XEXP (op0, 0)))
-             mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
+      emit_move_insn (target, const0_rtx);
 
-           op0 = extract_bit_field (op0, bitsize, bitpos, unsignedp,
-                                    (modifier == EXPAND_STACK_PARM
-                                     ? NULL_RTX : target),
-                                    ext_mode, ext_mode);
+      op1 = gen_label_rtx ();
+      jumpifnot_1 (code, treeop0, treeop1, op1, -1);
 
-           /* 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);
+      emit_move_insn (target, const1_rtx);
 
-           /* 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;
-
-               /* If the reference doesn't use the alias set of its type,
-                  we cannot create the temporary using that type.  */
-               if (component_uses_parent_alias_set (exp))
-                 {
-                   new = assign_stack_local (ext_mode, size, 0);
-                   set_mem_alias_set (new, get_alias_set (exp));
-                 }
-               else
-                 new = assign_stack_temp_for_type (ext_mode, size, 0, type);
+      emit_label (op1);
+      return target;
 
-               emit_move_insn (new, op0);
-               op0 = copy_rtx (new);
-               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, lang_hooks.decl_printable_name (fndecl, 1),
-                TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr))));
-       if (fndecl
-           && (attr = lookup_attribute ("warning",
-                                        DECL_ATTRIBUTES (fndecl))) != NULL)
-         warning (0, "%Kcall to %qs declared with attribute warning: %s",
-                  exp, lang_hooks.decl_printable_name (fndecl, 1),
-                  TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr))));
+    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))
-         {
-           if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_FRONTEND)
-             return lang_hooks.expand_expr (exp, original_target,
-                                            tmode, modifier, alt_rtl);
-           else
-             return expand_builtin (exp, target, subtarget, tmode, ignore);
-         }
+    case VEC_UNPACK_HI_EXPR:
+    case VEC_UNPACK_LO_EXPR:
+      {
+       op0 = expand_normal (treeop0);
+       this_optab = optab_for_tree_code (code, type, optab_default);
+       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.  */
+       this_optab = optab_for_tree_code (code,
+                                         TREE_TYPE (treeop0),
+                                         optab_default);
+       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);
+    default:
+      gcc_unreachable ();
+    }
 
-         else
-           {
-             gcc_assert (REG_P (target));
+  /* 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
 
-             /* 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);
-           }
+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);
+  optab this_optab;
+  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;
 
-         /* Return the entire union.  */
-         return target;
-       }
+  type = TREE_TYPE (exp);
+  mode = TYPE_MODE (type);
+  unsignedp = TYPE_UNSIGNED (type);
 
-      if (mode == TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
-       {
-         op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode,
-                            modifier);
+  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 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;
+  ignore = (target == const0_rtx
+           || ((CONVERT_EXPR_CODE_P (code)
+                || code == COND_EXPR || code == VIEW_CONVERT_EXPR)
+               && TREE_CODE (type) == VOID_TYPE));
 
-         return REDUCE_BIT_FIELD (op0);
-       }
+  /* 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));
 
-      op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode,
-                        modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier);
-      if (GET_MODE (op0) == mode)
-       ;
+  /* 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 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);
+  if (ignore)
+    {
+      if (! TREE_SIDE_EFFECTS (exp))
+       return const0_rtx;
 
-         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));
+      /* 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;
        }
 
-      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 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, modifier);
+  if (reduce_bit_field && modifier == EXPAND_STACK_PARM)
+    target = 0;
 
-      /* If the input and output modes are both the same, we are done.  */
-      if (TYPE_MODE (type) == GET_MODE (op0))
-       ;
-      /* If neither mode is BLKmode, and both modes are the same size
-        then we can use gen_lowpart.  */
-      else if (TYPE_MODE (type) != BLKmode && GET_MODE (op0) != BLKmode
-              && GET_MODE_SIZE (TYPE_MODE (type))
-                  == GET_MODE_SIZE (GET_MODE (op0)))
-       {
-         if (GET_CODE (op0) == SUBREG)
-           op0 = force_reg (GET_MODE (op0), op0);
-         op0 = gen_lowpart (TYPE_MODE (type), op0);
-       }
-      /* If both modes are integral, then we can convert from one to the
-        other.  */
-      else if (SCALAR_INT_MODE_P (GET_MODE (op0))
-              && SCALAR_INT_MODE_P (TYPE_MODE (type)))
-       op0 = convert_modes (TYPE_MODE (type), GET_MODE (op0), op0,
-                            TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
-      /* As a last resort, spill op0 to memory, and reload it in a
-        different mode.  */
-      else if (!MEM_P (op0))
-       {
-         /* If the operand is not a MEM, force it into memory.  Since we
-            are going to be 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));
+  /* Use subtarget as the target for operand 0 of a binary operation.  */
+  subtarget = get_subtarget (target);
+  original_target = target;
 
-         gcc_assert (!TREE_ADDRESSABLE (exp));
+  switch (code)
+    {
+    case LABEL_DECL:
+      {
+       tree function = decl_function_context (exp);
 
-         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);
+       temp = label_rtx (exp);
+       temp = gen_rtx_LABEL_REF (Pmode, temp);
 
-         emit_move_insn (target, op0);
-         op0 = target;
-       }
+       if (function != current_function_decl
+           && function != 0)
+         LABEL_REF_NONLOCAL_P (temp) = 1;
 
-      /* 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);
+       temp = gen_rtx_MEM (FUNCTION_MODE, temp);
+       return temp;
+      }
 
-         if (TYPE_ALIGN_OK (type))
-           set_mem_align (op0, MAX (MEM_ALIGN (op0), TYPE_ALIGN (type)));
-         else if (TYPE_MODE (type) != BLKmode && STRICT_ALIGNMENT
-                  && MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (TYPE_MODE (type)))
-           {
-             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 (TYPE_MODE (type)));
-             rtx new = assign_stack_temp_for_type (TYPE_MODE (type),
-                                                   temp_size, 0, type);
-             rtx new_with_op0_mode = adjust_address (new, GET_MODE (op0), 0);
+    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 (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;
 
-             gcc_assert (!TREE_ADDRESSABLE (exp));
+    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 (GET_MODE (op0) == BLKmode)
-               emit_block_move (new_with_op0_mode, op0,
-                                GEN_INT (GET_MODE_SIZE (TYPE_MODE (type))),
-                                (modifier == EXPAND_STACK_PARM
-                                 ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
-             else
-               emit_move_insn (new_with_op0_mode, op0);
+      /* 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);
+       }
 
-             op0 = new;
-           }
+      /* ... fall through ...  */
 
-         op0 = adjust_address (op0, TYPE_MODE (type), 0);
+    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)
+         && REGNO (decl_rtl) < FIRST_PSEUDO_REGISTER)
+       {
+           int i = REGNO (decl_rtl);
+           int nregs = hard_regno_nregs[i][GET_MODE (decl_rtl)];
+           while (nregs)
+             {
+               SET_HARD_REG_BIT (crtl->asm_clobbers, i);
+               i++;
+               nregs--;
+             }
        }
 
-      return 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))
+       {
+         assemble_external (exp);
+         TREE_USED (exp) = 1;
+       }
 
-    case POINTER_PLUS_EXPR: 
-      /* Even though the sizetype mode and the pointer's mode can be different
-         expand is able to handle this correctly and get the correct result out 
-         of the PLUS_EXPR code.  */
-    case PLUS_EXPR:
+      /* Show we haven't gotten RTL for this yet.  */
+      temp = 0;
 
-      /* Check if this is a case for multiplication and addition.  */
-      if ((TREE_CODE (type) == INTEGER_TYPE
-          || TREE_CODE (type) == FIXED_POINT_TYPE)
-         && TREE_CODE (TREE_OPERAND (exp, 0)) == MULT_EXPR)
-       {
-         tree subsubexp0, subsubexp1;
-         enum tree_code code0, code1, this_code;
+      /* 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);
 
-         subexp0 = TREE_OPERAND (exp, 0);
-         subsubexp0 = TREE_OPERAND (subexp0, 0);
-         subsubexp1 = TREE_OPERAND (subexp0, 1);
-         code0 = TREE_CODE (subsubexp0);
-         code1 = TREE_CODE (subsubexp1);
-         this_code = TREE_CODE (type) == INTEGER_TYPE ? NOP_EXPR
-                                                      : FIXED_CONVERT_EXPR;
-         if (code0 == this_code && code1 == this_code
-             && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
-                 < TYPE_PRECISION (TREE_TYPE (subsubexp0)))
-             && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
-                 == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp1, 0))))
-             && (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
-                 == TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subsubexp1, 0)))))
-           {
-             tree op0type = TREE_TYPE (TREE_OPERAND (subsubexp0, 0));
-             enum machine_mode innermode = TYPE_MODE (op0type);
-             bool zextend_p = TYPE_UNSIGNED (op0type);
-             bool sat_p = TYPE_SATURATING (TREE_TYPE (subsubexp0));
-             if (sat_p == 0)
-               this_optab = zextend_p ? umadd_widen_optab : smadd_widen_optab;
-             else
-               this_optab = zextend_p ? usmadd_widen_optab
-                                      : ssmadd_widen_optab;
-             if (mode == GET_MODE_2XWIDER_MODE (innermode)
-                 && (optab_handler (this_optab, mode)->insn_code
-                     != CODE_FOR_nothing))
-               {
-                 expand_operands (TREE_OPERAND (subsubexp0, 0),
-                                  TREE_OPERAND (subsubexp1, 0),
-                                  NULL_RTX, &op0, &op1, EXPAND_NORMAL);
-                 op2 = expand_expr (TREE_OPERAND (exp, 1), subtarget,
-                                    VOIDmode, EXPAND_NORMAL);
-                 temp = expand_ternary_op (mode, this_optab, op0, op1, op2,
-                                           target, unsignedp);
-                 gcc_assert (temp);
-                 return REDUCE_BIT_FIELD (temp);
-               }
-           }
-       }
+      /* 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 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.
+      if (MEM_P (decl_rtl) && REG_P (XEXP (decl_rtl, 0)))
+       temp = validize_mem (decl_rtl);
 
-        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.  */
+      /* If DECL_RTL is memory, we are in the normal case and the
+        address is not valid, get the address into a register.  */
 
-      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))
+      else if (MEM_P (decl_rtl) && modifier != EXPAND_INITIALIZER)
+       {
+         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 we got something, return it.  But first, set the alignment
+        if the address is a register.  */
+      if (temp != 0)
        {
-         tree t = TREE_OPERAND (exp, 1);
+         if (MEM_P (temp) && REG_P (XEXP (temp, 0)))
+           mark_reg_pointer (XEXP (temp, 0), DECL_ALIGN (exp));
 
-         TREE_OPERAND (exp, 1) = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
-         TREE_OPERAND (TREE_OPERAND (exp, 0), 0) = t;
+         return temp;
        }
 
-      /* 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 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 this is an EXPAND_SUM call, always return the sum.  */
-      if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER
-         || (mode == ptr_mode && (unsignedp || ! flag_trapv)))
+      if (REG_P (decl_rtl)
+         && GET_MODE (decl_rtl) != DECL_MODE (exp))
        {
-         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 pmode;
 
-             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);
-           }
+         /* 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);
 
-         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;
+         temp = gen_lowpart_SUBREG (mode, decl_rtl);
+         SUBREG_PROMOTED_VAR_P (temp) = 1;
+         SUBREG_PROMOTED_UNSIGNED_SET (temp, unsignedp);
+         return temp;
+       }
 
-             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);
-           }
-       }
+      return decl_rtl;
 
-      /* 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)
+    case INTEGER_CST:
+      temp = immed_double_const (TREE_INT_CST_LOW (exp),
+                                TREE_INT_CST_HIGH (exp), mode);
+
+      return temp;
+
+    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);
+      }
+
+    case CONST_DECL:
+      return expand_expr (DECL_INITIAL (exp), target, VOIDmode, modifier);
+
+    case REAL_CST:
+      /* If optimized, generate immediate CONST_DOUBLE
+        which will be turned into memory by reload if necessary.
+
+        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.
+
+        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)));
+
+    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)
        {
-         expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
-                          subtarget, &op0, &op1, 0);
-         if (op0 == const0_rtx)
-           return op1;
-         if (op1 == const0_rtx)
-           return op0;
-         goto binop2;
+         enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
+         rtx rtarg, itarg;
+
+         rtarg = XEXP (original_target, 0);
+         itarg = XEXP (original_target, 1);
+
+         /* 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);
+
+         if (op0 != rtarg)
+           emit_move_insn (rtarg, op0);
+         if (op1 != itarg)
+           emit_move_insn (itarg, op1);
+
+         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)
-         && TREE_CODE (TREE_OPERAND (exp, 1)) == MULT_EXPR)
+    case STRING_CST:
+      temp = expand_expr_constant (exp, 1, modifier);
+
+      /* 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;
+
+    case SAVE_EXPR:
+      {
+       tree val = treeop0;
+       rtx ret = expand_expr_real_1 (val, target, tmode, modifier, alt_rtl);
+
+       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);
+
+           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;
+
+           if (!CONSTANT_P (ret))
+             ret = copy_to_reg (ret);
+           SET_DECL_RTL (val, ret);
+         }
+
+        return ret;
+      }
+
+
+    case CONSTRUCTOR:
+      /* If we don't need the result, just ensure we evaluate any
+        subexpressions.  */
+      if (ignore)
        {
-         tree subsubexp0, subsubexp1;
-         enum tree_code code0, code1, this_code;
+         unsigned HOST_WIDE_INT idx;
+         tree value;
 
-         subexp1 = TREE_OPERAND (exp, 1);
-         subsubexp0 = TREE_OPERAND (subexp1, 0);
-         subsubexp1 = TREE_OPERAND (subexp1, 1);
-         code0 = TREE_CODE (subsubexp0);
-         code1 = TREE_CODE (subsubexp1);
-         this_code = TREE_CODE (type) == INTEGER_TYPE ? NOP_EXPR
-                                                      : FIXED_CONVERT_EXPR;
-         if (code0 == this_code && code1 == this_code
-             && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
-                 < TYPE_PRECISION (TREE_TYPE (subsubexp0)))
-             && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
-                 == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp1, 0))))
-             && (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
-                 == TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subsubexp1, 0)))))
-           {
-             tree op0type = TREE_TYPE (TREE_OPERAND (subsubexp0, 0));
-             enum machine_mode innermode = TYPE_MODE (op0type);
-             bool zextend_p = TYPE_UNSIGNED (op0type);
-             bool sat_p = TYPE_SATURATING (TREE_TYPE (subsubexp0));
-             if (sat_p == 0)
-               this_optab = zextend_p ? umsub_widen_optab : smsub_widen_optab;
-             else
-               this_optab = zextend_p ? usmsub_widen_optab
-                                      : ssmsub_widen_optab;
-             if (mode == GET_MODE_2XWIDER_MODE (innermode)
-                 && (optab_handler (this_optab, mode)->insn_code
-                     != CODE_FOR_nothing))
+         FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value)
+           expand_expr (value, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+         return const0_rtx;
+       }
+
+      return expand_constructor (exp, target, modifier, false);
+
+    case MISALIGNED_INDIRECT_REF:
+    case ALIGN_INDIRECT_REF:
+    case INDIRECT_REF:
+      {
+       tree exp1 = treeop0;
+       addr_space_t as = ADDR_SPACE_GENERIC;
+       enum machine_mode address_mode = Pmode;
+
+       if (modifier != EXPAND_WRITE)
+         {
+           tree t;
+
+           t = fold_read_from_constant_string (exp);
+           if (t)
+             return expand_expr (t, target, tmode, modifier);
+         }
+
+       if (POINTER_TYPE_P (TREE_TYPE (exp1)))
+         {
+           as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp1)));
+           address_mode = targetm.addr_space.address_mode (as);
+         }
+
+       op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM);
+       op0 = memory_address_addr_space (mode, op0, as);
+
+       if (code == ALIGN_INDIRECT_REF)
+         {
+           int align = TYPE_ALIGN_UNIT (type);
+           op0 = gen_rtx_AND (address_mode, op0, GEN_INT (-align));
+           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);
+
+       /* 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)
+         {
+           int icode;
+           rtx reg, insn;
+
+           gcc_assert (modifier == EXPAND_NORMAL
+                       || modifier == EXPAND_STACK_PARM);
+
+           /* The vectorizer should have already checked the mode.  */
+           icode = optab_handler (movmisalign_optab, mode)->insn_code;
+           gcc_assert (icode != CODE_FOR_nothing);
+
+           /* We've already validated the memory, and we're creating a
+              new pseudo destination.  The predicates really can't fail.  */
+           reg = gen_reg_rtx (mode);
+
+           /* Nor can the insn generator.  */
+           insn = GEN_FCN (icode) (reg, temp);
+           emit_insn (insn);
+
+           return reg;
+         }
+
+       return temp;
+      }
+
+    case TARGET_MEM_REF:
+      {
+       addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (exp));
+       struct mem_address addr;
+       tree base;
+
+       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, TMR_ORIGINAL (exp), 0);
+       set_mem_addr_space (temp, as);
+       base = get_base_address (TMR_ORIGINAL (exp));
+       if (INDIRECT_REF_P (base)
+           && TMR_BASE (exp)
+           && TREE_CODE (TMR_BASE (exp)) == SSA_NAME
+           && POINTER_TYPE_P (TREE_TYPE (TMR_BASE (exp))))
+         {
+           set_mem_expr (temp, build1 (INDIRECT_REF,
+                                       TREE_TYPE (exp), TMR_BASE (exp)));
+           set_mem_offset (temp, NULL_RTX);
+         }
+      }
+      return temp;
+
+    case ARRAY_REF:
+
+      {
+       tree array = treeop0;
+       tree index = treeop1;
+
+       /* 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.  */
+
+       if (modifier != EXPAND_CONST_ADDRESS
+           && modifier != EXPAND_INITIALIZER
+           && modifier != EXPAND_MEMORY)
+         {
+           tree t = fold_read_from_constant_string (exp);
+
+           if (t)
+             return expand_expr (t, target, tmode, modifier);
+         }
+
+       /* 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.  */
+
+       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;
+
+           FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (array), ix,
+                                     field, value)
+             if (tree_int_cst_equal (field, index))
                {
-                 expand_operands (TREE_OPERAND (subsubexp0, 0),
-                                  TREE_OPERAND (subsubexp1, 0),
-                                  NULL_RTX, &op0, &op1, EXPAND_NORMAL);
-                 op2 = expand_expr (TREE_OPERAND (exp, 0), subtarget,
-                                    VOIDmode, EXPAND_NORMAL);
-                 temp = expand_ternary_op (mode, this_optab, op0, op1, op2,
-                                           target, unsignedp);
-                 gcc_assert (temp);
-                 return REDUCE_BIT_FIELD (temp);
+                 if (!TREE_SIDE_EFFECTS (value))
+                   return expand_expr (fold (value), target, tmode, modifier);
+                 break;
                }
-           }
-       }
+         }
 
-      /* 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);
+       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 the last operand is a CONST_INT, use plus_constant of
-            the negated constant.  Else make the MINUS.  */
-         if (GET_CODE (op1) == CONST_INT)
-           return REDUCE_BIT_FIELD (plus_constant (op0, - INTVAL (op1)));
-         else
-           return REDUCE_BIT_FIELD (gen_rtx_MINUS (mode, op0, op1));
-       }
+               if (TREE_CODE (init) == CONSTRUCTOR)
+                 {
+                   unsigned HOST_WIDE_INT ix;
+                   tree field, value;
 
-      /* 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;
+                   FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), ix,
+                                             field, value)
+                     if (tree_int_cst_equal (field, index))
+                       {
+                         if (TREE_SIDE_EFFECTS (value))
+                           break;
 
-      expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
-                      subtarget, &op0, &op1, modifier);
+                         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;
+                           }
 
-      /* Convert A - const to A + (-const).  */
-      if (GET_CODE (op1) == CONST_INT)
+                         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)
        {
-         op1 = negate_rtx (mode, op1);
-         return REDUCE_BIT_FIELD (simplify_gen_binary (PLUS, mode, op0, op1));
+         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
+                     {
+                       tree count
+                         = build_int_cst (NULL_TREE,
+                                          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;
 
-      goto binop2;
+    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);
 
-    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;
+       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 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;
-       }
+       /* 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);
+
+       /* 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;
+         }
 
-      /* Attempt to return something suitable for generating an
-        indexed address, for machines that support that.  */
+       if (offset)
+         {
+           enum machine_mode address_mode;
+           rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode,
+                                         EXPAND_SUM);
 
-      if (modifier == EXPAND_SUM && mode == ptr_mode
-         && host_integerp (TREE_OPERAND (exp, 1), 0))
-       {
-         tree exp1 = TREE_OPERAND (exp, 1);
+           gcc_assert (MEM_P (op0));
 
-         op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode,
-                            EXPAND_SUM);
+           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 (!REG_P (op0))
-           op0 = force_operand (op0, NULL_RTX);
-         if (!REG_P (op0))
-           op0 = copy_to_mode_reg (mode, op0);
+           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;
+             }
 
-         return REDUCE_BIT_FIELD (gen_rtx_MULT (mode, op0,
-                              gen_int_mode (tree_low_cst (exp1, 0),
-                                            TYPE_MODE (TREE_TYPE (exp1)))));
-       }
+           op0 = offset_address (op0, offset_rtx,
+                                 highest_pow2_factor (offset));
+         }
 
-      if (modifier == EXPAND_STACK_PARM)
-       target = 0;
+       /* 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);
 
-      /* 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.  */
+       /* 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);
 
-      subexp0 = TREE_OPERAND (exp, 0);
-      subexp1 = TREE_OPERAND (exp, 1);
-      /* First, check if we have a multiplication of one signed and one
-        unsigned operand.  */
-      if (TREE_CODE (subexp0) == NOP_EXPR
-         && TREE_CODE (subexp1) == NOP_EXPR
-         && TREE_CODE (type) == INTEGER_TYPE
-         && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subexp0, 0)))
-             < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0))))
-         && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subexp0, 0)))
-             == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subexp1, 0))))
-         && (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subexp0, 0)))
-             != TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subexp1, 0)))))
-       {
-         enum machine_mode innermode
-           = TYPE_MODE (TREE_TYPE (TREE_OPERAND (subexp0, 0)));
-         this_optab = usmul_widen_optab;
-         if (mode == GET_MODE_WIDER_MODE (innermode))
-           {
-             if (optab_handler (this_optab, mode)->insn_code != CODE_FOR_nothing)
-               {
-                 if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subexp0, 0))))
-                   expand_operands (TREE_OPERAND (subexp0, 0),
-                                    TREE_OPERAND (subexp1, 0),
-                                    NULL_RTX, &op0, &op1, 0);
-                 else
-                   expand_operands (TREE_OPERAND (subexp0, 0),
-                                    TREE_OPERAND (subexp1, 0),
-                                    NULL_RTX, &op1, &op0, 0);
+           MEM_VOLATILE_P (op0) = 1;
+         }
 
-                 goto binop3;
-               }
-           }
-       }
-      /* Check for a multiplication with matching signedness.  */
-      else if (TREE_CODE (TREE_OPERAND (exp, 0)) == NOP_EXPR
-         && TREE_CODE (type) == INTEGER_TYPE
-         && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
-             < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0))))
-         && ((TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
-              && int_fits_type_p (TREE_OPERAND (exp, 1),
-                                  TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
-              /* Don't use a widening multiply if a shift will do.  */
-              && ((GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 1))))
-                   > HOST_BITS_PER_WIDE_INT)
-                  || exact_log2 (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))) < 0))
-             ||
-             (TREE_CODE (TREE_OPERAND (exp, 1)) == NOP_EXPR
-              && (TYPE_PRECISION (TREE_TYPE
-                                  (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)))
-                  == TYPE_PRECISION (TREE_TYPE
-                                     (TREE_OPERAND
-                                      (TREE_OPERAND (exp, 0), 0))))
-              /* If both operands are extended, they must either both
-                 be zero-extended or both be sign-extended.  */
-              && (TYPE_UNSIGNED (TREE_TYPE
-                                 (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)))
-                  == TYPE_UNSIGNED (TREE_TYPE
-                                    (TREE_OPERAND
-                                     (TREE_OPERAND (exp, 0), 0)))))))
-       {
-         tree op0type = TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0));
-         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;
+       /* 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;
 
-         if (mode == GET_MODE_2XWIDER_MODE (innermode))
-           {
-             if (optab_handler (this_optab, mode)->insn_code != CODE_FOR_nothing)
-               {
-                 if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
-                   expand_operands (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
-                                    TREE_OPERAND (exp, 1),
-                                    NULL_RTX, &op0, &op1, EXPAND_NORMAL);
-                 else
-                   expand_operands (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
-                                    TREE_OPERAND (TREE_OPERAND (exp, 1), 0),
-                                    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 (TREE_OPERAND (TREE_OPERAND (exp, 0), 0));
-                 if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
-                   op1 = convert_modes (innermode, mode,
-                                        expand_normal (TREE_OPERAND (exp, 1)),
-                                        unsignedp);
-                 else
-                   op1 = expand_normal (TREE_OPERAND (TREE_OPERAND (exp, 1), 0));
-                 temp = expand_binop (mode, other_optab, op0, op1, target,
-                                      unsignedp, OPTAB_LIB_WIDEN);
-                 hipart = gen_highpart (innermode, temp);
-                 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 (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
-                      subtarget, &op0, &op1, 0);
-      return REDUCE_BIT_FIELD (expand_mult (mode, op0, op1, target, unsignedp));
+           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 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 (ext_mode == BLKmode)
+             {
+               if (target == 0)
+                 target = assign_temp (type, 0, 1, 1);
 
-      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, 0);
-      return expand_divmod (0, code, mode, op0, op1, target, unsignedp);
+               if (bitsize == 0)
+                 return target;
 
-    case RDIV_EXPR:
-      goto binop;
+               /* 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 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, 0);
-      return expand_divmod (1, code, mode, op0, op1, target, unsignedp);
+               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));
 
-    case FIXED_CONVERT_EXPR:
-      op0 = expand_normal (TREE_OPERAND (exp, 0));
-      if (target == 0 || modifier == EXPAND_STACK_PARM)
-       target = gen_reg_rtx (mode);
+               return target;
+             }
 
-      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;
+           op0 = validize_mem (op0);
 
-    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;
+           if (MEM_P (op0) && REG_P (XEXP (op0, 0)))
+             mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
 
-    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;
+           op0 = extract_bit_field (op0, bitsize, bitpos, unsignedp,
+                                    (modifier == EXPAND_STACK_PARM
+                                     ? NULL_RTX : target),
+                                    ext_mode, ext_mode);
 
-    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 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);
 
-    case ABS_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget,
-                        VOIDmode, EXPAND_NORMAL);
-      if (modifier == EXPAND_STACK_PARM)
-       target = 0;
+           /* 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;
 
-      /* 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 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);
 
-      /* Unsigned abs is simply the operand.  Testing here means we don't
-        risk generating incorrect code below.  */
-      if (TYPE_UNSIGNED (type))
-       return op0;
+               emit_move_insn (new_rtx, op0);
+               op0 = copy_rtx (new_rtx);
+               PUT_MODE (op0, BLKmode);
+               set_mem_attributes (op0, exp, 1);
+             }
 
-      return expand_abs (mode, op0, target, unsignedp,
-                        safe_from_p (target, TREE_OPERAND (exp, 0), 1));
+           return op0;
+         }
 
-    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, 0);
+       /* If the result is BLKmode, use that to access the object
+          now as well.  */
+       if (mode == BLKmode)
+         mode1 = BLKmode;
 
-      /* 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;
+       /* 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);
 
-      /* At this point, a MEM target is no longer useful; we will get better
-        code without it.  */
+       if (op0 == orig_op0)
+         op0 = copy_rtx (op0);
 
-      if (! REG_P (target))
-       target = gen_reg_rtx (mode);
+       set_mem_attributes (op0, exp, 0);
+       if (REG_P (XEXP (op0, 0)))
+         mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
 
-      /* If op1 was placed in target, swap op0 and op1.  */
-      if (target != op0 && target == op1)
-       {
-         temp = op0;
-         op0 = op1;
-         op1 = temp;
-       }
+       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);
 
-      /* 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);
+       convert_move (target, op0, unsignedp);
+       return target;
+      }
+
+    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;
-
-           /* ??? 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 ();
+      }
+      return expand_call (exp, target, ignore);
 
-           start_sequence ();
+    case VIEW_CONVERT_EXPR:
+      op0 = NULL_RTX;
 
-           /* Try to emit the conditional move.  */
-           insn = emit_conditional_move (target, comparison_code,
-                                         op0, cmpop1, mode,
-                                         op0, op1, mode,
-                                         unsignedp);
+      /* 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;
 
-           /* If we could do the conditional move, emit the sequence,
-              and return.  */
-           if (insn)
+       /* ??? 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 (MEM_P (orig_op0))
              {
-               rtx seq = get_insns ();
-               end_sequence ();
-               emit_insn (seq);
-               return target;
-             }
-
-           /* Otherwise discard the sequence and fall back to code with
-              branches.  */
-           end_sequence ();
-         }
-#endif
-       if (target != op0)
-         emit_move_insn (target, op0);
-
-       temp = gen_label_rtx ();
-       do_compare_rtx_and_jump (target, cmpop1, comparison_code,
-                                unsignedp, mode, NULL_RTX, NULL_RTX, temp);
-      }
-      emit_move_insn (target, op1);
-      emit_label (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;
+               op0 = orig_op0;
 
-      /* ??? 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.  */
+               /* 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);
 
-      /* 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.  */
+               if (op0 == orig_op0)
+                 op0 = copy_rtx (op0);
 
-    case TRUTH_AND_EXPR:
-      code = BIT_AND_EXPR;
-    case BIT_AND_EXPR:
-      goto binop;
+               set_mem_attributes (op0, treeop0, 0);
+               if (REG_P (XEXP (op0, 0)))
+                 mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
 
-    case TRUTH_OR_EXPR:
-      code = BIT_IOR_EXPR;
-    case BIT_IOR_EXPR:
-      goto binop;
+               MEM_VOLATILE_P (op0) |= volatilep;
+             }
+         }
+      }
 
-    case TRUTH_XOR_EXPR:
-      code = BIT_XOR_EXPR;
-    case BIT_XOR_EXPR:
-      goto binop;
+      if (!op0)
+       op0 = expand_expr (treeop0,
+                          NULL_RTX, VOIDmode, modifier);
 
-    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 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);
+         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);
 
-    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;
+         gcc_assert (!TREE_ADDRESSABLE (exp));
 
-      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;
+         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);
 
-      /* 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, 0);
-      if (temp != 0)
-       return temp;
+         emit_move_insn (target, op0);
+         op0 = target;
+       }
 
-      /* For foo != 0, load foo, and if it is nonzero load 1 instead.  */
-      if (code == NE_EXPR && integer_zerop (TREE_OPERAND (exp, 1))
-         && original_target
-         && REG_P (original_target)
-         && (GET_MODE (original_target)
-             == TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
+      /* 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))
        {
-         temp = expand_expr (TREE_OPERAND (exp, 0), original_target,
-                             VOIDmode, EXPAND_NORMAL);
+         op0 = copy_rtx (op0);
 
-         /* If temp is constant, we can just compute the result.  */
-         if (GET_CODE (temp) == CONST_INT)
+         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))
            {
-             if (INTVAL (temp) != 0)
-               emit_move_insn (target, const1_rtx);
-             else
-               emit_move_insn (target, const0_rtx);
+             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);
 
-             return target;
-           }
+             gcc_assert (!TREE_ADDRESSABLE (exp));
 
-         if (temp != original_target)
-           {
-             enum machine_mode mode1 = GET_MODE (temp);
-             if (mode1 == VOIDmode)
-               mode1 = tmode != VOIDmode ? tmode : mode;
+             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);
 
-             temp = copy_to_mode_reg (mode1, temp);
+             op0 = new_rtx;
            }
 
-         op1 = gen_label_rtx ();
-         emit_cmp_and_jump_insns (temp, const0_rtx, EQ, NULL_RTX,
-                                  GET_MODE (temp), unsignedp, op1);
-         emit_move_insn (temp, const1_rtx);
-         emit_label (op1);
-         return temp;
+         op0 = adjust_address (op0, mode, 0);
        }
 
-      /* If no set-flag instruction, must generate a conditional store
-        into a temporary variable.  Drop through and handle this
-        like && and ||.  */
+      return op0;
+
+      /* Use a compare and a jump for BLKmode comparisons, or for function
+        type comparisons is HAVE_canonicalize_funcptr_for_compare.  */
 
+      /* Although TRUTH_{AND,OR}IF_EXPR aren't present in GIMPLE, they
+        are occassionally created by folding during expansion.  */
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
       if (! ignore
          && (target == 0
              || modifier == EXPAND_STACK_PARM
-             || ! safe_from_p (target, 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)
@@ -8996,7 +9435,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);
@@ -9004,18 +9443,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;
@@ -9031,7 +9458,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
@@ -9040,8 +9467,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
@@ -9050,7 +9477,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)
@@ -9065,15 +9492,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);
 
@@ -9082,23 +9509,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);
-       gcc_assert (ignore);
-       expand_assignment (lhs, rhs, false);
-       return const0_rtx;
-      }
-
-    case GIMPLE_MODIFY_STMT:
-      {
-       tree lhs = GIMPLE_STMT_OPERAND (exp, 0);
-       tree rhs = GIMPLE_STMT_OPERAND (exp, 1);
-
+       tree lhs = treeop0;
+       tree rhs = treeop1;
        gcc_assert (ignore);
 
        /* Check for |= or &= of a bitfield of size one into another bitfield
@@ -9121,7 +9538,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 ();
@@ -9133,41 +9550,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:
@@ -9191,52 +9591,25 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
     case POSTDECREMENT_EXPR:
     case LOOP_EXPR:
     case EXIT_EXPR:
-    case TRUTH_ANDIF_EXPR:
-    case TRUTH_ORIF_EXPR:
       /* Lowered by gimplify.c.  */
       gcc_unreachable ();
 
-    case CHANGE_DYNAMIC_TYPE_EXPR:
-      /* This is ignored at the RTL level.  The tree level set
-        DECL_POINTER_ALIAS_SET of any variable to be 0, which is
-        overkill for the RTL layer but is all that we can
-        represent.  */
-      return const0_rtx;
-
-    case EXC_PTR_EXPR:
-      return get_exception_pointer ();
-
-    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);
+        tree oprnd0 = treeop0;
+        tree oprnd1 = treeop1;
+        tree oprnd2 = treeop2;
         rtx op2;
 
         this_optab = optab_for_tree_code (code, type, optab_default);
@@ -9250,146 +9623,43 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
     case DOT_PROD_EXPR:
       {
-       tree oprnd0 = TREE_OPERAND (exp, 0);
-       tree oprnd1 = TREE_OPERAND (exp, 1);
-       tree oprnd2 = TREE_OPERAND (exp, 2);
+       tree oprnd0 = treeop0;
+       tree oprnd1 = treeop1;
+       tree oprnd2 = treeop2;
        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 = expand_widen_pattern_expr (&ops, op0, op1, op2,
                                            target, unsignedp);
        return target;
       }
 
-    case WIDEN_SUM_EXPR:
-      {
-        tree oprnd0 = TREE_OPERAND (exp, 0);
-        tree oprnd1 = TREE_OPERAND (exp, 1);
-
-        expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, 0);
-        target = expand_widen_pattern_expr (exp, op0, NULL_RTX, op1,
-                                            target, unsignedp);
-        return target;
-      }
-
-    case REDUC_MAX_EXPR:
-    case REDUC_MIN_EXPR:
-    case REDUC_PLUS_EXPR:
-      {
-        op0 = expand_normal (TREE_OPERAND (exp, 0));
-        this_optab = optab_for_tree_code (code, type, optab_default);
-        temp = expand_unop (mode, this_optab, op0, target, unsignedp);
-        gcc_assert (temp);
-        return temp;
-      }
-
-    case VEC_EXTRACT_EVEN_EXPR:
-    case VEC_EXTRACT_ODD_EXPR:
-      {
-        expand_operands (TREE_OPERAND (exp, 0),  TREE_OPERAND (exp, 1),
-                         NULL_RTX, &op0, &op1, 0);
-        this_optab = optab_for_tree_code (code, type, optab_default);
-        temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
-                             OPTAB_WIDEN);
-        gcc_assert (temp);
-        return temp;
-      }
-
-    case VEC_INTERLEAVE_HIGH_EXPR:
-    case VEC_INTERLEAVE_LOW_EXPR:
-      {
-        expand_operands (TREE_OPERAND (exp, 0),  TREE_OPERAND (exp, 1),
-                         NULL_RTX, &op0, &op1, 0);
-        this_optab = optab_for_tree_code (code, type, optab_default);
-        temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
-                             OPTAB_WIDEN);
-        gcc_assert (temp);
-        return temp;
-      }
-
-    case VEC_LSHIFT_EXPR:
-    case VEC_RSHIFT_EXPR:
-      {
-       target = expand_vec_shift_expr (exp, target);
-       return target;
-      }
-
-    case VEC_UNPACK_HI_EXPR:
-    case VEC_UNPACK_LO_EXPR:
-      {
-       op0 = expand_normal (TREE_OPERAND (exp, 0));
-       this_optab = optab_for_tree_code (code, type, optab_default);
-       temp = expand_widen_pattern_expr (exp, op0, NULL_RTX, NULL_RTX,
-                                         target, unsignedp);
-       gcc_assert (temp);
-       return temp;
-      }
-
-    case VEC_UNPACK_FLOAT_HI_EXPR:
-    case VEC_UNPACK_FLOAT_LO_EXPR:
-      {
-       op0 = expand_normal (TREE_OPERAND (exp, 0));
-       /* The signedness is determined from input operand.  */
-       this_optab = optab_for_tree_code (code,
-                                         TREE_TYPE (TREE_OPERAND (exp, 0)),
-                                         optab_default);
-       temp = expand_widen_pattern_expr
-         (exp, op0, NULL_RTX, NULL_RTX,
-          target, TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
-
-       gcc_assert (temp);
-       return temp;
-      }
-
-    case VEC_WIDEN_MULT_HI_EXPR:
-    case VEC_WIDEN_MULT_LO_EXPR:
+    case COMPOUND_LITERAL_EXPR:
       {
-       tree oprnd0 = TREE_OPERAND (exp, 0);
-       tree oprnd1 = TREE_OPERAND (exp, 1);
+       /* Initialize the anonymous variable declared in the compound
+          literal, then return the variable.  */
+       tree decl = COMPOUND_LITERAL_EXPR_DECL (exp);
 
-       expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, 0);
-       target = expand_widen_pattern_expr (exp, op0, op1, NULL_RTX,
-                                           target, unsignedp);
-       gcc_assert (target);
-       return target;
-      }
+       /* Create RTL for this variable.  */
+       if (!DECL_RTL_SET_P (decl))
+         {
+           if (DECL_HARD_REGISTER (decl))
+             /* The user specified an assembler name for this variable.
+                Set that up now.  */
+             rest_of_decl_compilation (decl, 0, 0);
+           else
+             expand_decl (decl);
+         }
 
-    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;
+       return expand_expr_real (decl, original_target, tmode,
+                                modifier, alt_rtl);
       }
 
-    case OMP_ATOMIC_LOAD:
-    case OMP_ATOMIC_STORE:
-      /* OMP expansion is not run when there were errors, so these codes
-                 can get here.  */
-      gcc_assert (errorcount != 0);
-      return NULL_RTX;
-
     default:
-      return lang_hooks.expand_expr (exp, original_target, tmode,
-                                    modifier, alt_rtl);
+      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, 0);
- 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.  */
@@ -9400,7 +9670,7 @@ reduce_to_bit_field_precision (rtx exp, rtx target, tree type)
   if (target && GET_MODE (target) != GET_MODE (exp))
     target = 0;
   /* For constant values, reduce using build_int_cst_type. */
-  if (GET_CODE (exp) == CONST_INT)
+  if (CONST_INT_P (exp))
     {
       HOST_WIDE_INT value = INTVAL (exp);
       tree t = build_int_cst_type (type, value);
@@ -9408,15 +9678,8 @@ 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
@@ -9583,15 +9846,12 @@ 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 either a comparison
-   or a TRUTH_NOT_EXPR whose operand 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.
 
-   If ONLY_CHEAP is nonzero, only do this if it is likely to be very
-   cheap.
-
    Return zero if there is no suitable set-flag instruction
    available on this machine.
 
@@ -9604,29 +9864,19 @@ string_constant (tree arg, tree *ptr_offset)
    set/jump/set sequence.  */
 
 static rtx
-do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
+do_store_flag (sepops ops, rtx target, enum machine_mode mode)
 {
   enum rtx_code code;
   tree arg0, arg1, type;
   tree tem;
   enum machine_mode operand_mode;
-  int invert = 0;
   int unsignedp;
   rtx op0, op1;
-  enum insn_code icode;
   rtx subtarget = target;
-  rtx result, label;
-
-  /* If this is a TRUTH_NOT_EXPR, set a flag indicating we must invert the
-     result at the end.  We can't simply invert the test since it would
-     have already been inverted if it were valid.  This case occurs for
-     some floating-point comparisons.  */
-
-  if (TREE_CODE (exp) == TRUTH_NOT_EXPR)
-    invert = 1, exp = TREE_OPERAND (exp, 0);
+  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)
@@ -9645,11 +9895,11 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
      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
@@ -9664,7 +9914,7 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
      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;
@@ -9748,80 +9998,24 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
       && integer_pow2p (TREE_OPERAND (arg0, 1)))
     {
       tree type = lang_hooks.types.type_for_mode (mode, unsignedp);
-      return expand_expr (fold_single_bit_test (code == NE ? NE_EXPR : EQ_EXPR,
+      return expand_expr (fold_single_bit_test (loc,
+                                               code == NE ? NE_EXPR : EQ_EXPR,
                                                arg0, arg1, type),
                          target, VOIDmode, EXPAND_NORMAL);
     }
 
-  /* Now see if we are likely to be able to do this.  Return if not.  */
-  if (! can_compare_p (code, operand_mode, ccp_store_flag))
-    return 0;
-
-  icode = setcc_gen_code[(int) code];
-
-  if (icode == CODE_FOR_nothing)
-    {
-      enum machine_mode wmode;
-
-      for (wmode = operand_mode;
-          icode == CODE_FOR_nothing && wmode != VOIDmode;
-          wmode = GET_MODE_WIDER_MODE (wmode))
-       icode = optab_handler (cstore_optab, wmode)->insn_code;
-    }
-
-  if (icode == CODE_FOR_nothing
-      || (only_cheap && insn_data[(int) icode].operand[0].mode != mode))
-    {
-      /* We can only do this if it is one of the special cases that
-        can be handled without an scc insn.  */
-      if ((code == LT && integer_zerop (arg1))
-         || (! only_cheap && code == GE && integer_zerop (arg1)))
-       ;
-      else if (! only_cheap && (code == NE || code == EQ)
-              && TREE_CODE (type) != REAL_TYPE
-              && ((optab_handler (abs_optab, operand_mode)->insn_code
-                   != CODE_FOR_nothing)
-                  || (optab_handler (ffs_optab, operand_mode)->insn_code
-                      != CODE_FOR_nothing)))
-       ;
-      else
-       return 0;
-    }
-
   if (! get_subtarget (target)
       || GET_MODE (subtarget) != operand_mode)
     subtarget = 0;
 
-  expand_operands (arg0, arg1, subtarget, &op0, &op1, 0);
+  expand_operands (arg0, arg1, subtarget, &op0, &op1, EXPAND_NORMAL);
 
   if (target == 0)
     target = gen_reg_rtx (mode);
 
-  result = emit_store_flag (target, code, op0, op1,
-                           operand_mode, unsignedp, 1);
-
-  if (result)
-    {
-      if (invert)
-       result = expand_binop (mode, xor_optab, result, const1_rtx,
-                              result, 0, OPTAB_LIB_WIDEN);
-      return result;
-    }
-
-  /* If this failed, we have to do this with set/compare/jump/set code.  */
-  if (!REG_P (target)
-      || reg_mentioned_p (target, op0) || reg_mentioned_p (target, op1))
-    target = gen_reg_rtx (GET_MODE (target));
-
-  emit_move_insn (target, invert ? const0_rtx : const1_rtx);
-  label = gen_label_rtx ();
-  do_compare_rtx_and_jump (op0, op1, code, unsignedp, operand_mode, NULL_RTX,
-                          NULL_RTX, label);
-
-  emit_move_insn (target, invert ? const1_rtx : const0_rtx);
-  emit_label (label);
-
-  return target;
+  /* Try a cstore if possible.  */
+  return emit_store_flag_force (target, code, op0, op1,
+                               operand_mode, unsignedp, 1);
 }
 \f
 
@@ -9832,19 +10026,6 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
 # define CODE_FOR_casesi CODE_FOR_nothing
 #endif
 
-/* If the machine does not have a case insn that compares the bounds,
-   this means extra overhead for dispatch tables, which raises the
-   threshold for using them.  */
-#ifndef CASE_VALUES_THRESHOLD
-#define CASE_VALUES_THRESHOLD (HAVE_casesi ? 4 : 5)
-#endif /* CASE_VALUES_THRESHOLD */
-
-unsigned int
-case_values_threshold (void)
-{
-  return CASE_VALUES_THRESHOLD;
-}
-
 /* Attempt to generate a casesi instruction.  Returns 1 if successful,
    0 otherwise (i.e. if there is no casesi instruction).  */
 int
@@ -10027,16 +10208,16 @@ try_tablejump (tree index_type, tree index_expr, tree minval, tree range,
 int
 vector_mode_valid_p (enum machine_mode mode)
 {
-  enum mode_class class = GET_MODE_CLASS (mode);
+  enum mode_class mclass = GET_MODE_CLASS (mode);
   enum machine_mode innermode;
 
   /* Doh!  What's going on?  */
-  if (class != MODE_VECTOR_INT
-      && class != MODE_VECTOR_FLOAT
-      && class != MODE_VECTOR_FRACT
-      && class != MODE_VECTOR_UFRACT
-      && class != MODE_VECTOR_ACCUM
-      && class != MODE_VECTOR_UACCUM)
+  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!  */
@@ -10084,9 +10265,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.  */
@@ -10095,4 +10275,52 @@ const_vector_from_tree (tree exp)
 
   return gen_rtx_CONST_VECTOR (mode, v);
 }
+
+
+/* Build a decl for a EH personality function named NAME. */
+
+tree
+build_personality_function (const char *name)
+{
+  tree decl, type;
+
+  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"