OSDN Git Service

* tlink.c (scan_linker_output): Parse linker messages from
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index e44a54f..f624d95 100644 (file)
@@ -1,6 +1,7 @@
 /* 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 Free Software Foundation, Inc.
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -125,8 +126,7 @@ static unsigned HOST_WIDE_INT move_by_pieces_ninsns (unsigned HOST_WIDE_INT,
 static void move_by_pieces_1 (rtx (*) (rtx, ...), enum machine_mode,
                              struct move_by_pieces *);
 static bool block_move_libcall_safe_for_call_parm (void);
-static bool emit_block_move_via_movmem (rtx, rtx, rtx, unsigned);
-static rtx emit_block_move_via_libcall (rtx, rtx, rtx, bool);
+static bool emit_block_move_via_movmem (rtx, rtx, rtx, unsigned, unsigned, HOST_WIDE_INT);
 static tree emit_block_move_libcall_fn (int);
 static void emit_block_move_via_loop (rtx, rtx, rtx, unsigned);
 static rtx clear_by_pieces_1 (void *, HOST_WIDE_INT, enum machine_mode);
@@ -134,7 +134,6 @@ static void clear_by_pieces (rtx, unsigned HOST_WIDE_INT, unsigned int);
 static void store_by_pieces_1 (struct store_by_pieces *, unsigned int);
 static void store_by_pieces_2 (rtx (*) (rtx, ...), enum machine_mode,
                               struct store_by_pieces *);
-static rtx clear_storage_via_libcall (rtx, rtx, bool);
 static tree clear_storage_libcall_fn (int);
 static rtx compress_float_constant (rtx, rtx);
 static rtx get_subtarget (rtx);
@@ -349,8 +348,8 @@ convert_move (rtx to, rtx from, int unsignedp)
 {
   enum machine_mode to_mode = GET_MODE (to);
   enum machine_mode from_mode = GET_MODE (from);
-  int to_real = GET_MODE_CLASS (to_mode) == MODE_FLOAT;
-  int from_real = GET_MODE_CLASS (from_mode) == MODE_FLOAT;
+  int to_real = SCALAR_FLOAT_MODE_P (to_mode);
+  int from_real = SCALAR_FLOAT_MODE_P (from_mode);
   enum insn_code code;
   rtx libcall;
 
@@ -410,10 +409,15 @@ convert_move (rtx to, rtx from, int unsignedp)
       rtx value, insns;
       convert_optab tab;
 
-      gcc_assert (GET_MODE_PRECISION (from_mode)
-                 != GET_MODE_PRECISION (to_mode));
+      gcc_assert ((GET_MODE_PRECISION (from_mode)
+                  != GET_MODE_PRECISION (to_mode))
+                 || (DECIMAL_FLOAT_MODE_P (from_mode)
+                     != DECIMAL_FLOAT_MODE_P (to_mode)));
       
-      if (GET_MODE_PRECISION (from_mode) < GET_MODE_PRECISION (to_mode))
+      if (GET_MODE_PRECISION (from_mode) == GET_MODE_PRECISION (to_mode))
+       /* Conversion between decimal float and binary float, same size.  */
+       tab = DECIMAL_FLOAT_MODE_P (from_mode) ? trunc_optab : sext_optab;
+      else if (GET_MODE_PRECISION (from_mode) < GET_MODE_PRECISION (to_mode))
        tab = sext_optab;
       else
        tab = trunc_optab;
@@ -1143,7 +1147,8 @@ move_by_pieces_1 (rtx (*genfun) (rtx, ...), enum machine_mode mode,
    0 otherwise.  */
 
 rtx
-emit_block_move (rtx x, rtx y, rtx size, enum block_op_methods method)
+emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method,
+                      unsigned int expected_align, HOST_WIDE_INT expected_size)
 {
   bool may_use_call;
   rtx retval = 0;
@@ -1198,7 +1203,8 @@ emit_block_move (rtx x, rtx y, rtx size, enum block_op_methods method)
 
   if (GET_CODE (size) == CONST_INT && MOVE_BY_PIECES_P (INTVAL (size), align))
     move_by_pieces (x, y, INTVAL (size), align, 0);
-  else if (emit_block_move_via_movmem (x, y, size, align))
+  else if (emit_block_move_via_movmem (x, y, size, align,
+                                      expected_align, expected_size))
     ;
   else if (may_use_call)
     retval = emit_block_move_via_libcall (x, y, size,
@@ -1212,6 +1218,12 @@ emit_block_move (rtx x, rtx y, rtx size, enum block_op_methods method)
   return retval;
 }
 
+rtx
+emit_block_move (rtx x, rtx y, rtx size, enum block_op_methods method)
+{
+  return emit_block_move_hints (x, y, size, method, 0, -1);
+}
+
 /* A subroutine of emit_block_move.  Returns true if calling the
    block move libcall will not clobber any parameters which may have
    already been placed on the stack.  */
@@ -1262,12 +1274,16 @@ block_move_libcall_safe_for_call_parm (void)
    return true if successful.  */
 
 static bool
-emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align)
+emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align,
+                           unsigned int expected_align, HOST_WIDE_INT expected_size)
 {
   rtx opalign = GEN_INT (align / BITS_PER_UNIT);
   int save_volatile_ok = volatile_ok;
   enum machine_mode mode;
 
+  if (expected_align < align)
+    expected_align = align;
+
   /* Since this is a move insn, we don't care about volatility.  */
   volatile_ok = 1;
 
@@ -1311,7 +1327,12 @@ emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align)
             that it doesn't fail the expansion because it thinks
             emitting the libcall would be more efficient.  */
 
-         pat = GEN_FCN ((int) code) (x, y, op2, opalign);
+         if (insn_data[(int) code].n_operands == 4)
+           pat = GEN_FCN ((int) code) (x, y, op2, opalign);
+         else
+           pat = GEN_FCN ((int) code) (x, y, op2, opalign,
+                                       GEN_INT (expected_align),
+                                       GEN_INT (expected_size));
          if (pat)
            {
              emit_insn (pat);
@@ -1330,11 +1351,11 @@ emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align)
 /* A subroutine of emit_block_move.  Expand a call to memcpy.
    Return the return value from memcpy, 0 otherwise.  */
 
-static rtx
+rtx
 emit_block_move_via_libcall (rtx dst, rtx src, rtx size, bool tailcall)
 {
   rtx dst_addr, src_addr;
-  tree call_expr, arg_list, fn, src_tree, dst_tree, size_tree;
+  tree call_expr, fn, src_tree, dst_tree, size_tree;
   enum machine_mode size_mode;
   rtx retval;
 
@@ -1365,17 +1386,10 @@ emit_block_move_via_libcall (rtx dst, rtx src, rtx size, bool tailcall)
   size_tree = make_tree (sizetype, size);
 
   fn = emit_block_move_libcall_fn (true);
-  arg_list = tree_cons (NULL_TREE, size_tree, NULL_TREE);
-  arg_list = tree_cons (NULL_TREE, src_tree, arg_list);
-  arg_list = tree_cons (NULL_TREE, dst_tree, arg_list);
-
-  /* Now we have to build up the CALL_EXPR itself.  */
-  call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
-  call_expr = build3 (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
-                     call_expr, arg_list, NULL_TREE);
+  call_expr = build_call_expr (fn, 3, dst_tree, src_tree, size_tree);
   CALL_EXPR_TAILCALL (call_expr) = tailcall;
 
-  retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
+  retval = expand_normal (call_expr);
 
   return retval;
 }
@@ -1403,6 +1417,8 @@ init_block_move_fn (const char *asmspec)
       TREE_PUBLIC (fn) = 1;
       DECL_ARTIFICIAL (fn) = 1;
       TREE_NOTHROW (fn) = 1;
+      DECL_VISIBILITY (fn) = VISIBILITY_DEFAULT;
+      DECL_VISIBILITY_SPECIFIED (fn) = 1;
 
       block_move_fn = fn;
     }
@@ -1849,7 +1865,7 @@ void
 emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
 {
   rtx *tmps, dst;
-  int start, i;
+  int start, finish, i;
   enum machine_mode m = GET_MODE (orig_dst);
 
   gcc_assert (GET_CODE (src) == PARALLEL);
@@ -1875,15 +1891,21 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
     start = 0;
   else
     start = 1;
+  finish = XVECLEN (src, 0);
 
-  tmps = alloca (sizeof (rtx) * XVECLEN (src, 0));
+  tmps = alloca (sizeof (rtx) * finish);
 
   /* Copy the (probable) hard regs into pseudos.  */
-  for (i = start; i < XVECLEN (src, 0); i++)
+  for (i = start; i < finish; i++)
     {
       rtx reg = XEXP (XVECEXP (src, 0, i), 0);
-      tmps[i] = gen_reg_rtx (GET_MODE (reg));
-      emit_move_insn (tmps[i], reg);
+      if (!REG_P (reg) || REGNO (reg) < FIRST_PSEUDO_REGISTER)
+       {
+         tmps[i] = gen_reg_rtx (GET_MODE (reg));
+         emit_move_insn (tmps[i], reg);
+       }
+      else
+       tmps[i] = reg;
     }
 
   /* If we won't be storing directly into memory, protect the real destination
@@ -1910,13 +1932,62 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
     }
   else if (!MEM_P (dst) && GET_CODE (dst) != CONCAT)
     {
-      dst = gen_reg_rtx (GET_MODE (orig_dst));
+      enum machine_mode outer = GET_MODE (dst);
+      enum machine_mode inner;
+      HOST_WIDE_INT bytepos;
+      bool done = false;
+      rtx temp;
+
+      if (!REG_P (dst) || REGNO (dst) < FIRST_PSEUDO_REGISTER)
+       dst = gen_reg_rtx (outer);
+
       /* Make life a bit easier for combine.  */
-      emit_move_insn (dst, CONST0_RTX (GET_MODE (orig_dst)));
+      /* If the first element of the vector is the low part
+        of the destination mode, use a paradoxical subreg to
+        initialize the destination.  */
+      if (start < finish)
+       {
+         inner = GET_MODE (tmps[start]);
+         bytepos = subreg_lowpart_offset (inner, outer);
+         if (INTVAL (XEXP (XVECEXP (src, 0, start), 1)) == bytepos)
+           {
+             temp = simplify_gen_subreg (outer, tmps[start],
+                                         inner, 0);
+             if (temp)
+               {
+                 emit_move_insn (dst, temp);
+                 done = true;
+                 start++;
+               }
+           }
+       }
+
+      /* If the first element wasn't the low part, try the last.  */
+      if (!done
+         && start < finish - 1)
+       {
+         inner = GET_MODE (tmps[finish - 1]);
+         bytepos = subreg_lowpart_offset (inner, outer);
+         if (INTVAL (XEXP (XVECEXP (src, 0, finish - 1), 1)) == bytepos)
+           {
+             temp = simplify_gen_subreg (outer, tmps[finish - 1],
+                                         inner, 0);
+             if (temp)
+               {
+                 emit_move_insn (dst, temp);
+                 done = true;
+                 finish--;
+               }
+           }
+       }
+
+      /* Otherwise, simply initialize the result to zero.  */
+      if (!done)
+        emit_move_insn (dst, CONST0_RTX (outer));
     }
 
   /* Process the pieces.  */
-  for (i = start; i < XVECLEN (src, 0); i++)
+  for (i = start; i < finish; i++)
     {
       HOST_WIDE_INT bytepos = INTVAL (XEXP (XVECEXP (src, 0, i), 1));
       enum machine_mode mode = GET_MODE (tmps[i]);
@@ -2434,7 +2505,8 @@ store_by_pieces_2 (rtx (*genfun) (rtx, ...), enum machine_mode mode,
    its length in bytes.  */
 
 rtx
-clear_storage (rtx object, rtx size, enum block_op_methods method)
+clear_storage_hints (rtx object, rtx size, enum block_op_methods method,
+                    unsigned int expected_align, HOST_WIDE_INT expected_size)
 {
   enum machine_mode mode = GET_MODE (object);
   unsigned int align;
@@ -2474,22 +2546,30 @@ clear_storage (rtx object, rtx size, enum block_op_methods method)
   if (GET_CODE (size) == CONST_INT
       && CLEAR_BY_PIECES_P (INTVAL (size), align))
     clear_by_pieces (object, INTVAL (size), align);
-  else if (set_storage_via_setmem (object, size, const0_rtx, align))
+  else if (set_storage_via_setmem (object, size, const0_rtx, align,
+                                  expected_align, expected_size))
     ;
   else
-    return clear_storage_via_libcall (object, size,
-                                     method == BLOCK_OP_TAILCALL);
+    return set_storage_via_libcall (object, size, const0_rtx,
+                                   method == BLOCK_OP_TAILCALL);
 
   return NULL;
 }
 
+rtx
+clear_storage (rtx object, rtx size, enum block_op_methods method)
+{
+  return clear_storage_hints (object, size, method, 0, -1);
+}
+
+
 /* A subroutine of clear_storage.  Expand a call to memset.
    Return the return value of memset, 0 otherwise.  */
 
-static rtx
-clear_storage_via_libcall (rtx object, rtx size, bool tailcall)
+rtx
+set_storage_via_libcall (rtx object, rtx size, rtx val, bool tailcall)
 {
-  tree call_expr, arg_list, fn, object_tree, size_tree;
+  tree call_expr, fn, object_tree, size_tree, val_tree;
   enum machine_mode size_mode;
   rtx retval;
 
@@ -2509,25 +2589,22 @@ clear_storage_via_libcall (rtx object, rtx size, 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)
+    val = convert_to_mode (TYPE_MODE (integer_type_node), val, 1);
   size_tree = make_tree (sizetype, size);
+  val_tree = make_tree (integer_type_node, val);
 
   fn = clear_storage_libcall_fn (true);
-  arg_list = tree_cons (NULL_TREE, size_tree, NULL_TREE);
-  arg_list = tree_cons (NULL_TREE, integer_zero_node, arg_list);
-  arg_list = tree_cons (NULL_TREE, object_tree, arg_list);
-
-  /* Now we have to build up the CALL_EXPR itself.  */
-  call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
-  call_expr = build3 (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
-                     call_expr, arg_list, NULL_TREE);
+  call_expr = build_call_expr (fn, 3,
+                              object_tree, integer_zero_node, size_tree);
   CALL_EXPR_TAILCALL (call_expr) = tailcall;
 
-  retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
+  retval = expand_normal (call_expr);
 
   return retval;
 }
 
-/* A subroutine of clear_storage_via_libcall.  Create the tree node
+/* A subroutine of set_storage_via_libcall.  Create the tree node
    for the function we use for block clears.  The first time FOR_CALL
    is true, we call assemble_external.  */
 
@@ -2550,6 +2627,8 @@ init_block_clear_fn (const char *asmspec)
       TREE_PUBLIC (fn) = 1;
       DECL_ARTIFICIAL (fn) = 1;
       TREE_NOTHROW (fn) = 1;
+      DECL_VISIBILITY (fn) = VISIBILITY_DEFAULT;
+      DECL_VISIBILITY_SPECIFIED (fn) = 1;
 
       block_clear_fn = fn;
     }
@@ -2579,7 +2658,8 @@ clear_storage_libcall_fn (int for_call)
 /* Expand a setmem pattern; return true if successful.  */
 
 bool
-set_storage_via_setmem (rtx object, rtx size, rtx val, unsigned int align)
+set_storage_via_setmem (rtx object, rtx size, rtx val, unsigned int align,
+                       unsigned int expected_align, HOST_WIDE_INT expected_size)
 {
   /* Try the most limited insn first, because there's no point
      including more than one in the machine description unless
@@ -2588,6 +2668,9 @@ set_storage_via_setmem (rtx object, rtx size, rtx val, unsigned int align)
   rtx opalign = GEN_INT (align / BITS_PER_UNIT);
   enum machine_mode mode;
 
+  if (expected_align < align)
+    expected_align = align;
+
   for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
        mode = GET_MODE_WIDER_MODE (mode))
     {
@@ -2628,7 +2711,12 @@ set_storage_via_setmem (rtx object, rtx size, rtx val, unsigned int align)
                opchar = copy_to_mode_reg (char_mode, opchar);
            }
 
-         pat = GEN_FCN ((int) code) (object, opsize, opchar, opalign);
+         if (insn_data[(int) code].n_operands == 4)
+           pat = GEN_FCN ((int) code) (object, opsize, opchar, opalign);
+         else
+           pat = GEN_FCN ((int) code) (object, opsize, opchar, opalign,
+                                       GEN_INT (expected_align),
+                                       GEN_INT (expected_size));
          if (pat)
            {
              emit_insn (pat);
@@ -2778,17 +2866,19 @@ emit_move_change_mode (enum machine_mode new_mode,
 {
   rtx ret;
 
-  if (reload_in_progress && MEM_P (x))
+  if (MEM_P (x))
     {
-      /* We can't use gen_lowpart here because it may call change_address
-        which is not appropriate if we were called when a reload was in
-        progress.  We don't have to worry about changing the address since
-        the size in bytes is supposed to be the same.  Copy the MEM to
-        change the mode and move any substitutions from the old MEM to
-        the new one.  */
-
-      ret = adjust_address_nv (x, new_mode, 0);
-      copy_replacements (x, ret);
+      /* We don't have to worry about changing the address since the
+        size in bytes is supposed to be the same.  */
+      if (reload_in_progress)
+       {
+         /* Copy the MEM to change the mode and move any
+            substitutions from the old MEM to the new one.  */
+         ret = adjust_address_nv (x, new_mode, 0);
+         copy_replacements (x, ret);
+       }
+      else
+       ret = adjust_address (x, new_mode, 0);
     }
   else
     {
@@ -2812,7 +2902,7 @@ emit_move_change_mode (enum machine_mode new_mode,
    emitted, or NULL if such a move could not be generated.  */
 
 static rtx
-emit_move_via_integer (enum machine_mode mode, rtx x, rtx y)
+emit_move_via_integer (enum machine_mode mode, rtx x, rtx y, bool force)
 {
   enum machine_mode imode;
   enum insn_code code;
@@ -2827,10 +2917,10 @@ emit_move_via_integer (enum machine_mode mode, rtx x, rtx y)
   if (code == CODE_FOR_nothing)
     return NULL_RTX;
 
-  x = emit_move_change_mode (imode, mode, x, false);
+  x = emit_move_change_mode (imode, mode, x, force);
   if (x == NULL_RTX)
     return NULL_RTX;
-  y = emit_move_change_mode (imode, mode, y, false);
+  y = emit_move_change_mode (imode, mode, y, force);
   if (y == NULL_RTX)
     return NULL_RTX;
   return emit_insn (GEN_FCN (code) (x, y));
@@ -2852,6 +2942,19 @@ emit_move_resolve_push (enum machine_mode mode, rtx x)
 #endif
   if (code == PRE_DEC || code == POST_DEC)
     adjust = -adjust;
+  else if (code == PRE_MODIFY || code == POST_MODIFY)
+    {
+      rtx expr = XEXP (XEXP (x, 0), 1);
+      HOST_WIDE_INT val;
+
+      gcc_assert (GET_CODE (expr) == PLUS || GET_CODE (expr) == MINUS);
+      gcc_assert (GET_CODE (XEXP (expr, 1)) == CONST_INT);
+      val = INTVAL (XEXP (expr, 1));
+      if (GET_CODE (expr) == MINUS)
+       val = -val;
+      gcc_assert (adjust == val || adjust == -val);
+      adjust = val;
+    }
 
   /* Do not use anti_adjust_stack, since we don't want to update
      stack_pointer_delta.  */
@@ -2865,13 +2968,13 @@ emit_move_resolve_push (enum machine_mode mode, rtx x)
     {
     case PRE_INC:
     case PRE_DEC:
+    case PRE_MODIFY:
       temp = stack_pointer_rtx;
       break;
     case POST_INC:
-      temp = plus_constant (stack_pointer_rtx, -GET_MODE_SIZE (mode));
-      break;
     case POST_DEC:
-      temp = plus_constant (stack_pointer_rtx, GET_MODE_SIZE (mode));
+    case POST_MODIFY:
+      temp = plus_constant (stack_pointer_rtx, -adjust);
       break;
     default:
       gcc_unreachable ();
@@ -2973,7 +3076,7 @@ emit_move_complex (enum machine_mode mode, rtx x, rtx y)
          return get_last_insn ();
        }
 
-      ret = emit_move_via_integer (mode, x, y);
+      ret = emit_move_via_integer (mode, x, y, true);
       if (ret)
        return ret;
     }
@@ -3011,11 +3114,43 @@ emit_move_ccmode (enum machine_mode mode, rtx x, rtx y)
     }
 
   /* Otherwise, find the MODE_INT mode of the same width.  */
-  ret = emit_move_via_integer (mode, x, y);
+  ret = emit_move_via_integer (mode, x, y, false);
   gcc_assert (ret != NULL);
   return ret;
 }
 
+/* Return true if word I of OP lies entirely in the
+   undefined bits of a paradoxical subreg.  */
+
+static bool
+undefined_operand_subword_p (rtx op, int i)
+{
+  enum machine_mode innermode, innermostmode;
+  int offset;
+  if (GET_CODE (op) != SUBREG)
+    return false;
+  innermode = GET_MODE (op);
+  innermostmode = GET_MODE (SUBREG_REG (op));
+  offset = i * UNITS_PER_WORD + SUBREG_BYTE (op);
+  /* The SUBREG_BYTE represents offset, as if the value were stored in
+     memory, except for a paradoxical subreg where we define
+     SUBREG_BYTE to be 0; undo this exception as in
+     simplify_subreg.  */
+  if (SUBREG_BYTE (op) == 0
+      && GET_MODE_SIZE (innermostmode) < GET_MODE_SIZE (innermode))
+    {
+      int difference = (GET_MODE_SIZE (innermostmode) - GET_MODE_SIZE (innermode));
+      if (WORDS_BIG_ENDIAN)
+       offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
+      if (BYTES_BIG_ENDIAN)
+       offset += difference % UNITS_PER_WORD;
+    }
+  if (offset >= GET_MODE_SIZE (innermostmode)
+      || offset <= -GET_MODE_SIZE (word_mode))
+    return true;
+  return false;
+}
+
 /* A subroutine of emit_move_insn_1.  Generate a move from Y into X.
    MODE is any multi-word or full-word mode that lacks a move_insn
    pattern.  Note that you will get better code if you define such
@@ -3053,14 +3188,21 @@ emit_move_multi_word (enum machine_mode mode, rtx x, rtx y)
        i++)
     {
       rtx xpart = operand_subword (x, i, 1, mode);
-      rtx ypart = operand_subword (y, i, 1, mode);
+      rtx ypart;
+
+      /* Do not generate code for a move if it would come entirely
+        from the undefined bits of a paradoxical subreg.  */
+      if (undefined_operand_subword_p (y, i))
+       continue;
+
+      ypart = operand_subword (y, i, 1, mode);
 
       /* If we can't get a part of Y, put Y into memory if it is a
         constant.  Otherwise, force it into a register.  Then we must
         be able to get a part of Y.  */
       if (ypart == 0 && CONSTANT_P (y))
        {
-         y = force_const_mem (mode, y);
+         y = use_anchored_address (force_const_mem (mode, y));
          ypart = operand_subword (y, i, 1, mode);
        }
       else if (ypart == 0)
@@ -3110,6 +3252,17 @@ emit_move_insn_1 (rtx x, rtx y)
   if (COMPLEX_MODE_P (mode))
     return emit_move_complex (mode, x, y);
 
+  if (GET_MODE_CLASS (mode) == MODE_DECIMAL_FLOAT)
+    {
+      rtx result = emit_move_via_integer (mode, x, y, true);
+
+      /* If we can't find an integer mode, use multi words.  */
+      if (result)
+       return result;
+      else
+       return emit_move_multi_word (mode, x, y);
+    }
+
   if (GET_MODE_CLASS (mode) == MODE_CC)
     return emit_move_ccmode (mode, x, y);
 
@@ -3119,7 +3272,7 @@ emit_move_insn_1 (rtx x, rtx y)
      fits within a HOST_WIDE_INT.  */
   if (!CONSTANT_P (y) || GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
     {
-      rtx ret = emit_move_via_integer (mode, x, y);
+      rtx ret = emit_move_via_integer (mode, x, y, false);
       if (ret)
        return ret;
     }
@@ -3162,6 +3315,8 @@ emit_move_insn (rtx x, rtx y)
             of the non-legitimate constant.  */
          if (!y)
            y = y_cst;
+         else
+           y = use_anchored_address (y);
        }
     }
 
@@ -3253,7 +3408,11 @@ compress_float_constant (rtx x, rtx y)
        }
       else
        continue;
+
+      /* For CSE's benefit, force the compressed constant pool entry
+        into a new pseudo.  This constant may be used in different modes,
+        and if not, combine will put things back together for us.  */
+      trunc_y = force_reg (srcmode, trunc_y);
       emit_unop_insn (ic, x, trunc_y, UNKNOWN);
       last_insn = get_last_insn ();
 
@@ -3471,7 +3630,8 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
 
   xinner = x;
 
-  if (mode == BLKmode)
+  if (mode == BLKmode
+      || (STRICT_ALIGNMENT && align < GET_MODE_ALIGNMENT (mode)))
     {
       /* Copy a block into the stack, entirely or partially.  */
 
@@ -3483,6 +3643,20 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
       offset = partial % (PARM_BOUNDARY / BITS_PER_UNIT);
       used = partial - offset;
 
+      if (mode != BLKmode)
+       {
+         /* A value is to be stored in an insufficiently aligned
+            stack slot; copy via a suitably aligned slot if
+            necessary.  */
+         size = GEN_INT (GET_MODE_SIZE (mode));
+         if (!MEM_P (xinner))
+           {
+             temp = assign_temp (type, 0, 1, 1);
+             emit_move_insn (temp, xinner);
+             xinner = temp;
+           }
+       }
+
       gcc_assert (size);
 
       /* USED is now the # of bytes we need not copy to the stack
@@ -3891,13 +4065,16 @@ expand_assignment (tree to, tree from)
   rtx result;
 
   /* Don't crash if the lhs of the assignment was erroneous.  */
-
   if (TREE_CODE (to) == ERROR_MARK)
     {
-      result = expand_expr (from, NULL_RTX, VOIDmode, 0);
+      result = expand_normal (from);
       return;
     }
 
+  /* Optimize away no-op moves without side-effects.  */
+  if (operand_equal_p (to, from, 0))
+    return;
+
   /* Assignment of a structure component needs special treatment
      if the structure component's rtx is not simply a MEM.
      Assignment of an array element at a constant index, and assignment of
@@ -3920,14 +4097,22 @@ expand_assignment (tree to, tree from)
       /* If we are going to use store_bit_field and extract_bit_field,
         make sure to_rtx will be safe for multiple use.  */
 
-      to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, 0);
+      to_rtx = expand_normal (tem);
 
       if (offset != 0)
        {
-         rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
+         rtx offset_rtx;
 
-         gcc_assert (MEM_P (to_rtx));
+         if (!MEM_P (to_rtx))
+           {
+             /* We can get constant negative offsets into arrays with broken
+                user code.  Translate this to a trap instead of ICEing.  */
+             gcc_assert (TREE_CODE (offset) == INTEGER_CST);
+             expand_builtin_trap ();
+             to_rtx = gen_rtx_MEM (BLKmode, const0_rtx);
+           }
 
+         offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
 #ifdef POINTERS_EXTEND_UNSIGNED
          if (GET_MODE (offset_rtx) != Pmode)
            offset_rtx = convert_to_mode (Pmode, offset_rtx, 0);
@@ -4020,7 +4205,7 @@ expand_assignment (tree to, tree from)
       rtx value;
 
       push_temp_slots ();
-      value = expand_expr (from, NULL_RTX, VOIDmode, 0);
+      value = expand_normal (from);
       if (to_rtx == 0)
        to_rtx = expand_expr (to, NULL_RTX, VOIDmode, EXPAND_WRITE);
 
@@ -4081,7 +4266,7 @@ expand_assignment (tree to, tree from)
 
       push_temp_slots ();
       size = expr_size (from);
-      from_rtx = expand_expr (from, NULL_RTX, VOIDmode, 0);
+      from_rtx = expand_normal (from);
 
       emit_library_call (memmove_libfunc, LCT_NORMAL,
                         VOIDmode, 3, XEXP (to_rtx, 0), Pmode,
@@ -4187,14 +4372,14 @@ store_expr (tree exp, rtx target, int call_param_p)
        {
          if (TYPE_UNSIGNED (TREE_TYPE (exp))
              != SUBREG_PROMOTED_UNSIGNED_P (target))
-           exp = convert
+           exp = fold_convert
              (lang_hooks.types.signed_or_unsigned_type
               (SUBREG_PROMOTED_UNSIGNED_P (target), TREE_TYPE (exp)), exp);
 
-         exp = convert (lang_hooks.types.type_for_mode
-                        (GET_MODE (SUBREG_REG (target)),
-                         SUBREG_PROMOTED_UNSIGNED_P (target)),
-                        exp);
+         exp = fold_convert (lang_hooks.types.type_for_mode
+                               (GET_MODE (SUBREG_REG (target)),
+                                SUBREG_PROMOTED_UNSIGNED_P (target)),
+                             exp);
 
          inner_target = SUBREG_REG (target);
        }
@@ -4384,28 +4569,24 @@ store_expr (tree exp, rtx target, int call_param_p)
   return NULL_RTX;
 }
 \f
-/* Examine CTOR to discover:
-   * how many scalar fields are set to nonzero values,
-     and place it in *P_NZ_ELTS;
-   * how many scalar fields are set to non-constant values,
-     and place it in  *P_NC_ELTS; and
-   * how many scalar fields in total are in CTOR,
-     and place it in *P_ELT_COUNT.
-   * if a type is a union, and the initializer from the constructor
-     is not the largest element in the union, then set *p_must_clear.  */
+/* Helper for categorize_ctor_elements.  Identical interface.  */
 
-static void
+static bool
 categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts,
-                           HOST_WIDE_INT *p_nc_elts,
                            HOST_WIDE_INT *p_elt_count,
                            bool *p_must_clear)
 {
   unsigned HOST_WIDE_INT idx;
-  HOST_WIDE_INT nz_elts, nc_elts, elt_count;
+  HOST_WIDE_INT nz_elts, elt_count;
   tree value, purpose;
 
+  /* Whether CTOR is a valid constant initializer, in accordance with what
+     initializer_constant_valid_p does.  If inferred from the constructor
+     elements, true until proven otherwise.  */
+  bool const_from_elts_p = constructor_static_from_elts_p (ctor);
+  bool const_p = const_from_elts_p ? true : TREE_STATIC (ctor);
+
   nz_elts = 0;
-  nc_elts = 0;
   elt_count = 0;
 
   FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), idx, purpose, value)
@@ -4427,11 +4608,16 @@ categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts,
        {
        case CONSTRUCTOR:
          {
-           HOST_WIDE_INT nz = 0, nc = 0, ic = 0;
-           categorize_ctor_elements_1 (value, &nz, &nc, &ic, p_must_clear);
+           HOST_WIDE_INT nz = 0, ic = 0;
+           
+           bool const_elt_p
+             = categorize_ctor_elements_1 (value, &nz, &ic, p_must_clear);
+
            nz_elts += mult * nz;
-           nc_elts += mult * nc;
-           elt_count += mult * ic;
+           elt_count += mult * ic;
+
+           if (const_from_elts_p && const_p)
+             const_p = const_elt_p;
          }
          break;
 
@@ -4470,8 +4656,10 @@ categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts,
        default:
          nz_elts += mult;
          elt_count += mult;
-         if (!initializer_constant_valid_p (value, TREE_TYPE (value)))
-           nc_elts += mult;
+
+         if (const_from_elts_p && const_p)
+           const_p = initializer_constant_valid_p (value, TREE_TYPE (value))
+                     != NULL_TREE;
          break;
        }
     }
@@ -4513,22 +4701,33 @@ categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts,
     }
 
   *p_nz_elts += nz_elts;
-  *p_nc_elts += nc_elts;
   *p_elt_count += elt_count;
+
+  return const_p;
 }
 
-void
+/* Examine CTOR to discover:
+   * how many scalar fields are set to nonzero values,
+     and place it in *P_NZ_ELTS;
+   * how many scalar fields in total are in CTOR,
+     and place it in *P_ELT_COUNT.
+   * if a type is a union, and the initializer from the constructor
+     is not the largest element in the union, then set *p_must_clear.
+
+   Return whether or not CTOR is a valid static constant initializer, the same
+   as "initializer_constant_valid_p (CTOR, TREE_TYPE (CTOR)) != 0".  */
+
+bool
 categorize_ctor_elements (tree ctor, HOST_WIDE_INT *p_nz_elts,
-                         HOST_WIDE_INT *p_nc_elts,
                          HOST_WIDE_INT *p_elt_count,
                          bool *p_must_clear)
 {
   *p_nz_elts = 0;
-  *p_nc_elts = 0;
   *p_elt_count = 0;
   *p_must_clear = false;
-  categorize_ctor_elements_1 (ctor, p_nz_elts, p_nc_elts, p_elt_count,
-                             p_must_clear);
+
+  return
+    categorize_ctor_elements_1 (ctor, p_nz_elts, p_elt_count, p_must_clear);
 }
 
 /* Count the number of scalars in TYPE.  Return -1 on overflow or
@@ -4608,7 +4807,6 @@ count_type_elements (tree type, bool allow_flexarr)
     case REAL_TYPE:
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
-    case CHAR_TYPE:
     case POINTER_TYPE:
     case OFFSET_TYPE:
     case REFERENCE_TYPE:
@@ -4631,10 +4829,10 @@ mostly_zeros_p (tree exp)
   if (TREE_CODE (exp) == CONSTRUCTOR)
 
     {
-      HOST_WIDE_INT nz_elts, nc_elts, count, elts;
+      HOST_WIDE_INT nz_elts, count, elts;
       bool must_clear;
 
-      categorize_ctor_elements (exp, &nz_elts, &nc_elts, &count, &must_clear);
+      categorize_ctor_elements (exp, &nz_elts, &count, &must_clear);
       if (must_clear)
        return 1;
 
@@ -4654,10 +4852,10 @@ all_zeros_p (tree exp)
   if (TREE_CODE (exp) == CONSTRUCTOR)
 
     {
-      HOST_WIDE_INT nz_elts, nc_elts, count;
+      HOST_WIDE_INT nz_elts, count;
       bool must_clear;
 
-      categorize_ctor_elements (exp, &nz_elts, &nc_elts, &count, &must_clear);
+      categorize_ctor_elements (exp, &nz_elts, &count, &must_clear);
       return nz_elts == 0;
     }
 
@@ -4828,7 +5026,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                                                    make_tree (TREE_TYPE (exp),
                                                               target));
 
-               offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
+               offset_rtx = expand_normal (offset);
                gcc_assert (MEM_P (to_rtx));
                
 #ifdef POINTERS_EXTEND_UNSIGNED
@@ -4863,13 +5061,13 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                  {
                    type = lang_hooks.types.type_for_size
                      (BITS_PER_WORD, TYPE_UNSIGNED (type));
-                   value = convert (type, value);
+                   value = fold_convert (type, value);
                  }
                
                if (BYTES_BIG_ENDIAN)
                  value
                   = fold_build2 (LSHIFT_EXPR, type, value,
-                                  build_int_cst (NULL_TREE,
+                                  build_int_cst (type,
                                                  BITS_PER_WORD - bitsize));
                bitsize = BITS_PER_WORD;
                mode = word_mode;
@@ -5051,7 +5249,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                    rtx loop_end = gen_label_rtx ();
                    tree exit_cond;
                    
-                   expand_expr (hi_index, NULL_RTX, VOIDmode, 0);
+                   expand_normal (hi_index);
                    unsignedp = TYPE_UNSIGNED (domain);
                    
                    index = build_decl (VAR_DECL, NULL_TREE, domain);
@@ -5067,15 +5265,19 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                    emit_label (loop_start);
 
                    /* Assign value to element index.  */
-                   position
-                     = convert (ssizetype,
-                                fold_build2 (MINUS_EXPR, TREE_TYPE (index),
-                                             index, TYPE_MIN_VALUE (domain)));
-                   position = size_binop (MULT_EXPR, position,
-                                          convert (ssizetype,
-                                                   TYPE_SIZE_UNIT (elttype)));
+                   position =
+                     fold_convert (ssizetype,
+                                   fold_build2 (MINUS_EXPR,
+                                                TREE_TYPE (index),
+                                                index,
+                                                TYPE_MIN_VALUE (domain)));
+
+                   position =
+                       size_binop (MULT_EXPR, position,
+                                   fold_convert (ssizetype,
+                                                 TYPE_SIZE_UNIT (elttype)));
                    
-                   pos_rtx = expand_expr (position, 0, VOIDmode, 0);
+                   pos_rtx = expand_normal (position);
                    xtarget = offset_address (target, pos_rtx,
                                              highest_pow2_factor (position));
                    xtarget = adjust_address (xtarget, mode, 0);
@@ -5117,11 +5319,12 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                                                     index,
                                                     TYPE_MIN_VALUE (domain)));
                
-               position = size_binop (MULT_EXPR, index,
-                                      convert (ssizetype,
-                                               TYPE_SIZE_UNIT (elttype)));
+               position =
+                 size_binop (MULT_EXPR, index,
+                             fold_convert (ssizetype,
+                                           TYPE_SIZE_UNIT (elttype)));
                xtarget = offset_address (target,
-                                         expand_expr (position, 0, VOIDmode, 0),
+                                         expand_normal (position),
                                          highest_pow2_factor (position));
                xtarget = adjust_address (xtarget, mode, 0);
                store_expr (value, xtarget, 0);
@@ -5220,7 +5423,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
          }
        
        /* Inform later passes that the old value is dead.  */
-       if (!cleared && REG_P (target))
+       if (!cleared && !vector && REG_P (target))
          emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
 
         /* Store each element of the constructor into the corresponding
@@ -5247,7 +5450,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                   vectors in the case of BLKmode vectors.  */
                gcc_assert (TREE_CODE (TREE_TYPE (value)) != VECTOR_TYPE);
                RTVEC_ELT (vector, eltpos)
-                 = expand_expr (value, NULL_RTX, VOIDmode, 0);
+                 = expand_normal (value);
              }
            else
              {
@@ -5385,7 +5588,7 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
            }
        }
 
-      temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
+      temp = expand_normal (exp);
 
       /* If BITSIZE is narrower than the size of the type of EXP
         we will be narrowing TEMP.  Normally, what's wanted are the
@@ -5505,6 +5708,13 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
     {
       size_tree = TREE_OPERAND (exp, 1);
       *punsignedp = BIT_FIELD_REF_UNSIGNED (exp);
+      
+      /* For vector types, with the correct size of access, use the mode of
+        inner type.  */
+      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == VECTOR_TYPE
+         && TREE_TYPE (exp) == TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0)))
+         && tree_int_cst_equal (size_tree, TYPE_SIZE (TREE_TYPE (exp))))
+        mode = TYPE_MODE (TREE_TYPE (exp));
     }
   else
     {
@@ -5572,7 +5782,7 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
 
            offset = size_binop (PLUS_EXPR, offset,
                                 size_binop (MULT_EXPR,
-                                            convert (sizetype, index),
+                                            fold_convert (sizetype, index),
                                             unit_size));
          }
          break;
@@ -5611,7 +5821,8 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
   /* If OFFSET is constant, see if we can return the whole thing as a
      constant bit position.  Otherwise, split it up.  */
   if (host_integerp (offset, 0)
-      && 0 != (tem = size_binop (MULT_EXPR, convert (bitsizetype, offset),
+      && 0 != (tem = size_binop (MULT_EXPR,
+                                fold_convert (bitsizetype, offset),
                                 bitsize_unit_node))
       && 0 != (tem = size_binop (PLUS_EXPR, tem, bit_offset))
       && host_integerp (tem, 0))
@@ -5779,15 +5990,6 @@ force_operand (rtx value, rtx target)
       return subtarget;
     }
 
-  if (code == ZERO_EXTEND || code == SIGN_EXTEND)
-    {
-      if (!target)
-       target = gen_reg_rtx (GET_MODE (value));
-      convert_move (target, force_operand (XEXP (value, 0), NULL),
-                   code == ZERO_EXTEND);
-      return target;
-    }
-
   if (ARITHMETIC_P (value))
     {
       op2 = XEXP (value, 1);
@@ -5859,8 +6061,32 @@ force_operand (rtx value, rtx target)
     }
   if (UNARY_P (value))
     {
+      if (!target)
+       target = gen_reg_rtx (GET_MODE (value));
       op1 = force_operand (XEXP (value, 0), NULL_RTX);
-      return expand_simple_unop (GET_MODE (value), code, op1, target, 0);
+      switch (code)
+       {
+       case ZERO_EXTEND:
+       case SIGN_EXTEND:
+       case TRUNCATE:
+       case FLOAT_EXTEND:
+       case FLOAT_TRUNCATE:
+         convert_move (target, op1, code == ZERO_EXTEND);
+         return target;
+
+       case FIX:
+       case UNSIGNED_FIX:
+         expand_fix (target, op1, code == UNSIGNED_FIX);
+         return target;
+
+       case FLOAT:
+       case UNSIGNED_FLOAT:
+         expand_float (target, op1, code == UNSIGNED_FLOAT);
+         return target;
+
+       default:
+         return expand_simple_unop (GET_MODE (value), code, op1, target, 0);
+       }
     }
 
 #ifdef INSN_SCHEDULING
@@ -5949,6 +6175,19 @@ safe_from_p (rtx x, tree exp, int top_p)
                return safe_from_p (x, exp, 0);
            }
        }
+      else if (TREE_CODE (exp) == CONSTRUCTOR)
+       {
+         constructor_elt *ce;
+         unsigned HOST_WIDE_INT idx;
+
+         for (idx = 0;
+              VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (exp), idx, ce);
+              idx++)
+           if ((ce->index != NULL_TREE && !safe_from_p (x, ce->index, 0))
+               || !safe_from_p (x, ce->value, 0))
+             return 0;
+         return 1;
+       }
       else if (TREE_CODE (exp) == ERROR_MARK)
        return 1;       /* An already-visited SAVE_EXPR? */
       else
@@ -5973,6 +6212,7 @@ safe_from_p (rtx x, tree exp, int top_p)
 
     case tcc_expression:
     case tcc_reference:
+    case tcc_vl_exp:
       /* Now do code-specific tests.  EXP_RTL is set to any rtx we find in
         the expression.  If it is set, we conflict iff we are that rtx or
         both are in memory.  Otherwise, we check all operands of the
@@ -6035,7 +6275,7 @@ safe_from_p (rtx x, tree exp, int top_p)
       if (exp_rtl)
        break;
 
-      nops = TREE_CODE_LENGTH (TREE_CODE (exp));
+      nops = TREE_OPERAND_LENGTH (exp);
       for (i = 0; i < nops; i++)
        if (TREE_OPERAND (exp, i) != 0
            && ! safe_from_p (x, TREE_OPERAND (exp, i), 0))
@@ -6052,6 +6292,9 @@ safe_from_p (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
@@ -6096,7 +6339,7 @@ highest_pow2_factor (tree exp)
         a MIN_EXPR, or a MAX_EXPR.  If the constant overflows, we have an
         erroneous program, so return BIGGEST_ALIGNMENT to avoid any
         later ICE.  */
-      if (TREE_CONSTANT_OVERFLOW (exp))
+      if (TREE_OVERFLOW (exp))
        return BIGGEST_ALIGNMENT;
       else
        {
@@ -6166,6 +6409,19 @@ highest_pow2_factor_for_target (tree target, tree exp)
   return MAX (factor, target_align);
 }
 \f
+/* Return &VAR expression for emulated thread local VAR.  */
+
+static tree
+emutls_var_address (tree var)
+{
+  tree emuvar = emutls_decl (var);
+  tree fn = built_in_decls [BUILT_IN_EMUTLS_GET_ADDRESS];
+  tree arg = build_fold_addr_expr_with_type (emuvar, ptr_type_node);
+  tree arglist = build_tree_list (NULL_TREE, arg);
+  tree call = build_function_call_expr (fn, arglist);
+  return fold_convert (build_pointer_type (TREE_TYPE (var)), call);
+}
+\f
 /* Expands variable VAR.  */
 
 void
@@ -6228,6 +6484,20 @@ expand_operands (tree exp0, tree exp1, rtx target, rtx *op0, rtx *op1,
 }
 
 \f
+/* Return a MEM that contains constant EXP.  DEFER is as for
+   output_constant_def and MODIFIER is as for expand_expr.  */
+
+static rtx
+expand_expr_constant (tree exp, int defer, enum expand_modifier modifier)
+{
+  rtx mem;
+
+  mem = output_constant_def (exp, defer);
+  if (modifier != EXPAND_INITIALIZER)
+    mem = use_anchored_address (mem);
+  return mem;
+}
+
 /* A subroutine of expand_expr_addr_expr.  Evaluate the address of EXP.
    The TARGET, TMODE and MODIFIER arguments are as for expand_expr.  */
 
@@ -6249,14 +6519,14 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
      exception here is STRING_CST.  */
   if (TREE_CODE (exp) == CONSTRUCTOR
       || CONSTANT_CLASS_P (exp))
-    return XEXP (output_constant_def (exp, 0), 0);
+    return XEXP (expand_expr_constant (exp, 0, modifier), 0);
 
   /* Everything must be something allowed by is_gimple_addressable.  */
   switch (TREE_CODE (exp))
     {
     case INDIRECT_REF:
       /* This case will happen via recursion for &a->b.  */
-      return expand_expr (TREE_OPERAND (exp, 0), target, tmode, EXPAND_NORMAL);
+      return expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
 
     case CONST_DECL:
       /* Recurse and make the output_constant_def clause above handle this.  */
@@ -6280,6 +6550,18 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
       inner = TREE_OPERAND (exp, 0);
       break;
 
+    case VAR_DECL:
+      /* TLS emulation hook - replace __thread VAR's &VAR with
+        __emutls_get_address (&_emutls.VAR).  */
+      if (! targetm.have_tls
+         && TREE_CODE (exp) == VAR_DECL
+         && DECL_THREAD_LOCAL_P (exp))
+       {
+         exp = emutls_var_address (exp);
+         return expand_expr (exp, target, tmode, modifier);
+       }
+      /* Fall through.  */
+
     default:
       /* If the object is a DECL, then expand it for its rtl.  Don't bypass
         expand_expr, as that can have various side effects; LABEL_DECLs for
@@ -6338,7 +6620,7 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
       result = convert_memory_address (tmode, result);
       tmp = convert_memory_address (tmode, tmp);
 
-      if (modifier == EXPAND_SUM)
+      if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
        result = gen_rtx_PLUS (tmode, result, tmp);
       else
        {
@@ -6458,7 +6740,7 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
 
   /* Handle ERROR_MARK before anybody tries to access its type.  */
   if (TREE_CODE (exp) == ERROR_MARK
-      || TREE_CODE (TREE_TYPE (exp)) == ERROR_MARK)
+      || (!GIMPLE_TUPLE_P (exp) && TREE_CODE (TREE_TYPE (exp)) == ERROR_MARK))
     {
       ret = CONST0_RTX (tmode);
       return ret ? ret : const0_rtx;
@@ -6480,7 +6762,7 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
      information.  It would be better of the diagnostic routines
      used the file/line information embedded in the tree nodes rather
      than globals.  */
-  if (cfun && EXPR_HAS_LOCATION (exp))
+  if (cfun && cfun->ib_boundaries_block && EXPR_HAS_LOCATION (exp))
     {
       location_t saved_location = input_location;
       input_location = EXPR_LOCATION (exp);
@@ -6527,15 +6809,15 @@ static rtx
 expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                    enum expand_modifier modifier, rtx *alt_rtl)
 {
-  rtx op0, op1, temp;
-  tree type = TREE_TYPE (exp);
+  rtx op0, op1, 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;
+  tree context, subexp0, subexp1;
   bool reduce_bit_field = false;
 #define REDUCE_BIT_FIELD(expr) (reduce_bit_field && !ignore              \
                                 ? reduce_to_bit_field_precision ((expr), \
@@ -6543,8 +6825,18 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                                                                  type)   \
                                 : (expr))
 
-  mode = TYPE_MODE (type);
-  unsignedp = TYPE_UNSIGNED (type);
+  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);
+    }
   if (lang_hooks.reduce_bit_field_operations
       && TREE_CODE (type) == INTEGER_TYPE
       && GET_MODE_PRECISION (mode) > TYPE_PRECISION (type))
@@ -6645,11 +6937,22 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
          && (TREE_STATIC (exp) || DECL_EXTERNAL (exp)))
        layout_decl (exp, 0);
 
+      /* TLS emulation hook - replace __thread vars with
+        *__emutls_get_address (&_emutls.var).  */
+      if (! targetm.have_tls
+         && TREE_CODE (exp) == VAR_DECL
+         && DECL_THREAD_LOCAL_P (exp))
+       {
+         exp = build_fold_indirect_ref (emutls_var_address (exp));
+         return expand_expr_real_1 (exp, target, tmode, modifier, NULL);
+       }
+
       /* ... fall through ...  */
 
     case FUNCTION_DECL:
     case RESULT_DECL:
-      gcc_assert (DECL_RTL (exp));
+      decl_rtl = DECL_RTL (exp);
+      gcc_assert (decl_rtl);
 
       /* 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
@@ -6676,27 +6979,24 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
         from its initializer, while the initializer is still being parsed.
         See expand_decl.  */
 
-      if (MEM_P (DECL_RTL (exp))
-              && REG_P (XEXP (DECL_RTL (exp), 0)))
-       temp = validize_mem (DECL_RTL (exp));
+      if (MEM_P (decl_rtl) && REG_P (XEXP (decl_rtl, 0)))
+       temp = validize_mem (decl_rtl);
 
       /* If DECL_RTL is memory, we are in the normal case and either
         the address is not valid or it is not a register and -fforce-addr
         is specified, get the address into a register.  */
 
-      else if (MEM_P (DECL_RTL (exp))
-              && modifier != EXPAND_CONST_ADDRESS
-              && modifier != EXPAND_SUM
-              && modifier != EXPAND_INITIALIZER
-              && (! memory_address_p (DECL_MODE (exp),
-                                      XEXP (DECL_RTL (exp), 0))
-                  || (flag_force_addr
-                      && !REG_P (XEXP (DECL_RTL (exp), 0)))))
+      else if (MEM_P (decl_rtl) && modifier != EXPAND_INITIALIZER)
        {
          if (alt_rtl)
-           *alt_rtl = DECL_RTL (exp);
-         temp = replace_equiv_address (DECL_RTL (exp),
-                                       copy_rtx (XEXP (DECL_RTL (exp), 0)));
+           *alt_rtl = decl_rtl;
+         decl_rtl = use_anchored_address (decl_rtl);
+         if (modifier != EXPAND_CONST_ADDRESS
+             && modifier != EXPAND_SUM
+             && (!memory_address_p (DECL_MODE (exp), XEXP (decl_rtl, 0))
+                 || (flag_force_addr && !REG_P (XEXP (decl_rtl, 0)))))
+           temp = replace_equiv_address (decl_rtl,
+                                         copy_rtx (XEXP (decl_rtl, 0)));
        }
 
       /* If we got something, return it.  But first, set the alignment
@@ -6713,24 +7013,25 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
         must be a promoted value.  We return a SUBREG of the wanted mode,
         but mark it so that we know that it was already extended.  */
 
-      if (REG_P (DECL_RTL (exp))
-         && GET_MODE (DECL_RTL (exp)) != DECL_MODE (exp))
+      if (REG_P (decl_rtl)
+         && GET_MODE (decl_rtl) != DECL_MODE (exp))
        {
          enum machine_mode pmode;
          
          /* Get the signedness used for this variable.  Ensure we get the
             same mode we got when the variable was declared.  */
          pmode = promote_mode (type, DECL_MODE (exp), &unsignedp,
-                               (TREE_CODE (exp) == RESULT_DECL ? 1 : 0));
-         gcc_assert (GET_MODE (DECL_RTL (exp)) == pmode);
+                               (TREE_CODE (exp) == RESULT_DECL
+                                || TREE_CODE (exp) == PARM_DECL) ? 1 : 0);
+         gcc_assert (GET_MODE (decl_rtl) == pmode);
 
-         temp = gen_lowpart_SUBREG (mode, DECL_RTL (exp));
+         temp = gen_lowpart_SUBREG (mode, decl_rtl);
          SUBREG_PROMOTED_VAR_P (temp) = 1;
          SUBREG_PROMOTED_UNSIGNED_SET (temp, unsignedp);
          return temp;
        }
 
-      return DECL_RTL (exp);
+      return decl_rtl;
 
     case INTEGER_CST:
       temp = immed_double_const (TREE_INT_CST_LOW (exp),
@@ -6741,21 +7042,30 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
         simplified by validate_replace_rtx during virtual register
         instantiation, which can result in unrecognizable insns.
         Avoid this by forcing all overflows into registers.  */
-      if (TREE_CONSTANT_OVERFLOW (exp)
+      if (TREE_OVERFLOW (exp)
          && modifier != EXPAND_INITIALIZER)
        temp = force_reg (mode, temp);
 
       return temp;
 
     case VECTOR_CST:
-      if (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (exp))) == MODE_VECTOR_INT
-         || GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (exp))) == MODE_VECTOR_FLOAT)
-       return const_vector_from_tree (exp);
-      else
-       return expand_expr (build_constructor_from_list
-                           (TREE_TYPE (exp),
-                            TREE_VECTOR_CST_ELTS (exp)),
-                           ignore ? const0_rtx : target, tmode, modifier);
+      {
+       tree tmp = NULL_TREE;
+       if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
+           || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
+         return const_vector_from_tree (exp);
+       if (GET_MODE_CLASS (mode) == MODE_INT)
+         {
+           tree type_for_mode = lang_hooks.types.type_for_mode (mode, 1);
+           if (type_for_mode)
+             tmp = fold_unary (VIEW_CONVERT_EXPR, type_for_mode, exp);
+         }
+       if (!tmp)
+         tmp = build_constructor_from_list (type,
+                                            TREE_VECTOR_CST_ELTS (exp));
+       return expand_expr (tmp, ignore ? const0_rtx : target,
+                           tmode, modifier);
+      }
 
     case CONST_DECL:
       return expand_expr (DECL_INITIAL (exp), target, VOIDmode, modifier);
@@ -6799,7 +7109,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       /* ... fall through ...  */
 
     case STRING_CST:
-      temp = output_constant_def (exp, 1);
+      temp = expand_expr_constant (exp, 1, modifier);
 
       /* temp contains a constant address.
         On RISC machines where a constant address isn't valid,
@@ -6900,7 +7210,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                    || modifier == EXPAND_CONST_ADDRESS)
                   && TREE_CONSTANT (exp)))
        {
-         rtx constructor = output_constant_def (exp, 1);
+         rtx constructor = expand_expr_constant (exp, 1, modifier);
 
          if (modifier != EXPAND_CONST_ADDRESS
              && modifier != EXPAND_INITIALIZER
@@ -6966,7 +7276,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
            int icode;
            rtx reg, insn;
 
-           gcc_assert (modifier == EXPAND_NORMAL);
+           gcc_assert (modifier == EXPAND_NORMAL
+                       || modifier == EXPAND_STACK_PARM);
 
            /* The vectorizer should have already checked the mode.  */
            icode = movmisalign_optab->handlers[mode].insn_code;
@@ -7072,17 +7383,36 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                          break;
                        }
                  }
-               else if (TREE_CODE (init) == STRING_CST
-                        && 0 > compare_tree_int (index,
-                                                 TREE_STRING_LENGTH (init)))
+               else if(TREE_CODE (init) == STRING_CST)
                  {
-                   tree type = TREE_TYPE (TREE_TYPE (init));
-                   enum machine_mode mode = TYPE_MODE (type);
-
-                   if (GET_MODE_CLASS (mode) == MODE_INT
-                       && GET_MODE_SIZE (mode) == 1)
-                     return gen_int_mode (TREE_STRING_POINTER (init)
-                                          [TREE_INT_CST_LOW (index)], mode);
+                   tree index1 = index;
+                   tree low_bound = array_ref_low_bound (exp);
+                   index1 = fold_convert (sizetype, TREE_OPERAND (exp, 1));
+                   
+                   /* Optimize the special-case of a zero lower bound.
+                   
+                      We convert the low_bound to sizetype to avoid some problems
+                      with constant folding.  (E.g. suppose the lower bound is 1,
+                      and its mode is QI.  Without the conversion,l (ARRAY
+                      +(INDEX-(unsigned char)1)) becomes ((ARRAY+(-(unsigned char)1))
+                      +INDEX), which becomes (ARRAY+255+INDEX).  Opps!)  */
+                   
+                   if (! integer_zerop (low_bound))
+                     index1 = size_diffop (index1, fold_convert (sizetype,
+                                                                 low_bound));
+                 
+                   if (0 > compare_tree_int (index1,
+                                             TREE_STRING_LENGTH (init)))
+                     {
+                       tree type = TREE_TYPE (TREE_TYPE (init));
+                       enum machine_mode mode = TYPE_MODE (type);
+
+                       if (GET_MODE_CLASS (mode) == MODE_INT
+                           && GET_MODE_SIZE (mode) == 1)
+                         return gen_int_mode (TREE_STRING_POINTER (init)
+                                              [TREE_INT_CST_LOW (index1)],
+                                              mode);
+                     }
                  }
              }
          }
@@ -7178,25 +7508,30 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                          || modifier == EXPAND_STACK_PARM)
                         ? modifier : EXPAND_NORMAL);
 
-       /* If this is a constant, put it into a register if it is a
-          legitimate constant and OFFSET is 0 and memory if it isn't.  */
+       /* If this is a constant, put it into a register if it is a legitimate
+          constant, OFFSET is 0, and we won't try to extract outside the
+          register (in case we were passed a partially uninitialized object
+          or a view_conversion to a larger size).  Force the constant to
+          memory otherwise.  */
        if (CONSTANT_P (op0))
          {
            enum machine_mode mode = TYPE_MODE (TREE_TYPE (tem));
            if (mode != BLKmode && LEGITIMATE_CONSTANT_P (op0)
-               && offset == 0)
+               && offset == 0
+               && bitpos + bitsize <= GET_MODE_BITSIZE (mode))
              op0 = force_reg (mode, op0);
            else
              op0 = validize_mem (force_const_mem (mode, op0));
          }
 
-       /* Otherwise, if this object not in memory and we either have an
-          offset or a BLKmode result, put it there.  This case can't occur in
-          C, but can in Ada if we have unchecked conversion of an expression
-          from a scalar type to an array or record type or for an
-          ARRAY_RANGE_REF whose type is BLKmode.  */
+       /* Otherwise, if this object not in memory and we either have an
+          offset, a BLKmode result, or a reference outside the object, put it
+          there.  Such cases can occur in Ada if we have unchecked conversion
+          of an expression from a scalar type to an array or record type or
+          for an ARRAY_RANGE_REF whose type is BLKmode.  */
        else if (!MEM_P (op0)
                 && (offset != 0
+                    || (bitpos + bitsize > GET_MODE_BITSIZE (GET_MODE (op0)))
                     || (code == ARRAY_RANGE_REF && mode == BLKmode)))
          {
            tree nt = build_qualified_type (TREE_TYPE (tem),
@@ -7364,9 +7699,18 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
               necessarily be constant.  */
            if (mode == BLKmode)
              {
-               rtx new
-                 = assign_stack_temp_for_type
-                   (ext_mode, GET_MODE_BITSIZE (ext_mode), 0, type);
+               HOST_WIDE_INT size = GET_MODE_BITSIZE (ext_mode);
+               rtx new;
+
+               /* If the reference doesn't use the alias set of its type,
+                  we cannot create the temporary using that type.  */
+               if (component_uses_parent_alias_set (exp))
+                 {
+                   new = assign_stack_local (ext_mode, size, 0);
+                   set_mem_alias_set (new, get_alias_set (exp));
+                 }
+               else
+                 new = assign_stack_temp_for_type (ext_mode, size, 0, type);
 
                emit_move_insn (new, op0);
                op0 = copy_rtx (new);
@@ -7413,12 +7757,12 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
     case CALL_EXPR:
       /* Check for a built-in function.  */
-      if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
-         && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
+      if (TREE_CODE (CALL_EXPR_FN (exp)) == ADDR_EXPR
+         && (TREE_CODE (TREE_OPERAND (CALL_EXPR_FN (exp), 0))
              == FUNCTION_DECL)
-         && DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
+         && DECL_BUILT_IN (TREE_OPERAND (CALL_EXPR_FN (exp), 0)))
        {
-         if (DECL_BUILT_IN_CLASS (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
+         if (DECL_BUILT_IN_CLASS (TREE_OPERAND (CALL_EXPR_FN (exp), 0))
              == BUILT_IN_FRONTEND)
            return lang_hooks.expand_expr (exp, original_target,
                                           tmode, modifier,
@@ -7498,7 +7842,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
          return REDUCE_BIT_FIELD (op0);
        }
 
-      op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, modifier);
+      op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode,
+                        modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier);
       if (GET_MODE (op0) == mode)
        ;
 
@@ -7544,7 +7889,11 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       else if (TYPE_MODE (type) != BLKmode && GET_MODE (op0) != BLKmode
               && GET_MODE_SIZE (TYPE_MODE (type))
                   == GET_MODE_SIZE (GET_MODE (op0)))
-       op0 = gen_lowpart (TYPE_MODE (type), 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))
@@ -7556,7 +7905,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       else if (!MEM_P (op0))
        {
          /* If the operand is not a MEM, force it into memory.  Since we
-            are going to be be changing the mode of the MEM, don't call
+            are going to be changing the mode of the MEM, don't call
             force_const_mem for constants because we don't allow pool
             constants to change mode.  */
          tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
@@ -7806,7 +8155,43 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
         from a narrower type.  If this machine supports multiplying
         in that narrower type with a result in the desired type,
         do it that way, and avoid the explicit type-conversion.  */
-      if (TREE_CODE (TREE_OPERAND (exp, 0)) == NOP_EXPR
+
+      subexp0 = TREE_OPERAND (exp, 0);
+      subexp1 = TREE_OPERAND (exp, 1);
+      /* First, check if we have a multiplication of one signed and one
+        unsigned operand.  */
+      if (TREE_CODE (subexp0) == NOP_EXPR
+         && TREE_CODE (subexp1) == NOP_EXPR
+         && TREE_CODE (type) == INTEGER_TYPE
+         && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subexp0, 0)))
+             < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0))))
+         && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subexp0, 0)))
+             == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subexp1, 0))))
+         && (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subexp0, 0)))
+             != TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subexp1, 0)))))
+       {
+         enum machine_mode innermode
+           = TYPE_MODE (TREE_TYPE (TREE_OPERAND (subexp0, 0)));
+         this_optab = usmul_widen_optab;
+         if (mode == GET_MODE_WIDER_MODE (innermode))
+           {
+             if (this_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+               {
+                 if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subexp0, 0))))
+                   expand_operands (TREE_OPERAND (subexp0, 0),
+                                    TREE_OPERAND (subexp1, 0),
+                                    NULL_RTX, &op0, &op1, 0);
+                 else
+                   expand_operands (TREE_OPERAND (subexp0, 0),
+                                    TREE_OPERAND (subexp1, 0),
+                                    NULL_RTX, &op1, &op0, 0);
+
+                 goto binop3;
+               }
+           }
+       }
+      /* Check for a multiplication with matching signedness.  */
+      else if (TREE_CODE (TREE_OPERAND (exp, 0)) == NOP_EXPR
          && TREE_CODE (type) == INTEGER_TYPE
          && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
              < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0))))
@@ -7845,27 +8230,24 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                  if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
                    expand_operands (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
                                     TREE_OPERAND (exp, 1),
-                                    NULL_RTX, &op0, &op1, 0);
+                                    NULL_RTX, &op0, &op1, EXPAND_NORMAL);
                  else
                    expand_operands (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
                                     TREE_OPERAND (TREE_OPERAND (exp, 1), 0),
-                                    NULL_RTX, &op0, &op1, 0);
+                                    NULL_RTX, &op0, &op1, EXPAND_NORMAL);
                  goto binop3;
                }
              else if (other_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing
                       && innermode == word_mode)
                {
                  rtx htem, hipart;
-                 op0 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
-                                    NULL_RTX, VOIDmode, 0);
+                 op0 = expand_normal (TREE_OPERAND (TREE_OPERAND (exp, 0), 0));
                  if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
                    op1 = convert_modes (innermode, mode,
-                                        expand_expr (TREE_OPERAND (exp, 1),
-                                                     NULL_RTX, VOIDmode, 0),
+                                        expand_normal (TREE_OPERAND (exp, 1)),
                                         unsignedp);
                  else
-                   op1 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 1), 0),
-                                      NULL_RTX, VOIDmode, 0);
+                   op1 = expand_normal (TREE_OPERAND (TREE_OPERAND (exp, 1), 0));
                  temp = expand_binop (mode, other_optab, op0, op1, target,
                                       unsignedp, OPTAB_LIB_WIDEN);
                  hipart = gen_highpart (innermode, temp);
@@ -7909,20 +8291,15 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                       subtarget, &op0, &op1, 0);
       return expand_divmod (1, code, mode, op0, op1, target, unsignedp);
 
-    case FIX_ROUND_EXPR:
-    case FIX_FLOOR_EXPR:
-    case FIX_CEIL_EXPR:
-      gcc_unreachable ();                      /* Not used for C.  */
-
     case FIX_TRUNC_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
+      op0 = expand_normal (TREE_OPERAND (exp, 0));
       if (target == 0 || modifier == EXPAND_STACK_PARM)
        target = gen_reg_rtx (mode);
       expand_fix (target, op0, unsignedp);
       return target;
 
     case FLOAT_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
+      op0 = expand_normal (TREE_OPERAND (exp, 0));
       if (target == 0 || modifier == EXPAND_STACK_PARM)
        target = gen_reg_rtx (mode);
       /* expand_float can't figure out what to do if FROM has VOIDmode.
@@ -8002,69 +8379,76 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       if (! CONSTANT_P (op1))
        op1 = force_reg (mode, op1);
 
-#ifdef HAVE_conditional_move
-      /* Use a conditional move if possible.  */
-      if (can_conditionally_move_p (mode))
-       {
-         enum rtx_code comparison_code;
-         rtx insn;
+      {
+       enum rtx_code comparison_code;
+       rtx cmpop1 = op1;
 
-         if (code == MAX_EXPR)
-           comparison_code = unsignedp ? GEU : GE;
-         else
-           comparison_code = unsignedp ? LEU : LE;
+       if (code == MAX_EXPR)
+         comparison_code = unsignedp ? GEU : GE;
+       else
+         comparison_code = unsignedp ? LEU : LE;
 
-         /* ??? Same problem as in expmed.c: emit_conditional_move
-            forces a stack adjustment via compare_from_rtx, and we
-            lose the stack adjustment if the sequence we are about
-            to create is discarded.  */
-         do_pending_stack_adjust ();
+       /* Canonicalize to comparisons against 0.  */
+       if (op1 == const1_rtx)
+         {
+           /* Converting (a >= 1 ? a : 1) into (a > 0 ? a : 1)
+              or (a != 0 ? a : 1) for unsigned.
+              For MIN we are safe converting (a <= 1 ? a : 1)
+              into (a <= 0 ? a : 1)  */
+           cmpop1 = const0_rtx;
+           if (code == MAX_EXPR)
+             comparison_code = unsignedp ? NE : GT;
+         }
+       if (op1 == constm1_rtx && !unsignedp)
+         {
+           /* Converting (a >= -1 ? a : -1) into (a >= 0 ? a : -1)
+              and (a <= -1 ? a : -1) into (a < 0 ? a : -1) */
+           cmpop1 = const0_rtx;
+           if (code == MIN_EXPR)
+             comparison_code = LT;
+         }
+#ifdef HAVE_conditional_move
+       /* Use a conditional move if possible.  */
+       if (can_conditionally_move_p (mode))
+         {
+           rtx insn;
 
-         start_sequence ();
+           /* ??? 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 ();
 
-         /* Try to emit the conditional move.  */
-         insn = emit_conditional_move (target, comparison_code,
-                                       op0, op1, mode,
-                                       op0, op1, mode,
-                                       unsignedp);
+           start_sequence ();
 
-         /* If we could do the conditional move, emit the sequence,
-            and return.  */
-         if (insn)
-           {
-             rtx seq = get_insns ();
-             end_sequence ();
-             emit_insn (seq);
-             return target;
-           }
+           /* Try to emit the conditional move.  */
+           insn = emit_conditional_move (target, comparison_code,
+                                         op0, cmpop1, mode,
+                                         op0, op1, mode,
+                                         unsignedp);
 
-         /* Otherwise discard the sequence and fall back to code with
-            branches.  */
-         end_sequence ();
-       }
-#endif
-      if (target != op0)
-       emit_move_insn (target, op0);
+           /* If we could do the conditional move, emit the sequence,
+              and return.  */
+           if (insn)
+             {
+               rtx seq = get_insns ();
+               end_sequence ();
+               emit_insn (seq);
+               return target;
+             }
 
-      temp = gen_label_rtx ();
+           /* Otherwise discard the sequence and fall back to code with
+              branches.  */
+           end_sequence ();
+         }
+#endif
+       if (target != op0)
+         emit_move_insn (target, op0);
 
-      /* If this mode is an integer too wide to compare properly,
-        compare word by word.  Rely on cse to optimize constant cases.  */
-      if (GET_MODE_CLASS (mode) == MODE_INT
-         && ! can_compare_p (GE, mode, ccp_jump))
-       {
-         if (code == MAX_EXPR)
-           do_jump_by_parts_greater_rtx (mode, unsignedp, target, op1,
-                                         NULL_RTX, temp);
-         else
-           do_jump_by_parts_greater_rtx (mode, unsignedp, op1, target,
-                                         NULL_RTX, temp);
-       }
-      else
-       {
-         do_compare_rtx_and_jump (target, op1, code == MAX_EXPR ? GE : LE,
-                                  unsignedp, mode, NULL_RTX, NULL_RTX, temp);
-       }
+       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;
@@ -8285,6 +8669,15 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       {
        tree lhs = TREE_OPERAND (exp, 0);
        tree rhs = TREE_OPERAND (exp, 1);
+       gcc_assert (ignore);
+       expand_assignment (lhs, rhs);
+       return const0_rtx;
+      }
+
+    case GIMPLE_MODIFY_STMT:
+      {
+       tree lhs = GIMPLE_STMT_OPERAND (exp, 0);
+       tree rhs = GIMPLE_STMT_OPERAND (exp, 1);
 
        gcc_assert (ignore);
 
@@ -8305,21 +8698,17 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
            && integer_onep (DECL_SIZE (TREE_OPERAND (TREE_OPERAND (rhs, 1), 1))))
          {
            rtx label = gen_label_rtx ();
-
+           int value = TREE_CODE (rhs) == BIT_IOR_EXPR;
            do_jump (TREE_OPERAND (rhs, 1),
-                    TREE_CODE (rhs) == BIT_IOR_EXPR ? label : 0,
-                    TREE_CODE (rhs) == BIT_AND_EXPR ? label : 0);
-           expand_assignment (lhs, convert (TREE_TYPE (rhs),
-                                            (TREE_CODE (rhs) == BIT_IOR_EXPR
-                                             ? integer_one_node
-                                             : integer_zero_node)));
+                    value ? label : 0,
+                    value ? 0 : label);
+           expand_assignment (lhs, build_int_cst (TREE_TYPE (rhs), value));
            do_pending_stack_adjust ();
            emit_label (label);
            return const0_rtx;
          }
 
        expand_assignment (lhs, rhs);
-
        return const0_rtx;
       }
 
@@ -8335,8 +8724,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
     case COMPLEX_EXPR:
       /* Get the rtx code of the operands.  */
-      op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
-      op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
+      op0 = expand_normal (TREE_OPERAND (exp, 0));
+      op1 = expand_normal (TREE_OPERAND (exp, 1));
 
       if (!target)
        target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
@@ -8348,11 +8737,11 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       return target;
 
     case REALPART_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
+      op0 = expand_normal (TREE_OPERAND (exp, 0));
       return read_complex_part (op0, false);
 
     case IMAGPART_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
+      op0 = expand_normal (TREE_OPERAND (exp, 0));
       return read_complex_part (op0, true);
 
     case RESX_EXPR:
@@ -8423,25 +8812,74 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
         rtx op2;
 
         this_optab = optab_for_tree_code (code, type);
-        expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, 0);
-        op2 = expand_expr (oprnd2, NULL_RTX, VOIDmode, 0);
+        expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+        op2 = expand_normal (oprnd2);
         temp = expand_ternary_op (mode, this_optab, op0, op1, op2, 
                                  target, unsignedp);
         gcc_assert (temp);
         return temp;
       }
 
+    case DOT_PROD_EXPR:
+      {
+       tree oprnd0 = TREE_OPERAND (exp, 0);
+       tree oprnd1 = TREE_OPERAND (exp, 1);
+       tree oprnd2 = TREE_OPERAND (exp, 2);
+       rtx op2;
+
+       expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+       op2 = expand_normal (oprnd2);
+       target = expand_widen_pattern_expr (exp, op0, op1, op2, 
+                                           target, unsignedp);
+       return target;
+      }
+
+    case WIDEN_SUM_EXPR:
+      {
+        tree oprnd0 = TREE_OPERAND (exp, 0);
+        tree oprnd1 = TREE_OPERAND (exp, 1);
+                                                                               
+        expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, 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_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
+        op0 = expand_normal (TREE_OPERAND (exp, 0));
         this_optab = optab_for_tree_code (code, type);
         temp = expand_unop (mode, this_optab, op0, target, unsignedp);
         gcc_assert (temp);
         return temp;
       }
 
+    case VEC_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);
+        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);
+        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:
       {
@@ -8449,6 +8887,37 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
        return target;
       }
 
+    case VEC_UNPACK_HI_EXPR:
+    case VEC_UNPACK_LO_EXPR:
+      {
+       op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
+       this_optab = optab_for_tree_code (code, type);
+       temp = expand_widen_pattern_expr (exp, op0, NULL_RTX, NULL_RTX,
+                                         target, unsignedp);
+       gcc_assert (temp);
+       return temp;
+      }
+
+    case VEC_WIDEN_MULT_HI_EXPR:
+    case VEC_WIDEN_MULT_LO_EXPR:
+      {
+       tree oprnd0 = TREE_OPERAND (exp, 0);
+       tree oprnd1 = TREE_OPERAND (exp, 1);
+
+       expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, 0);
+       target = expand_widen_pattern_expr (exp, op0, op1, NULL_RTX,
+                                           target, unsignedp);
+       gcc_assert (target);
+       return target;
+      }
+
+    case VEC_PACK_MOD_EXPR:
+    case VEC_PACK_SAT_EXPR:
+      {
+       mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
+       goto binop;
+      }
+
     default:
       return lang_hooks.expand_expr (exp, original_target, tmode,
                                     modifier, alt_rtl);
@@ -8551,7 +9020,7 @@ is_aligning_offset (tree offset, tree exp)
 tree
 string_constant (tree arg, tree *ptr_offset)
 {
-  tree array, offset;
+  tree array, offset, lower_bound;
   STRIP_NOPS (arg);
 
   if (TREE_CODE (arg) == ADDR_EXPR)
@@ -8573,6 +9042,20 @@ string_constant (tree arg, tree *ptr_offset)
          if (TREE_CODE (array) != STRING_CST
              && TREE_CODE (array) != VAR_DECL)
            return 0;
+
+         /* Check if the array has a nonzero lower bound.  */
+         lower_bound = array_ref_low_bound (TREE_OPERAND (arg, 0));
+         if (!integer_zerop (lower_bound))
+           {
+             /* If the offset and base aren't both constants, return 0.  */
+             if (TREE_CODE (lower_bound) != INTEGER_CST)
+               return 0;
+             if (TREE_CODE (offset) != INTEGER_CST)
+               return 0;
+             /* Adjust offset by the lower bound.  */
+             offset = size_diffop (fold_convert (sizetype, offset), 
+                                   fold_convert (sizetype, lower_bound));
+           }
        }
       else
        return 0;
@@ -8607,7 +9090,7 @@ string_constant (tree arg, tree *ptr_offset)
 
   if (TREE_CODE (array) == STRING_CST)
     {
-      *ptr_offset = convert (sizetype, offset);
+      *ptr_offset = fold_convert (sizetype, offset);
       return array;
     }
   else if (TREE_CODE (array) == VAR_DECL)
@@ -8634,7 +9117,7 @@ string_constant (tree arg, tree *ptr_offset)
 
       /* If variable is bigger than the string literal, OFFSET must be constant
         and inside of the bounds of the string literal.  */
-      offset = convert (sizetype, offset);
+      offset = fold_convert (sizetype, offset);
       if (compare_tree_int (DECL_SIZE_UNIT (array), length) > 0
          && (! host_integerp (offset, 1)
              || compare_tree_int (offset, length) >= 0))
@@ -8821,6 +9304,17 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
     return 0;
 
   icode = setcc_gen_code[(int) code];
+
+  if (icode == CODE_FOR_nothing)
+    {
+      enum machine_mode wmode;
+      
+      for (wmode = operand_mode;
+          icode == CODE_FOR_nothing && wmode != VOIDmode;
+          wmode = GET_MODE_WIDER_MODE (wmode))
+       icode = cstore_optab->handlers[(int) wmode].insn_code;
+    }
+
   if (icode == CODE_FOR_nothing
       || (only_cheap && insn_data[(int) icode].operand[0].mode != mode))
     {
@@ -8866,25 +9360,10 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
     target = gen_reg_rtx (GET_MODE (target));
 
   emit_move_insn (target, invert ? const0_rtx : const1_rtx);
-  result = compare_from_rtx (op0, op1, code, unsignedp,
-                            operand_mode, NULL_RTX);
-  if (GET_CODE (result) == CONST_INT)
-    return (((result == const0_rtx && ! invert)
-            || (result != const0_rtx && invert))
-           ? const0_rtx : const1_rtx);
-
-  /* The code of RESULT may not match CODE if compare_from_rtx
-     decided to swap its operands and reverse the original code.
-
-     We know that compare_from_rtx returns either a CONST_INT or
-     a new comparison code, so it is safe to just extract the
-     code from RESULT.  */
-  code = GET_CODE (result);
-
   label = gen_label_rtx ();
-  gcc_assert (bcc_gen_fctn[(int) code]);
-
-  emit_jump_insn ((*bcc_gen_fctn[(int) code]) (label));
+  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);
 
@@ -8930,13 +9409,13 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range,
   if (GET_MODE_BITSIZE (TYPE_MODE (index_type)) > GET_MODE_BITSIZE (index_mode))
     {
       enum machine_mode omode = TYPE_MODE (index_type);
-      rtx rangertx = expand_expr (range, NULL_RTX, VOIDmode, 0);
+      rtx rangertx = expand_normal (range);
 
       /* We must handle the endpoints in the original mode.  */
       index_expr = build2 (MINUS_EXPR, index_type,
                           index_expr, minval);
       minval = integer_zero_node;
-      index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
+      index = expand_normal (index_expr);
       emit_cmp_and_jump_insns (rangertx, index, LTU, NULL_RTX,
                               omode, 1, default_label);
       /* Now we can safely truncate.  */
@@ -8946,12 +9425,11 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range,
     {
       if (TYPE_MODE (index_type) != index_mode)
        {
-         index_expr = convert (lang_hooks.types.type_for_size
-                               (index_bits, 0), index_expr);
-         index_type = TREE_TYPE (index_expr);
+         index_type = lang_hooks.types.type_for_size (index_bits, 0);
+         index_expr = fold_convert (index_type, index_expr);
        }
 
-      index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
+      index = expand_normal (index_expr);
     }
 
   do_pending_stack_adjust ();
@@ -8961,7 +9439,7 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range,
       (index, op_mode))
     index = copy_to_mode_reg (op_mode, index);
 
-  op1 = expand_expr (minval, NULL_RTX, VOIDmode, 0);
+  op1 = expand_normal (minval);
 
   op_mode = insn_data[(int) CODE_FOR_casesi].operand[1].mode;
   op1 = convert_modes (op_mode, TYPE_MODE (TREE_TYPE (minval)),
@@ -8970,7 +9448,7 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range,
       (op1, op_mode))
     op1 = copy_to_mode_reg (op_mode, op1);
 
-  op2 = expand_expr (range, NULL_RTX, VOIDmode, 0);
+  op2 = expand_normal (range);
 
   op_mode = insn_data[(int) CODE_FOR_casesi].operand[2].mode;
   op2 = convert_modes (op_mode, TYPE_MODE (TREE_TYPE (range)),
@@ -9074,16 +9552,15 @@ try_tablejump (tree index_type, tree index_expr, tree minval, tree range,
     return 0;
 
   index_expr = fold_build2 (MINUS_EXPR, index_type,
-                           convert (index_type, index_expr),
-                           convert (index_type, minval));
-  index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
+                           fold_convert (index_type, index_expr),
+                           fold_convert (index_type, minval));
+  index = expand_normal (index_expr);
   do_pending_stack_adjust ();
 
   do_tablejump (index, TYPE_MODE (index_type),
                convert_modes (TYPE_MODE (index_type),
                               TYPE_MODE (TREE_TYPE (range)),
-                              expand_expr (range, NULL_RTX,
-                                           VOIDmode, 0),
+                              expand_normal (range),
                               TYPE_UNSIGNED (TREE_TYPE (range))),
                table_label, default_label);
   return 1;