OSDN Git Service

* flags.h (g_switch_value): Change to an unsigned
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index f3c0144..9c21ac9 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 Free Software Foundation, Inc.
+   2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -21,6 +21,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "machmode.h"
 #include "real.h"
 #include "rtl.h"
@@ -54,9 +56,11 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #ifdef PUSH_ROUNDING
 
+#ifndef PUSH_ARGS_REVERSED
 #if defined (STACK_GROWS_DOWNWARD) != defined (ARGS_GROW_DOWNWARD)
 #define PUSH_ARGS_REVERSED     /* If it's last to first.  */
 #endif
+#endif
 
 #endif
 
@@ -91,7 +95,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 int cse_not_expected;
 
 /* Chain of pending expressions for PLACEHOLDER_EXPR to replace.  */
-static tree placeholder_list = 0;
+tree placeholder_list = 0;
 
 /* This structure is used by move_by_pieces to describe the move to
    be performed.  */
@@ -151,7 +155,7 @@ static rtx clear_storage_via_libcall PARAMS ((rtx, rtx));
 static tree clear_storage_libcall_fn PARAMS ((int));
 static rtx compress_float_constant PARAMS ((rtx, rtx));
 static rtx get_subtarget       PARAMS ((rtx));
-static int is_zeros_p          PARAMS ((tree));
+static int is_zeros_p         PARAMS ((tree));
 static int mostly_zeros_p      PARAMS ((tree));
 static void store_constructor_field PARAMS ((rtx, unsigned HOST_WIDE_INT,
                                             HOST_WIDE_INT, enum machine_mode,
@@ -162,19 +166,19 @@ static rtx store_field            PARAMS ((rtx, HOST_WIDE_INT,
                                         tree, enum machine_mode, int, tree,
                                         int));
 static rtx var_rtx             PARAMS ((tree));
-static HOST_WIDE_INT highest_pow2_factor PARAMS ((tree));
-static HOST_WIDE_INT highest_pow2_factor_for_type PARAMS ((tree, tree));
+
+static unsigned HOST_WIDE_INT highest_pow2_factor PARAMS ((tree));
+static unsigned HOST_WIDE_INT highest_pow2_factor_for_type PARAMS ((tree,
+                                                                   tree));
+
 static int is_aligning_offset  PARAMS ((tree, tree));
 static rtx expand_increment    PARAMS ((tree, int, int));
-static void do_jump_by_parts_greater PARAMS ((tree, int, rtx, rtx));
-static void do_jump_by_parts_equality PARAMS ((tree, rtx, rtx));
-static void do_compare_and_jump        PARAMS ((tree, enum rtx_code, enum rtx_code,
-                                        rtx, rtx));
 static rtx do_store_flag       PARAMS ((tree, rtx, enum machine_mode, int));
 #ifdef PUSH_ROUNDING
 static void emit_single_push_insn PARAMS ((enum machine_mode, rtx, tree));
 #endif
 static void do_tablejump PARAMS ((rtx, enum machine_mode, rtx, rtx, rtx));
+static rtx const_vector_from_tree PARAMS ((tree));
 
 /* Record for each mode whether we can move a register directly to or
    from an object of that mode in memory.  If we can't, we won't try
@@ -225,13 +229,20 @@ static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
   (move_by_pieces_ninsns (SIZE, ALIGN) < (unsigned int) CLEAR_RATIO)
 #endif
 
+/* This macro is used to determine whether store_by_pieces should be
+   called to "memset" storage with byte values other than zero, or
+   to "memcpy" storage when the source is a constant string.  */
+#ifndef STORE_BY_PIECES_P
+#define STORE_BY_PIECES_P(SIZE, ALIGN) MOVE_BY_PIECES_P (SIZE, ALIGN)
+#endif
+
 /* This array records the insn_code of insns to perform block moves.  */
 enum insn_code movstr_optab[NUM_MACHINE_MODES];
 
 /* This array records the insn_code of insns to perform block clears.  */
 enum insn_code clrstr_optab[NUM_MACHINE_MODES];
 
-/* SLOW_UNALIGNED_ACCESS is non-zero if unaligned accesses are very slow.  */
+/* SLOW_UNALIGNED_ACCESS is nonzero if unaligned accesses are very slow.  */
 
 #ifndef SLOW_UNALIGNED_ACCESS
 #define SLOW_UNALIGNED_ACCESS(MODE, ALIGN) STRICT_ALIGNMENT
@@ -552,7 +563,8 @@ convert_move (to, from, unsignedp)
   rtx libcall;
 
   /* rtx code for making an equivalent value.  */
-  enum rtx_code equiv_code = (unsignedp ? ZERO_EXTEND : SIGN_EXTEND);
+  enum rtx_code equiv_code = (unsignedp < 0 ? UNKNOWN
+                             : (unsignedp ? ZERO_EXTEND : SIGN_EXTEND));
 
   to = protect_from_queue (to, 1);
   from = protect_from_queue (from, 0);
@@ -1394,6 +1406,8 @@ convert_modes (mode, oldmode, x, unsignedp)
                  && ((GET_CODE (x) == MEM && ! MEM_VOLATILE_P (x)
                       && direct_load[(int) mode])
                      || (GET_CODE (x) == REG
+                         && (! HARD_REGISTER_P (x)
+                             || HARD_REGNO_MODE_OK (REGNO (x), mode))
                          && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
                                                    GET_MODE_BITSIZE (GET_MODE (x)))))))))
     {
@@ -1449,7 +1463,7 @@ convert_modes (mode, oldmode, x, unsignedp)
    If PUSH_ROUNDING is defined and TO is NULL, emit_single_push_insn is
    used to push FROM to the stack.
 
-   ALIGN is maximum alignment we can assume.  */
+   ALIGN is maximum stack alignment we can assume.  */
 
 void
 move_by_pieces (to, from, len, align)
@@ -1463,6 +1477,8 @@ move_by_pieces (to, from, len, align)
   enum machine_mode mode = VOIDmode, tmode;
   enum insn_code icode;
 
+  align = MIN (to ? MEM_ALIGN (to) : align, MEM_ALIGN (from));
+
   data.offset = 0;
   data.from_addr = from_addr;
   if (to)
@@ -1733,6 +1749,16 @@ emit_block_move (x, y, size, method)
   if (size == 0)
     abort ();
 
+  /* 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)
+    {
+      x = shallow_copy_rtx (x);
+      y = shallow_copy_rtx (y);
+      set_mem_size (x, size);
+      set_mem_size (y, size);
+    }
+
   if (GET_CODE (size) == CONST_INT && MOVE_BY_PIECES_P (INTVAL (size), align))
     move_by_pieces (x, y, INTVAL (size), align);
   else if (emit_block_move_via_movstr (x, y, size, align))
@@ -1815,16 +1841,16 @@ emit_block_move_via_movstr (x, y, size, align)
      rtx x, y, size;
      unsigned int align;
 {
-  /* Try the most limited insn first, because there's no point
-     including more than one in the machine description unless
-     the more limited one has some advantage.  */
-
   rtx opalign = GEN_INT (align / BITS_PER_UNIT);
   enum machine_mode mode;
 
   /* Since this is a move insn, we don't care about volatility.  */
   volatile_ok = 1;
 
+  /* Try the most limited insn first, because there's no point
+     including more than one in the machine description unless
+     the more limited one has some advantage.  */
+
   for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
        mode = GET_MODE_WIDER_MODE (mode))
     {
@@ -1884,38 +1910,48 @@ static rtx
 emit_block_move_via_libcall (dst, src, size)
      rtx dst, src, size;
 {
+  rtx dst_addr, src_addr;
   tree call_expr, arg_list, fn, src_tree, dst_tree, size_tree;
   enum machine_mode size_mode;
   rtx retval;
 
   /* DST, SRC, or SIZE may have been passed through protect_from_queue.
 
-     It is unsafe to save the value generated by protect_from_queue
-     and reuse it later.  Consider what happens if emit_queue is
-     called before the return value from protect_from_queue is used.
+     It is unsafe to save the value generated by protect_from_queue and reuse
+     it later.  Consider what happens if emit_queue is called before the
+     return value from protect_from_queue is used.
 
-     Expansion of the CALL_EXPR below will call emit_queue before
-     we are finished emitting RTL for argument setup.  So if we are
-     not careful we could get the wrong value for an argument.
+     Expansion of the CALL_EXPR below will call emit_queue before we are
+     finished emitting RTL for argument setup.  So if we are not careful we
+     could get the wrong value for an argument.
 
-     To avoid this problem we go ahead and emit code to copy X, Y &
-     SIZE into new pseudos.  We can then place those new pseudos
-     into an RTL_EXPR and use them later, even after a call to
+     To avoid this problem we go ahead and emit code to copy the addresses of
+     DST and SRC and SIZE into new pseudos.  We can then place those new
+     pseudos into an RTL_EXPR and use them later, even after a call to
      emit_queue.
 
-     Note this is not strictly needed for library calls since they
-     do not call emit_queue before loading their arguments.  However,
-     we may need to have library calls call emit_queue in the future
-     since failing to do so could cause problems for targets which
-     define SMALL_REGISTER_CLASSES and pass arguments in registers.  */
+     Note this is not strictly needed for library calls since they do not call
+     emit_queue before loading their arguments.  However, we may need to have
+     library calls call emit_queue in the future since failing to do so could
+     cause problems for targets which define SMALL_REGISTER_CLASSES and pass
+     arguments in registers.  */
+
+  dst_addr = copy_to_mode_reg (Pmode, XEXP (dst, 0));
+  src_addr = copy_to_mode_reg (Pmode, XEXP (src, 0));
 
-  dst = copy_to_mode_reg (Pmode, XEXP (dst, 0));
-  src = copy_to_mode_reg (Pmode, XEXP (src, 0));
+#ifdef POINTERS_EXTEND_UNSIGNED
+  dst_addr = convert_memory_address (ptr_mode, dst_addr);
+  src_addr = convert_memory_address (ptr_mode, src_addr);
+#endif
+
+  dst_tree = make_tree (ptr_type_node, dst_addr);
+  src_tree = make_tree (ptr_type_node, src_addr);
 
   if (TARGET_MEM_FUNCTIONS)
     size_mode = TYPE_MODE (sizetype);
   else
     size_mode = TYPE_MODE (unsigned_type_node);
+
   size = convert_to_mode (size_mode, size, 1);
   size = copy_to_mode_reg (size_mode, size);
 
@@ -1927,8 +1963,6 @@ emit_block_move_via_libcall (dst, src, size)
 
      For convenience, we generate the call to bcopy this way as well.  */
 
-  dst_tree = make_tree (ptr_type_node, dst);
-  src_tree = make_tree (ptr_type_node, src);
   if (TARGET_MEM_FUNCTIONS)
     size_tree = make_tree (sizetype, size);
   else
@@ -1955,13 +1989,17 @@ emit_block_move_via_libcall (dst, src, size)
 
   retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
 
-  /* If we are initializing a readonly value, show the above call
-     clobbered it.  Otherwise, a load from it may erroneously be
-     hoisted from a loop.  */
+  /* If we are initializing a readonly value, show the above call clobbered
+     it. Otherwise, a load from it may erroneously be hoisted from a loop, or
+     the delay slot scheduler might overlook conflicts and take nasty
+     decisions.  */
   if (RTX_UNCHANGING_P (dst))
-    emit_insn (gen_rtx_CLOBBER (VOIDmode, dst));
+    add_function_usage_to
+      (last_call_insn (), gen_rtx_EXPR_LIST (VOIDmode,
+                                            gen_rtx_CLOBBER (VOIDmode, dst),
+                                            NULL_RTX));
 
-  return (TARGET_MEM_FUNCTIONS ? retval : NULL_RTX);
+  return TARGET_MEM_FUNCTIONS ? retval : NULL_RTX;
 }
 
 /* A subroutine of emit_block_move_via_libcall.  Create the tree node
@@ -1970,15 +2008,14 @@ emit_block_move_via_libcall (dst, src, size)
 
 static GTY(()) tree block_move_fn;
 
-static tree
-emit_block_move_libcall_fn (for_call)
-      int for_call;
+void
+init_block_move_fn (asmspec)
+     const char *asmspec;
 {
-  static bool emitted_extern;
-  tree fn = block_move_fn, args;
-
-  if (!fn)
+  if (!block_move_fn)
     {
+      tree fn, args;
+
       if (TARGET_MEM_FUNCTIONS)
        {
          fn = get_identifier ("memcpy");
@@ -2003,14 +2040,30 @@ emit_block_move_libcall_fn (for_call)
       block_move_fn = fn;
     }
 
+  if (asmspec)
+    {
+      SET_DECL_RTL (block_move_fn, NULL_RTX);
+      SET_DECL_ASSEMBLER_NAME (block_move_fn, get_identifier (asmspec));
+    }
+}
+
+static tree
+emit_block_move_libcall_fn (for_call)
+     int for_call;
+{
+  static bool emitted_extern;
+
+  if (!block_move_fn)
+    init_block_move_fn (NULL);
+
   if (for_call && !emitted_extern)
     {
       emitted_extern = true;
-      make_decl_rtl (fn, NULL);
-      assemble_external (fn);
+      make_decl_rtl (block_move_fn, NULL);
+      assemble_external (block_move_fn);
     }
 
-  return fn;
+  return block_move_fn;
 }
 
 /* A subroutine of emit_block_move.  Copy the data via an explicit
@@ -2111,64 +2164,26 @@ move_block_to_reg (regno, x, nregs, mode)
 }
 
 /* Copy all or part of a BLKmode value X out of registers starting at REGNO.
-   The number of registers to be filled is NREGS.  SIZE indicates the number
-   of bytes in the object X.  */
+   The number of registers to be filled is NREGS.  */
 
 void
-move_block_from_reg (regno, x, nregs, size)
+move_block_from_reg (regno, x, nregs)
      int regno;
      rtx x;
      int nregs;
-     int size;
 {
   int i;
-#ifdef HAVE_store_multiple
-  rtx pat;
-  rtx last;
-#endif
-  enum machine_mode mode;
 
   if (nregs == 0)
     return;
 
-  /* If SIZE is that of a mode no bigger than a word, just use that
-     mode's store operation.  */
-  if (size <= UNITS_PER_WORD
-      && (mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0)) != BLKmode
-      && !FUNCTION_ARG_REG_LITTLE_ENDIAN)
-    {
-      emit_move_insn (adjust_address (x, mode, 0), gen_rtx_REG (mode, regno));
-      return;
-    }
-
-  /* Blocks smaller than a word on a BYTES_BIG_ENDIAN machine must be aligned
-     to the left before storing to memory.  Note that the previous test
-     doesn't handle all cases (e.g. SIZE == 3).  */
-  if (size < UNITS_PER_WORD
-      && BYTES_BIG_ENDIAN
-      && !FUNCTION_ARG_REG_LITTLE_ENDIAN)
-    {
-      rtx tem = operand_subword (x, 0, 1, BLKmode);
-      rtx shift;
-
-      if (tem == 0)
-       abort ();
-
-      shift = expand_shift (LSHIFT_EXPR, word_mode,
-                           gen_rtx_REG (word_mode, regno),
-                           build_int_2 ((UNITS_PER_WORD - size)
-                                        * BITS_PER_UNIT, 0), NULL_RTX, 0);
-      emit_move_insn (tem, shift);
-      return;
-    }
-
   /* See if the machine can do this with a store multiple insn.  */
 #ifdef HAVE_store_multiple
   if (HAVE_store_multiple)
     {
-      last = get_last_insn ();
-      pat = gen_store_multiple (x, gen_rtx_REG (word_mode, regno),
-                               GEN_INT (nregs));
+      rtx last = get_last_insn ();
+      rtx pat = gen_store_multiple (x, gen_rtx_REG (word_mode, regno),
+                                   GEN_INT (nregs));
       if (pat)
        {
          emit_insn (pat);
@@ -2190,6 +2205,42 @@ move_block_from_reg (regno, x, nregs, size)
     }
 }
 
+/* Generate a PARALLEL rtx for a new non-consecutive group of registers from
+   ORIG, where ORIG is a non-consecutive group of registers represented by
+   a PARALLEL.  The clone is identical to the original except in that the
+   original set of registers is replaced by a new set of pseudo registers.
+   The new set has the same modes as the original set.  */
+
+rtx
+gen_group_rtx (orig)
+     rtx orig;
+{
+  int i, length;
+  rtx *tmps;
+
+  if (GET_CODE (orig) != PARALLEL)
+    abort ();
+
+  length = XVECLEN (orig, 0);
+  tmps = (rtx *) alloca (sizeof (rtx) * length);
+
+  /* Skip a NULL entry in first slot.  */
+  i = XEXP (XVECEXP (orig, 0, 0), 0) ? 0 : 1;
+
+  if (i)
+    tmps[0] = 0;
+
+  for (; i < length; i++)
+    {
+      enum machine_mode mode = GET_MODE (XEXP (XVECEXP (orig, 0, i), 0));
+      rtx offset = XEXP (XVECEXP (orig, 0, i), 1);
+
+      tmps[i] = gen_rtx_EXPR_LIST (VOIDmode, gen_reg_rtx (mode), offset);
+    }
+
+  return gen_rtx_PARALLEL (GET_MODE (orig), gen_rtvec_v (length, tmps));
+}
+
 /* Emit code to move a block SRC to a block DST, where DST is non-consecutive
    registers represented by a PARALLEL.  SSIZE represents the total size of
    block SRC in bytes, or -1 if not known.  */
@@ -2265,27 +2316,45 @@ emit_group_load (dst, orig_src, ssize)
        }
       else if (GET_CODE (src) == CONCAT)
        {
-         if ((bytepos == 0
-              && bytelen == GET_MODE_SIZE (GET_MODE (XEXP (src, 0))))
-             || (bytepos == (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (XEXP (src, 0)))
-                 && bytelen == GET_MODE_SIZE (GET_MODE (XEXP (src, 1)))))
+         unsigned int slen = GET_MODE_SIZE (GET_MODE (src));
+         unsigned int slen0 = GET_MODE_SIZE (GET_MODE (XEXP (src, 0)));
+
+         if ((bytepos == 0 && bytelen == slen0)
+             || (bytepos != 0 && bytepos + bytelen <= slen))
            {
-             tmps[i] = XEXP (src, bytepos != 0);
+             /* The following assumes that the concatenated objects all
+                have the same size.  In this case, a simple calculation
+                can be used to determine the object and the bit field
+                to be extracted.  */
+             tmps[i] = XEXP (src, bytepos / slen0);
              if (! CONSTANT_P (tmps[i])
                  && (GET_CODE (tmps[i]) != REG || GET_MODE (tmps[i]) != mode))
                tmps[i] = extract_bit_field (tmps[i], bytelen * BITS_PER_UNIT,
-                                            0, 1, NULL_RTX, mode, mode, ssize);
+                                            (bytepos % slen0) * BITS_PER_UNIT,
+                                            1, NULL_RTX, mode, mode, ssize);
            }
          else if (bytepos == 0)
            {
-             rtx mem = assign_stack_temp (GET_MODE (src),
-                                          GET_MODE_SIZE (GET_MODE (src)), 0);
+             rtx mem = assign_stack_temp (GET_MODE (src), slen, 0);
              emit_move_insn (mem, src);
              tmps[i] = adjust_address (mem, mode, 0);
            }
          else
            abort ();
        }
+      /* FIXME: A SIMD parallel will eventually lead to a subreg of a
+        SIMD register, which is currently broken.  While we get GCC
+        to emit proper RTL for these cases, let's dump to memory.  */
+      else if (VECTOR_MODE_P (GET_MODE (dst))
+              && GET_CODE (src) == REG)
+       {
+         int slen = GET_MODE_SIZE (GET_MODE (src));
+         rtx mem;
+
+         mem = assign_stack_temp (GET_MODE (src), slen, 0);
+         emit_move_insn (mem, src);
+         tmps[i] = adjust_address (mem, mode, (int) bytepos);
+       }
       else if (CONSTANT_P (src)
               || (GET_CODE (src) == REG && GET_MODE (src) == mode))
        tmps[i] = src;
@@ -2306,6 +2375,26 @@ emit_group_load (dst, orig_src, ssize)
     emit_move_insn (XEXP (XVECEXP (dst, 0, i), 0), tmps[i]);
 }
 
+/* Emit code to move a block SRC to block DST, where SRC and DST are
+   non-consecutive groups of registers, each represented by a PARALLEL.  */
+
+void
+emit_group_move (dst, src)
+     rtx dst, src;
+{
+  int i;
+
+  if (GET_CODE (src) != PARALLEL
+      || GET_CODE (dst) != PARALLEL
+      || XVECLEN (src, 0) != XVECLEN (dst, 0))
+    abort ();
+
+  /* Skip first entry if NULL.  */
+  for (i = XEXP (XVECEXP (src, 0, 0), 0) ? 0 : 1; i < XVECLEN (src, 0); i++)
+    emit_move_insn (XEXP (XVECEXP (dst, 0, i), 0),
+                   XEXP (XVECEXP (src, 0, i), 0));
+}
+
 /* Emit code to move a block SRC to a block DST, where SRC is non-consecutive
    registers represented by a PARALLEL.  SSIZE represents the total size of
    block DST, or -1 if not known.  */
@@ -2365,7 +2454,7 @@ emit_group_store (orig_dst, src, ssize)
     {
       dst = gen_reg_rtx (GET_MODE (orig_dst));
       /* Make life a bit easier for combine.  */
-      emit_move_insn (dst, const0_rtx);
+      emit_move_insn (dst, CONST0_RTX (GET_MODE (orig_dst)));
     }
 
   /* Process the pieces.  */
@@ -2397,6 +2486,15 @@ emit_group_store (orig_dst, src, ssize)
              bytepos -= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0)));
              dest = XEXP (dst, 1);
            }
+         else if (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;
+           }
          else
            abort ();
        }
@@ -2415,7 +2513,7 @@ emit_group_store (orig_dst, src, ssize)
   emit_queue ();
 
   /* Copy from the pseudo into the (probable) hard reg.  */
-  if (GET_CODE (dst) == REG)
+  if (orig_dst != dst)
     emit_move_insn (orig_dst, dst);
 }
 
@@ -2449,26 +2547,17 @@ copy_blkmode_from_reg (tgtblk, srcreg, type)
     }
 
   /* This code assumes srcreg is at least a full word.  If it isn't, copy it
-     into a new pseudo which is a full word.
+     into a new pseudo which is a full word.  */
 
-     If FUNCTION_ARG_REG_LITTLE_ENDIAN is set and convert_to_mode does a copy,
-     the wrong part of the register gets copied so we fake a type conversion
-     in place.  */
   if (GET_MODE (srcreg) != BLKmode
       && GET_MODE_SIZE (GET_MODE (srcreg)) < UNITS_PER_WORD)
-    {
-      if (FUNCTION_ARG_REG_LITTLE_ENDIAN)
-       srcreg = simplify_gen_subreg (word_mode, srcreg, GET_MODE (srcreg), 0);
-      else
-       srcreg = convert_to_mode (word_mode, srcreg, TREE_UNSIGNED (type));
-    }
+    srcreg = convert_to_mode (word_mode, srcreg, TREE_UNSIGNED (type));
 
   /* Structures whose size is not a multiple of a word are aligned
      to the least significant byte (to the right).  On a BYTES_BIG_ENDIAN
      machine, this means we must skip the empty high order bytes when
      calculating the bit offset.  */
   if (BYTES_BIG_ENDIAN
-      && !FUNCTION_ARG_REG_LITTLE_ENDIAN
       && bytes % UNITS_PER_WORD)
     big_endian_correction
       = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD) * BITS_PER_UNIT));
@@ -2586,7 +2675,7 @@ can_store_by_pieces (len, constfun, constfundata, align)
   int reverse;
   rtx cst;
 
-  if (! MOVE_BY_PIECES_P (len, align))
+  if (! STORE_BY_PIECES_P (len, align))
     return 0;
 
   if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
@@ -2661,7 +2750,7 @@ store_by_pieces (to, len, constfun, constfundata, align)
 {
   struct store_by_pieces data;
 
-  if (! MOVE_BY_PIECES_P (len, align))
+  if (! STORE_BY_PIECES_P (len, align))
     abort ();
   to = protect_from_queue (to, 1);
   data.constfun = constfun;
@@ -3007,15 +3096,14 @@ clear_storage_via_libcall (object, size)
 
 static GTY(()) tree block_clear_fn;
 
-static tree
-clear_storage_libcall_fn (for_call)
-     int for_call;
+void
+init_block_clear_fn (asmspec)
+     const char *asmspec;
 {
-  static bool emitted_extern;
-  tree fn = block_clear_fn, args;
-
-  if (!fn)
+  if (!block_clear_fn)
     {
+      tree fn, args;
+
       if (TARGET_MEM_FUNCTIONS)
        {
          fn = get_identifier ("memset");
@@ -3039,14 +3127,30 @@ clear_storage_libcall_fn (for_call)
       block_clear_fn = fn;
     }
 
+  if (asmspec)
+    {
+      SET_DECL_RTL (block_clear_fn, NULL_RTX);
+      SET_DECL_ASSEMBLER_NAME (block_clear_fn, get_identifier (asmspec));
+    }
+}
+
+static tree
+clear_storage_libcall_fn (for_call)
+     int for_call;
+{
+  static bool emitted_extern;
+
+  if (!block_clear_fn)
+    init_block_clear_fn (NULL);
+
   if (for_call && !emitted_extern)
     {
       emitted_extern = true;
-      make_decl_rtl (fn, NULL);
-      assemble_external (fn);
+      make_decl_rtl (block_clear_fn, NULL);
+      assemble_external (block_clear_fn);
     }
 
-  return fn;
+  return block_clear_fn;
 }
 \f
 /* Generate code to copy Y into X.
@@ -3076,7 +3180,7 @@ emit_move_insn (x, y)
   else if (CONSTANT_P (y))
     {
       if (optimize
-         && FLOAT_MODE_P (GET_MODE (x))
+         && SCALAR_FLOAT_MODE_P (GET_MODE (x))
          && (last_insn = compress_float_constant (x, y)))
        return last_insn;
 
@@ -3084,6 +3188,12 @@ emit_move_insn (x, y)
        {
          y_cst = y;
          y = force_const_mem (mode, y);
+
+         /* If the target's cannot_force_const_mem prevented the spill,
+            assume that the target's move expanders will also take care
+            of the non-legitimate constant.  */
+         if (!y)
+           y = y_cst;
        }
     }
 
@@ -3134,11 +3244,7 @@ emit_move_insn_1 (x, y)
 
   /* Expand complex moves by moving real part and imag part, if possible.  */
   else if ((class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT)
-          && BLKmode != (submode = mode_for_size ((GET_MODE_UNIT_SIZE (mode)
-                                                   * BITS_PER_UNIT),
-                                                  (class == MODE_COMPLEX_INT
-                                                   ? MODE_INT : MODE_FLOAT),
-                                                  0))
+          && BLKmode != (submode = GET_MODE_INNER (mode))
           && (mov_optab->handlers[(int) submode].insn_code
               != CODE_FOR_nothing))
     {
@@ -3300,6 +3406,61 @@ emit_move_insn_1 (x, y)
       return get_last_insn ();
     }
 
+  /* Handle MODE_CC modes:  If we don't have a special move insn for this mode,
+     find a mode to do it in.  If we have a movcc, use it.  Otherwise,
+     find the MODE_INT mode of the same width.  */
+  else if (GET_MODE_CLASS (mode) == MODE_CC
+          && mov_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing)
+    {
+      enum insn_code insn_code;
+      enum machine_mode tmode = VOIDmode;
+      rtx x1 = x, y1 = y;
+
+      if (mode != CCmode
+         && mov_optab->handlers[(int) CCmode].insn_code != CODE_FOR_nothing)
+       tmode = CCmode;
+      else
+       for (tmode = QImode; tmode != VOIDmode;
+            tmode = GET_MODE_WIDER_MODE (tmode))
+         if (GET_MODE_SIZE (tmode) == GET_MODE_SIZE (mode))
+           break;
+
+      if (tmode == VOIDmode)
+       abort ();
+
+      /* Get X and Y in TMODE.  We can't use gen_lowpart here because it
+        may call change_address which is not appropriate if we were
+        called when a reload was in progress.  We don't have to worry
+        about changing the address since the size in bytes is supposed to
+        be the same.  Copy the MEM to change the mode and move any
+        substitutions from the old MEM to the new one.  */
+
+      if (reload_in_progress)
+       {
+         x = gen_lowpart_common (tmode, x1);
+         if (x == 0 && GET_CODE (x1) == MEM)
+           {
+             x = adjust_address_nv (x1, tmode, 0);
+             copy_replacements (x1, x);
+           }
+
+         y = gen_lowpart_common (tmode, y1);
+         if (y == 0 && GET_CODE (y1) == MEM)
+           {
+             y = adjust_address_nv (y1, tmode, 0);
+             copy_replacements (y1, y);
+           }
+       }
+      else
+       {
+         x = gen_lowpart (tmode, x);
+         y = gen_lowpart (tmode, y);
+       }
+         
+      insn_code = mov_optab->handlers[(int) tmode].insn_code;
+      return emit_insn (GEN_FCN (insn_code) (x, y));
+    }
+
   /* This will handle any multi-word or full-word mode that lacks a move_insn
      pattern.  However, you will get better code if you define such patterns,
      even if they must turn into multiple assembler instructions.  */
@@ -3690,6 +3851,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
          && PUSH_ARGS
          && GET_CODE (size) == CONST_INT
          && skip == 0
+         && MEM_ALIGN (xinner) >= align
          && (MOVE_BY_PIECES_P ((unsigned) INTVAL (size) - used, align))
          /* Here we avoid the case of a structure whose weak alignment
             forces many pushes of a small amount of data,
@@ -3841,7 +4003,6 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
   else
     {
       rtx addr;
-      rtx target = NULL_RTX;
       rtx dest;
 
       /* Push padding now if padding above and stack grows down,
@@ -3865,7 +4026,6 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
          else
            addr = memory_address (mode, gen_rtx_PLUS (Pmode, args_addr,
                                                       args_so_far));
-         target = addr;
          dest = gen_rtx_MEM (mode, addr);
          if (type != 0)
            {
@@ -3956,7 +4116,8 @@ expand_assignment (to, from, want_value, suggest_reg)
      problem.  */
 
   if (TREE_CODE (to) == COMPONENT_REF || TREE_CODE (to) == BIT_FIELD_REF
-      || TREE_CODE (to) == ARRAY_REF || TREE_CODE (to) == ARRAY_RANGE_REF)
+      || TREE_CODE (to) == ARRAY_REF || TREE_CODE (to) == ARRAY_RANGE_REF
+      || TREE_CODE (TREE_TYPE (to)) == ARRAY_TYPE)
     {
       enum machine_mode mode1;
       HOST_WIDE_INT bitsize, bitpos;
@@ -3987,7 +4148,7 @@ expand_assignment (to, from, want_value, suggest_reg)
 
 #ifdef POINTERS_EXTEND_UNSIGNED
          if (GET_MODE (offset_rtx) != Pmode)
-           offset_rtx = convert_memory_address (Pmode, offset_rtx);
+           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);
@@ -4184,7 +4345,7 @@ expand_assignment (to, from, want_value, suggest_reg)
    and storing the value into TARGET.
    TARGET may contain a QUEUED rtx.
 
-   If WANT_VALUE is nonzero, return a copy of the value
+   If WANT_VALUE & 1 is nonzero, return a copy of the value
    not in TARGET, so that we can be sure to use the proper
    value in a containing expression even if TARGET has something
    else stored in it.  If possible, we copy the value through a pseudo
@@ -4199,9 +4360,12 @@ expand_assignment (to, from, want_value, suggest_reg)
    with no sequence point.  Will other languages need this to
    be more thorough?
 
-   If WANT_VALUE is 0, we return NULL, to make sure
+   If WANT_VALUE & 1 is 0, we return NULL, to make sure
    to catch quickly any cases where the caller uses the value
-   and fails to set WANT_VALUE.  */
+   and fails to set WANT_VALUE.
+
+   If WANT_VALUE & 2 is set, this is a store into a call param on the
+   stack, and block moves may need to be treated specially.  */
 
 rtx
 store_expr (exp, target, want_value)
@@ -4213,11 +4377,22 @@ store_expr (exp, target, want_value)
   int dont_return_target = 0;
   int dont_store_target = 0;
 
+  if (VOID_TYPE_P (TREE_TYPE (exp)))
+    {
+      /* C++ can generate ?: expressions with a throw expression in one
+        branch and an rvalue in the other. Here, we resolve attempts to
+        store the throw expression's nonexistant result. */
+      if (want_value)
+       abort ();
+      expand_expr (exp, const0_rtx, VOIDmode, 0);
+      return NULL_RTX;
+    }
   if (TREE_CODE (exp) == COMPOUND_EXPR)
     {
       /* Perform first part of compound expression, then assign from second
         part.  */
-      expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
+      expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
+                  want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL);
       emit_queue ();
       return store_expr (TREE_OPERAND (exp, 1), target, want_value);
     }
@@ -4237,20 +4412,20 @@ store_expr (exp, target, want_value)
       NO_DEFER_POP;
       jumpifnot (TREE_OPERAND (exp, 0), lab1);
       start_cleanup_deferral ();
-      store_expr (TREE_OPERAND (exp, 1), target, 0);
+      store_expr (TREE_OPERAND (exp, 1), target, want_value & 2);
       end_cleanup_deferral ();
       emit_queue ();
       emit_jump_insn (gen_jump (lab2));
       emit_barrier ();
       emit_label (lab1);
       start_cleanup_deferral ();
-      store_expr (TREE_OPERAND (exp, 2), target, 0);
+      store_expr (TREE_OPERAND (exp, 2), target, want_value & 2);
       end_cleanup_deferral ();
       emit_queue ();
       emit_label (lab2);
       OK_DEFER_POP;
 
-      return want_value ? target : NULL_RTX;
+      return want_value & 1 ? target : NULL_RTX;
     }
   else if (queued_subexp_p (target))
     /* If target contains a postincrement, let's not risk
@@ -4260,18 +4435,24 @@ store_expr (exp, target, want_value)
        {
          /* Expand EXP into a new pseudo.  */
          temp = gen_reg_rtx (GET_MODE (target));
-         temp = expand_expr (exp, temp, GET_MODE (target), 0);
+         temp = expand_expr (exp, temp, GET_MODE (target),
+                             (want_value & 2
+                              ? EXPAND_STACK_PARM : EXPAND_NORMAL));
        }
       else
-       temp = expand_expr (exp, NULL_RTX, GET_MODE (target), 0);
+       temp = expand_expr (exp, NULL_RTX, GET_MODE (target),
+                           (want_value & 2
+                            ? EXPAND_STACK_PARM : EXPAND_NORMAL));
 
       /* If target is volatile, ANSI requires accessing the value
         *from* the target, if it is accessed.  So make that happen.
         In no case return the target itself.  */
-      if (! MEM_VOLATILE_P (target) && want_value)
+      if (! MEM_VOLATILE_P (target) && (want_value & 1) != 0)
        dont_return_target = 1;
     }
-  else if (want_value && GET_CODE (target) == MEM && ! MEM_VOLATILE_P (target)
+  else if ((want_value & 1) != 0
+          && GET_CODE (target) == MEM
+          && ! MEM_VOLATILE_P (target)
           && GET_MODE (target) != BLKmode)
     /* If target is in memory and caller wants value in a register instead,
        arrange that.  Pass TARGET as target for expand_expr so that,
@@ -4280,7 +4461,8 @@ store_expr (exp, target, want_value)
        Don't do this if TARGET is volatile because we are supposed
        to write it and then read it.  */
     {
-      temp = expand_expr (exp, target, GET_MODE (target), 0);
+      temp = expand_expr (exp, target, GET_MODE (target),
+                         want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL);
       if (GET_MODE (temp) != BLKmode && GET_MODE (temp) != VOIDmode)
        {
          /* If TEMP is already in the desired TARGET, only copy it from
@@ -4294,7 +4476,7 @@ store_expr (exp, target, want_value)
       dont_return_target = 1;
     }
   else if (GET_CODE (target) == SUBREG && SUBREG_PROMOTED_VAR_P (target))
-    /* If this is an scalar in a register that is stored in a wider mode
+    /* If this is a scalar in a register that is stored in a wider mode
        than the declared mode, compute the result into its declared mode
        and then convert to the wider mode.  Our value is the computed
        expression.  */
@@ -4307,7 +4489,8 @@ store_expr (exp, target, want_value)
         the extend.  But don't do this if the type of EXP is a subtype
         of something else since then the conversion might involve
         more than just converting modes.  */
-      if (! want_value && INTEGRAL_TYPE_P (TREE_TYPE (exp))
+      if ((want_value & 1) == 0
+         && INTEGRAL_TYPE_P (TREE_TYPE (exp))
          && TREE_TYPE (TREE_TYPE (exp)) == 0)
        {
          if (TREE_UNSIGNED (TREE_TYPE (exp))
@@ -4324,14 +4507,15 @@ store_expr (exp, target, want_value)
          inner_target = SUBREG_REG (target);
        }
 
-      temp = expand_expr (exp, inner_target, VOIDmode, 0);
+      temp = expand_expr (exp, inner_target, VOIDmode,
+                         want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL);
 
-      /* If TEMP is a volatile MEM and we want a result value, make
-        the access now so it gets done only once.  Likewise if
-        it contains TARGET.  */
-      if (GET_CODE (temp) == MEM && want_value
-         && (MEM_VOLATILE_P (temp)
-             || reg_mentioned_p (SUBREG_REG (target), XEXP (temp, 0))))
+      /* If TEMP is a MEM and we want a result value, make the access
+        now so it gets done only once.  Strictly speaking, this is 
+        only necessary if the MEM is volatile, or if the address 
+        overlaps TARGET.  But not performing the load twice also
+        reduces the amount of rtl we generate and then have to CSE.  */
+      if (GET_CODE (temp) == MEM && (want_value & 1) != 0)
        temp = copy_to_reg (temp);
 
       /* If TEMP is a VOIDmode constant, use convert_modes to make
@@ -4352,7 +4536,7 @@ store_expr (exp, target, want_value)
         target.  Otherwise, the caller might get confused by a result whose
         mode is larger than expected.  */
 
-      if (want_value && GET_MODE (temp) != GET_MODE (target))
+      if ((want_value & 1) != 0 && GET_MODE (temp) != GET_MODE (target))
        {
          if (GET_MODE (temp) != VOIDmode)
            {
@@ -4367,11 +4551,12 @@ store_expr (exp, target, want_value)
                                  temp, SUBREG_PROMOTED_UNSIGNED_P (target));
        }
 
-      return want_value ? temp : NULL_RTX;
+      return want_value & 1 ? temp : NULL_RTX;
     }
   else
     {
-      temp = expand_expr (exp, target, GET_MODE (target), 0);
+      temp = expand_expr (exp, target, GET_MODE (target),
+                         want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL);
       /* 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.
@@ -4383,7 +4568,7 @@ store_expr (exp, target, want_value)
            && REGNO (target) < FIRST_PSEUDO_REGISTER)
          && !(GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
          && ! rtx_equal_p (temp, target)
-         && (CONSTANT_P (temp) || want_value))
+         && (CONSTANT_P (temp) || (want_value & 1) != 0))
        dont_return_target = 1;
     }
 
@@ -4454,7 +4639,9 @@ store_expr (exp, target, want_value)
 
          if (GET_CODE (size) == CONST_INT
              && INTVAL (size) < TREE_STRING_LENGTH (exp))
-           emit_block_move (target, temp, size, BLOCK_OP_NORMAL);
+           emit_block_move (target, temp, size,
+                            (want_value & 2
+                             ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
          else
            {
              /* Compute the size of the data to copy from the string.  */
@@ -4462,13 +4649,18 @@ store_expr (exp, target, want_value)
                = size_binop (MIN_EXPR,
                              make_tree (sizetype, size),
                              size_int (TREE_STRING_LENGTH (exp)));
-             rtx copy_size_rtx = expand_expr (copy_size, NULL_RTX,
-                                              VOIDmode, 0);
+             rtx copy_size_rtx
+               = expand_expr (copy_size, NULL_RTX, VOIDmode,
+                              (want_value & 2
+                               ? EXPAND_STACK_PARM : EXPAND_NORMAL));
              rtx label = 0;
 
              /* Copy that much.  */
-             copy_size_rtx = convert_to_mode (ptr_mode, copy_size_rtx, 0);
-             emit_block_move (target, temp, copy_size_rtx, BLOCK_OP_NORMAL);
+             copy_size_rtx = convert_to_mode (ptr_mode, copy_size_rtx,
+                                              TREE_UNSIGNED (sizetype));
+             emit_block_move (target, temp, copy_size_rtx,
+                              (want_value & 2
+                               ? 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.  */
@@ -4486,8 +4678,8 @@ store_expr (exp, target, want_value)
 
 #ifdef POINTERS_EXTEND_UNSIGNED
                  if (GET_MODE (copy_size_rtx) != Pmode)
-                   copy_size_rtx = convert_memory_address (Pmode,
-                                                           copy_size_rtx);
+                   copy_size_rtx = convert_to_mode (Pmode, copy_size_rtx,
+                                                    TREE_UNSIGNED (sizetype));
 #endif
 
                  target = offset_address (target, copy_size_rtx,
@@ -4509,13 +4701,15 @@ store_expr (exp, target, want_value)
       else if (GET_CODE (target) == PARALLEL)
        emit_group_load (target, temp, int_size_in_bytes (TREE_TYPE (exp)));
       else if (GET_MODE (temp) == BLKmode)
-       emit_block_move (target, temp, expr_size (exp), BLOCK_OP_NORMAL);
+       emit_block_move (target, temp, expr_size (exp),
+                        (want_value & 2
+                         ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
       else
        emit_move_insn (target, temp);
     }
 
   /* If we don't want a value, return NULL_RTX.  */
-  if (! want_value)
+  if ((want_value & 1) == 0)
     return NULL_RTX;
 
   /* If we are supposed to return TEMP, do so as long as it isn't a MEM.
@@ -4524,7 +4718,8 @@ store_expr (exp, target, want_value)
     return temp;
 
   /* Return TARGET itself if it is a hard register.  */
-  else if (want_value && GET_MODE (target) != BLKmode
+  else if ((want_value & 1) != 0
+          && GET_MODE (target) != BLKmode
           && ! (GET_CODE (target) == REG
                 && REGNO (target) < FIRST_PSEUDO_REGISTER))
     return copy_to_reg (target);
@@ -4638,7 +4833,7 @@ store_constructor_field (target, bitsize, bitpos, mode, exp, type, cleared,
 {
   if (TREE_CODE (exp) == CONSTRUCTOR
       && bitpos % BITS_PER_UNIT == 0
-      /* If we have a non-zero bitpos for a register target, then we just
+      /* If we have a nonzero bitpos for a register target, then we just
         let store_field do the bitfield handling.  This is unlikely to
         generate unnecessary clear instructions anyways.  */
       && (bitpos == 0 || GET_CODE (target) == MEM))
@@ -4727,7 +4922,15 @@ store_constructor (exp, target, cleared, size)
                   || ((HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (target))
                       == size)))
        {
-         clear_storage (target, GEN_INT (size));
+         rtx xtarget = target;
+
+         if (readonly_fields_p (type))
+           {
+             xtarget = copy_rtx (xtarget);
+             RTX_UNCHANGING_P (xtarget) = 1;
+           }
+
+         clear_storage (xtarget, GEN_INT (size));
          cleared = 1;
        }
 
@@ -4744,7 +4947,6 @@ store_constructor (exp, target, cleared, size)
          enum machine_mode mode;
          HOST_WIDE_INT bitsize;
          HOST_WIDE_INT bitpos = 0;
-         int unsignedp;
          tree offset;
          rtx to_rtx = target;
 
@@ -4762,7 +4964,6 @@ store_constructor (exp, target, cleared, size)
          else
            bitsize = -1;
 
-         unsignedp = TREE_UNSIGNED (field);
          mode = DECL_MODE (field);
          if (DECL_BIT_FIELD (field))
            mode = VOIDmode;
@@ -4791,7 +4992,7 @@ store_constructor (exp, target, cleared, size)
 
 #ifdef POINTERS_EXTEND_UNSIGNED
              if (GET_MODE (offset_rtx) != Pmode)
-               offset_rtx = convert_memory_address (Pmode, offset_rtx);
+               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);
@@ -4983,7 +5184,7 @@ store_constructor (exp, target, cleared, size)
            {
              tree lo_index = TREE_OPERAND (index, 0);
              tree hi_index = TREE_OPERAND (index, 1);
-             rtx index_r, pos_rtx, hi_r, loop_top, loop_end;
+             rtx index_r, pos_rtx, loop_end;
              struct nesting *loop;
              HOST_WIDE_INT lo, hi, count;
              tree position;
@@ -5022,8 +5223,7 @@ store_constructor (exp, target, cleared, size)
                }
              else
                {
-                 hi_r = expand_expr (hi_index, NULL_RTX, VOIDmode, 0);
-                 loop_top = gen_label_rtx ();
+                 expand_expr (hi_index, NULL_RTX, VOIDmode, 0);
                  loop_end = gen_label_rtx ();
 
                  unsignedp = TREE_UNSIGNED (domain);
@@ -5284,8 +5484,8 @@ store_constructor (exp, target, cleared, size)
                                 TYPE_MODE (sizetype));
            }
          else
-           emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__setbits"),
-                              LCT_NORMAL, VOIDmode, 4, XEXP (targetx, 0),
+           emit_library_call (setbits_libfunc, LCT_NORMAL,
+                              VOIDmode, 4, XEXP (targetx, 0),
                               Pmode, bitlength_rtx, TYPE_MODE (sizetype),
                               startbit_rtx, TYPE_MODE (sizetype),
                               endbit_rtx, TYPE_MODE (sizetype));
@@ -5339,7 +5539,7 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode, unsignedp, type,
      side-effects.  */
   if (bitsize == 0)
     return expand_expr (exp, const0_rtx, VOIDmode, 0);
-  else if (bitsize >=0 && bitsize < HOST_BITS_PER_WIDE_INT)
+  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
@@ -5351,15 +5551,13 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode, unsignedp, type,
      that object.  Finally, load from the object into TARGET.  This is not
      very efficient in general, but should only be slightly more expensive
      than the otherwise-required unaligned accesses.  Perhaps this can be
-     cleaned up later.  */
+     cleaned up later.  It's tempting to make OBJECT readonly, but it's set
+     twice, once with emit_move_insn and once via store_field.  */
 
   if (mode == BLKmode
       && (GET_CODE (target) == REG || GET_CODE (target) == SUBREG))
     {
-      rtx object
-       = assign_temp
-         (build_qualified_type (type, TYPE_QUALS (type) | TYPE_QUAL_CONST),
-          0, 1, 1);
+      rtx object = assign_temp (type, 0, 1, 1);
       rtx blk_object = adjust_address (object, BLKmode, 0);
 
       if (bitsize != (HOST_WIDE_INT) GET_MODE_BITSIZE (GET_MODE (target)))
@@ -5395,9 +5593,11 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode, unsignedp, type,
       || GET_CODE (target) == SUBREG
       /* If the field isn't aligned enough to store as an ordinary memref,
         store it as a bit field.  */
-      || (mode != BLKmode && SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (target))
-         && (MEM_ALIGN (target) < GET_MODE_ALIGNMENT (mode)
-             || bitpos % GET_MODE_ALIGNMENT (mode)))
+      || (mode != BLKmode
+         && ((((MEM_ALIGN (target) < GET_MODE_ALIGNMENT (mode))
+               || bitpos % GET_MODE_ALIGNMENT (mode))
+              && SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (target)))
+             || (bitpos % BITS_PER_UNIT != 0)))              
       /* If the RHS and field are a constant size and the size of the
         RHS isn't the same size as the bitfield, we must use bitfield
         operations.  */
@@ -5417,7 +5617,7 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode, unsignedp, type,
        temp = expand_shift (RSHIFT_EXPR, GET_MODE (temp), temp,
                             size_int (GET_MODE_BITSIZE (GET_MODE (temp))
                                       - bitsize),
-                            temp, 1);
+                            NULL_RTX, 1);
 
       /* Unless MODE is VOIDmode or BLKmode, convert TEMP to
         MODE.  */
@@ -5657,8 +5857,20 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
 
          continue;
        }
+
+      /* We can go inside most conversions: all NON_VALUE_EXPRs, all normal
+        conversions that don't change the mode, and all view conversions
+        except those that need to "step up" the alignment.  */
       else if (TREE_CODE (exp) != NON_LVALUE_EXPR
-              && TREE_CODE (exp) != VIEW_CONVERT_EXPR
+              && ! (TREE_CODE (exp) == VIEW_CONVERT_EXPR
+                    && ! ((TYPE_ALIGN (TREE_TYPE (exp))
+                           > TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (exp, 0))))
+                          && STRICT_ALIGNMENT
+                          && (TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (exp, 0)))
+                              < BIGGEST_ALIGNMENT)
+                          && (TYPE_ALIGN_OK (TREE_TYPE (exp))
+                              || TYPE_ALIGN_OK (TREE_TYPE
+                                                (TREE_OPERAND (exp, 0))))))
               && ! ((TREE_CODE (exp) == NOP_EXPR
                      || TREE_CODE (exp) == CONVERT_EXPR)
                     && (TYPE_MODE (TREE_TYPE (exp))
@@ -5928,22 +6140,31 @@ safe_from_p (x, exp, top_p)
 
     case 'x':
       if (TREE_CODE (exp) == TREE_LIST)
-       return ((TREE_VALUE (exp) == 0
-                || safe_from_p (x, TREE_VALUE (exp), 0))
-               && (TREE_CHAIN (exp) == 0
-                   || safe_from_p (x, TREE_CHAIN (exp), 0)));
+       {
+         while (1)
+           {
+             if (TREE_VALUE (exp) && !safe_from_p (x, TREE_VALUE (exp), 0))
+               return 0;
+             exp = TREE_CHAIN (exp);
+             if (!exp)
+               return 1;
+             if (TREE_CODE (exp) != TREE_LIST)
+               return safe_from_p (x, exp, 0);
+           }
+       }
       else if (TREE_CODE (exp) == ERROR_MARK)
        return 1;       /* An already-visited SAVE_EXPR? */
       else
        return 0;
 
-    case '1':
-      return safe_from_p (x, TREE_OPERAND (exp, 0), 0);
-
     case '2':
     case '<':
-      return (safe_from_p (x, TREE_OPERAND (exp, 0), 0)
-             && safe_from_p (x, TREE_OPERAND (exp, 1), 0));
+      if (!safe_from_p (x, TREE_OPERAND (exp, 1), 0))
+       return 0;
+      /* FALLTHRU */
+
+    case '1':
+      return safe_from_p (x, TREE_OPERAND (exp, 0), 0);
 
     case 'e':
     case 'r':
@@ -6160,11 +6381,11 @@ check_max_integer_computation_mode (exp)
 /* Return the highest power of two that EXP is known to be a multiple of.
    This is used in updating alignment of MEMs in array references.  */
 
-static HOST_WIDE_INT
+static unsigned HOST_WIDE_INT
 highest_pow2_factor (exp)
      tree exp;
 {
-  HOST_WIDE_INT c0, c1;
+  unsigned HOST_WIDE_INT c0, c1;
 
   switch (TREE_CODE (exp))
     {
@@ -6230,12 +6451,12 @@ highest_pow2_factor (exp)
 /* Similar, except that it is known that the expression must be a multiple
    of the alignment of TYPE.  */
 
-static HOST_WIDE_INT
+static unsigned HOST_WIDE_INT
 highest_pow2_factor_for_type (type, exp)
      tree type;
      tree exp;
 {
-  HOST_WIDE_INT type_align, factor;
+  unsigned HOST_WIDE_INT type_align, factor;
 
   factor = highest_pow2_factor (exp);
   type_align = TYPE_ALIGN (type) / BITS_PER_UNIT;
@@ -6341,7 +6562,14 @@ find_placeholder (exp, plist)
 
    EXPAND_CONST_ADDRESS says that it is okay to return a MEM
    with a constant address even if that address is not normally legitimate.
-   EXPAND_INITIALIZER and EXPAND_SUM also have this effect.  */
+   EXPAND_INITIALIZER and EXPAND_SUM also have this effect.
+
+   EXPAND_STACK_PARM is used when expanding to a TARGET on the stack for
+   a call parameter.  Such targets require special care as we haven't yet
+   marked TARGET so that it's safe from being trashed by libcalls.  We
+   don't want to use TARGET for anything but the final result;
+   Intermediate values must go elsewhere.   Additionally, calls to
+   emit_block_move will be flagged with BLOCK_OP_CALL_PARM.  */
 
 rtx
 expand_expr (exp, target, tmode, modifier)
@@ -6434,7 +6662,7 @@ expand_expr (exp, target, tmode, modifier)
 
 #ifdef MAX_INTEGER_COMPUTATION_MODE
   /* Only check stuff here if the mode we want is different from the mode
-     of the expression; if it's the same, check_max_integer_computiation_mode
+     of the expression; if it's the same, check_max_integer_computation_mode
      will handle it.  Do we really need to check this stuff at all?  */
 
   if (target
@@ -6478,38 +6706,32 @@ expand_expr (exp, target, tmode, modifier)
   /* If will do cse, generate all results into pseudo registers
      since 1) that allows cse to find more things
      and 2) otherwise cse could produce an insn the machine
-     cannot support.  And exception is a CONSTRUCTOR into a multi-word
-     MEM: that's much more likely to be most efficient into the MEM.  */
+     cannot support.  An exception is a CONSTRUCTOR into a multi-word
+     MEM: that's much more likely to be most efficient into the MEM.
+     Another is a CALL_EXPR which must return in memory.  */
 
   if (! cse_not_expected && mode != BLKmode && target
       && (GET_CODE (target) != REG || REGNO (target) < FIRST_PSEUDO_REGISTER)
-      && ! (code == CONSTRUCTOR && GET_MODE_SIZE (mode) > UNITS_PER_WORD))
-    target = subtarget;
+      && ! (code == CONSTRUCTOR && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
+      && ! (code == CALL_EXPR && aggregate_value_p (exp)))
+    target = 0;
 
   switch (code)
     {
     case LABEL_DECL:
       {
        tree function = decl_function_context (exp);
-       /* Handle using a label in a containing function.  */
-       if (function != current_function_decl
-           && function != inline_function_decl && function != 0)
-         {
-           struct function *p = find_function_data (function);
-           p->expr->x_forced_labels
-             = gen_rtx_EXPR_LIST (VOIDmode, label_rtx (exp),
-                                  p->expr->x_forced_labels);
-         }
+       /* Labels in containing functions, or labels used from initializers,
+          must be forced.  */
+       if (modifier == EXPAND_INITIALIZER
+           || (function != current_function_decl
+               && function != inline_function_decl
+               && function != 0))
+         temp = force_label_rtx (exp);
        else
-         {
-           if (modifier == EXPAND_INITIALIZER)
-             forced_labels = gen_rtx_EXPR_LIST (VOIDmode,
-                                                label_rtx (exp),
-                                                forced_labels);
-         }
+         temp = label_rtx (exp);
 
-       temp = gen_rtx_MEM (FUNCTION_MODE,
-                           gen_rtx_LABEL_REF (Pmode, label_rtx (exp)));
+       temp = gen_rtx_MEM (FUNCTION_MODE, gen_rtx_LABEL_REF (Pmode, temp));
        if (function != current_function_decl
            && function != inline_function_decl && function != 0)
          LABEL_REF_NONLOCAL_P (XEXP (temp, 0)) = 1;
@@ -6517,7 +6739,7 @@ expand_expr (exp, target, tmode, modifier)
       }
 
     case PARM_DECL:
-      if (DECL_RTL (exp) == 0)
+      if (!DECL_RTL_SET_P (exp))
        {
          error_with_decl (exp, "prior parameter's size depends on `%s'");
          return CONST0_RTX (mode);
@@ -6528,23 +6750,10 @@ expand_expr (exp, target, tmode, modifier)
     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_TYPE_P (TREE_TYPE (exp))
+      if (DECL_SIZE (exp) == 0
+         && COMPLETE_OR_UNBOUND_ARRAY_TYPE_P (TREE_TYPE (exp))
          && (TREE_STATIC (exp) || DECL_EXTERNAL (exp)))
-       {
-         rtx value = DECL_RTL_IF_SET (exp);
-
-         layout_decl (exp, 0);
-
-         /* If the RTL was already set, update its mode and memory
-            attributes.  */
-         if (value != 0)
-           {
-             PUT_MODE (value, DECL_MODE (exp));
-             SET_DECL_RTL (exp, 0);
-             set_mem_attributes (value, exp, 1);
-             SET_DECL_RTL (exp, value);
-           }
-       }
+       layout_decl (exp, 0);
 
       /* ... fall through ...  */
 
@@ -6669,8 +6878,11 @@ expand_expr (exp, target, tmode, modifier)
 
       return temp;
 
+    case VECTOR_CST:
+      return const_vector_from_tree (exp);
+
     case CONST_DECL:
-      return expand_expr (DECL_INITIAL (exp), target, VOIDmode, 0);
+      return expand_expr (DECL_INITIAL (exp), target, VOIDmode, modifier);
 
     case REAL_CST:
       /* If optimized, generate immediate CONST_DOUBLE
@@ -6688,36 +6900,31 @@ expand_expr (exp, target, tmode, modifier)
 
     case COMPLEX_CST:
     case STRING_CST:
-      if (! TREE_CST_RTL (exp))
-       output_constant_def (exp, 1);
+      temp = output_constant_def (exp, 1);
 
-      /* TREE_CST_RTL probably contains a constant address.
+      /* 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 (GET_CODE (TREE_CST_RTL (exp)) == MEM
-         && modifier != EXPAND_CONST_ADDRESS
+      if (modifier != EXPAND_CONST_ADDRESS
          && modifier != EXPAND_INITIALIZER
          && modifier != EXPAND_SUM
-         && (! memory_address_p (mode, XEXP (TREE_CST_RTL (exp), 0))
-             || (flag_force_addr
-                 && GET_CODE (XEXP (TREE_CST_RTL (exp), 0)) != REG)))
-       return replace_equiv_address (TREE_CST_RTL (exp),
-                                     copy_rtx (XEXP (TREE_CST_RTL (exp), 0)));
-      return TREE_CST_RTL (exp);
+         && (! memory_address_p (mode, XEXP (temp, 0))
+             || flag_force_addr))
+       return replace_equiv_address (temp,
+                                     copy_rtx (XEXP (temp, 0)));
+      return temp;
 
     case EXPR_WITH_FILE_LOCATION:
       {
        rtx to_return;
-       const char *saved_input_filename = input_filename;
-       int saved_lineno = lineno;
+       location_t saved_loc = input_location;
        input_filename = EXPR_WFL_FILENAME (exp);
-       lineno = EXPR_WFL_LINENO (exp);
+       input_line = EXPR_WFL_LINENO (exp);
        if (EXPR_WFL_EMIT_LINE_NOTE (exp))
-         emit_line_note (input_filename, lineno);
+         emit_line_note (input_filename, input_line);
        /* Possibly avoid switching back and forth here.  */
        to_return = expand_expr (EXPR_WFL_NODE (exp), target, tmode, modifier);
-       input_filename = saved_input_filename;
-       lineno = saved_lineno;
+       input_location = saved_loc;
        return to_return;
       }
 
@@ -6746,7 +6953,7 @@ expand_expr (exp, target, tmode, modifier)
          temp = SAVE_EXPR_RTL (exp);
          if (temp && GET_CODE (temp) == REG)
            {
-             put_var_into_stack (exp);
+             put_var_into_stack (exp, /*rescan=*/true);
              temp = SAVE_EXPR_RTL (exp);
            }
          if (temp == 0 || GET_CODE (temp) != MEM)
@@ -6773,12 +6980,12 @@ expand_expr (exp, target, tmode, modifier)
          /* If the mode of TEMP does not match that of the expression, it
             must be a promoted value.  We pass store_expr a SUBREG of the
             wanted mode but mark it so that we know that it was already
-            extended.  Note that `unsignedp' was modified above in
-            this case.  */
+            extended.  */
 
          if (GET_CODE (temp) == REG && GET_MODE (temp) != mode)
            {
              temp = gen_lowpart_SUBREG (mode, SAVE_EXPR_RTL (exp));
+             promote_mode (type, mode, &unsignedp, 0);
              SUBREG_PROMOTED_VAR_P (temp) = 1;
              SUBREG_PROMOTED_UNSIGNED_SET (temp, unsignedp);
            }
@@ -6786,7 +6993,8 @@ expand_expr (exp, target, tmode, modifier)
          if (temp == const0_rtx)
            expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
          else
-           store_expr (TREE_OPERAND (exp, 0), temp, 0);
+           store_expr (TREE_OPERAND (exp, 0), temp,
+                       modifier == EXPAND_STACK_PARM ? 2 : 0);
 
          TREE_USED (exp) = 1;
        }
@@ -6832,9 +7040,6 @@ expand_expr (exp, target, tmode, modifier)
        return temp;
       }
 
-      /* We can't find the object or there was a missing WITH_RECORD_EXPR.  */
-      abort ();
-
     case WITH_RECORD_EXPR:
       /* Put the object on the placeholder list, expand our first operand,
         and pop the list.  */
@@ -6883,7 +7088,6 @@ expand_expr (exp, target, tmode, modifier)
     case BIND_EXPR:
       {
        tree vars = TREE_OPERAND (exp, 0);
-       int vars_need_expansion = 0;
 
        /* Need to open a binding contour here because
           if there are any cleanups they must be contained here.  */
@@ -6898,10 +7102,7 @@ expand_expr (exp, target, tmode, modifier)
        while (vars)
          {
            if (!DECL_RTL_SET_P (vars))
-             {
-               vars_need_expansion = 1;
-               expand_decl (vars);
-             }
+             expand_decl (vars);
            expand_decl_init (vars);
            vars = TREE_CHAIN (vars);
          }
@@ -6978,7 +7179,8 @@ expand_expr (exp, target, tmode, modifier)
          /* Handle calls that pass values in multiple non-contiguous
             locations.  The Irix 6 ABI has examples of this.  */
          if (target == 0 || ! safe_from_p (target, exp, 1)
-             || GET_CODE (target) == PARALLEL)
+             || GET_CODE (target) == PARALLEL
+             || modifier == EXPAND_STACK_PARM)
            target
              = assign_temp (build_qualified_type (type,
                                                   (TYPE_QUALS (type)
@@ -7121,18 +7323,12 @@ expand_expr (exp, target, tmode, modifier)
              }
          }
       }
-      /* Fall through.  */
+      goto normal_inner_ref;
 
     case COMPONENT_REF:
-    case BIT_FIELD_REF:
-    case ARRAY_RANGE_REF:
       /* If the operand is a CONSTRUCTOR, we can just extract the
-        appropriate field if it is present.  Don't do this if we have
-        already written the data since we want to refer to that copy
-        and varasm.c assumes that's what we'll do.  */
-      if (code == COMPONENT_REF
-         && TREE_CODE (TREE_OPERAND (exp, 0)) == CONSTRUCTOR
-         && TREE_CST_RTL (TREE_OPERAND (exp, 0)) == 0)
+        appropriate field if it is present.  */
+      if (TREE_CODE (TREE_OPERAND (exp, 0)) == CONSTRUCTOR)
        {
          tree elt;
 
@@ -7152,6 +7348,9 @@ expand_expr (exp, target, tmode, modifier)
                        && (GET_MODE_BITSIZE (DECL_MODE (TREE_PURPOSE (elt)))
                            <= HOST_BITS_PER_WIDE_INT))))
              {
+               if (DECL_BIT_FIELD (TREE_PURPOSE (elt))
+                   && modifier == EXPAND_STACK_PARM)
+                 target = 0;
                op0 = expand_expr (TREE_VALUE (elt), target, tmode, modifier);
                if (DECL_BIT_FIELD (TREE_PURPOSE (elt)))
                  {
@@ -7181,7 +7380,11 @@ expand_expr (exp, target, tmode, modifier)
                return op0;
              }
        }
+      goto normal_inner_ref;
 
+    case BIT_FIELD_REF:
+    case ARRAY_RANGE_REF:
+    normal_inner_ref:
       {
        enum machine_mode mode1;
        HOST_WIDE_INT bitsize, bitpos;
@@ -7206,10 +7409,12 @@ expand_expr (exp, target, tmode, modifier)
                         (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_CONST_ADDRESS
+                         || modifier == EXPAND_STACK_PARM)
                         ? modifier : EXPAND_NORMAL);
 
        /* If this is a constant, put it into a register if it is a
@@ -7226,7 +7431,8 @@ expand_expr (exp, target, tmode, modifier)
 
        if (offset != 0)
          {
-           rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
+           rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode,
+                                         EXPAND_SUM);
 
            /* If this object is in a register, put it into memory.
               This case can't occur in C, but can in Ada if we have
@@ -7239,7 +7445,8 @@ expand_expr (exp, target, tmode, modifier)
                   forcing the SAVE_EXPR into memory.  */
                if (TREE_CODE (TREE_OPERAND (exp, 0)) == SAVE_EXPR)
                  {
-                   put_var_into_stack (TREE_OPERAND (exp, 0));
+                   put_var_into_stack (TREE_OPERAND (exp, 0), 
+                                       /*rescan=*/true);
                    op0 = SAVE_EXPR_RTL (TREE_OPERAND (exp, 0));
                  }
                else
@@ -7260,7 +7467,7 @@ expand_expr (exp, target, tmode, modifier)
 
 #ifdef POINTERS_EXTEND_UNSIGNED
            if (GET_MODE (offset_rtx) != Pmode)
-             offset_rtx = convert_memory_address (Pmode, offset_rtx);
+             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);
@@ -7325,10 +7532,10 @@ expand_expr (exp, target, tmode, modifier)
            /* If the field isn't aligned enough to fetch as a memref,
               fetch it as a bit field.  */
            || (mode1 != BLKmode
-               && SLOW_UNALIGNED_ACCESS (mode1, MEM_ALIGN (op0))
-               && ((TYPE_ALIGN (TREE_TYPE (tem))
-                    < GET_MODE_ALIGNMENT (mode))
-                   || (bitpos % GET_MODE_ALIGNMENT (mode) != 0)))
+               && (((TYPE_ALIGN (TREE_TYPE (tem)) < GET_MODE_ALIGNMENT (mode)
+                     || (bitpos % GET_MODE_ALIGNMENT (mode) != 0))
+                    && 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.  */
@@ -7362,7 +7569,8 @@ expand_expr (exp, target, tmode, modifier)
                emit_block_move (target, op0,
                                 GEN_INT ((bitsize + BITS_PER_UNIT - 1)
                                          / BITS_PER_UNIT),
-                                BLOCK_OP_NORMAL);
+                                (modifier == EXPAND_STACK_PARM
+                                 ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
 
                return target;
              }
@@ -7372,8 +7580,10 @@ expand_expr (exp, target, tmode, modifier)
            if (GET_CODE (op0) == MEM && GET_CODE (XEXP (op0, 0)) == REG)
              mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
 
-           op0 = extract_bit_field (op0, bitsize, bitpos,
-                                    unsignedp, target, ext_mode, ext_mode,
+           op0 = extract_bit_field (op0, bitsize, bitpos, unsignedp,
+                                    (modifier == EXPAND_STACK_PARM
+                                     ? NULL_RTX : target),
+                                    ext_mode, ext_mode,
                                     int_size_in_bytes (TREE_TYPE (tem)));
 
            /* If the result is a record type and BITSIZE is narrower than
@@ -7617,8 +7827,8 @@ expand_expr (exp, target, tmode, modifier)
        {
          if (DECL_BUILT_IN_CLASS (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
              == BUILT_IN_FRONTEND)
-           return (*lang_hooks.expand_expr)
-             (exp, original_target, tmode, modifier);
+           return (*lang_hooks.expand_expr) (exp, original_target,
+                                             tmode, modifier);
          else
            return expand_builtin (exp, target, subtarget, tmode, ignore);
        }
@@ -7654,7 +7864,8 @@ expand_expr (exp, target, tmode, modifier)
          if (GET_CODE (target) == MEM)
            /* Store data into beginning of memory target.  */
            store_expr (TREE_OPERAND (exp, 0),
-                       adjust_address (target, TYPE_MODE (valtype), 0), 0);
+                       adjust_address (target, TYPE_MODE (valtype), 0),
+                       modifier == EXPAND_STACK_PARM ? 2 : 0);
 
          else if (GET_CODE (target) == REG)
            /* Store this field into a union of the proper type.  */
@@ -7722,12 +7933,14 @@ expand_expr (exp, target, tmode, modifier)
       op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, modifier);
 
       /* If the input and output modes are both the same, we are done.
-        Otherwise, if neither mode is BLKmode and both are within a word, we
-        can use gen_lowpart.  If neither is true, make sure the operand is
-        in memory and convert the MEM to the new mode.  */
+        Otherwise, if neither mode is BLKmode and both are integral and within
+        a word, we can use gen_lowpart.  If neither is true, make sure the
+        operand is in memory and convert the MEM to the new mode.  */
       if (TYPE_MODE (type) == GET_MODE (op0))
        ;
       else if (TYPE_MODE (type) != BLKmode && GET_MODE (op0) != BLKmode
+              && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
+              && GET_MODE_CLASS (TYPE_MODE (type)) == MODE_INT
               && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_WORD
               && GET_MODE_SIZE (GET_MODE (op0)) <= UNITS_PER_WORD)
        op0 = gen_lowpart (TYPE_MODE (type), op0);
@@ -7779,7 +7992,8 @@ expand_expr (exp, target, tmode, modifier)
              if (GET_MODE (op0) == BLKmode)
                emit_block_move (new_with_op0_mode, op0,
                                 GEN_INT (GET_MODE_SIZE (TYPE_MODE (type))),
-                                BLOCK_OP_NORMAL);
+                                (modifier == EXPAND_STACK_PARM
+                                 ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
              else
                emit_move_insn (new_with_op0_mode, op0);
 
@@ -7792,9 +8006,6 @@ expand_expr (exp, target, tmode, modifier)
       return op0;
 
     case PLUS_EXPR:
-      /* We come here from MINUS_EXPR when the second operand is a
-         constant.  */
-    plus_expr:
       this_optab = ! unsignedp && flag_trapv
                    && (GET_MODE_CLASS (mode) == MODE_INT)
                    ? addv_optab : add_optab;
@@ -7834,6 +8045,8 @@ expand_expr (exp, target, tmode, modifier)
       if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER
          || (mode == ptr_mode && (unsignedp || ! flag_trapv)))
        {
+         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)))
@@ -7890,20 +8103,30 @@ expand_expr (exp, target, tmode, modifier)
            }
        }
 
+      if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
+       subtarget = 0;
+
       /* 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;
-
-      if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
-       subtarget = 0;
+       {
+         op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+         op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
+         if (op0 == const0_rtx)
+           return op1;
+         if (op1 == const0_rtx)
+           return op0;
+         goto binop2;
+       }
 
       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, modifier);
       op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, modifier);
 
+      /* We come here from MINUS_EXPR when the second operand is a
+         constant.  */
     both_summands:
       /* Make sure any term that's a sum with a constant comes last.  */
       if (GET_CODE (op0) == PLUS
@@ -7973,27 +8196,33 @@ expand_expr (exp, target, tmode, modifier)
          else
            return gen_rtx_MINUS (mode, op0, op1);
        }
-      /* Convert A - const to A + (-const).  */
-      if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
-       {
-         tree negated = fold (build1 (NEGATE_EXPR, type,
-                                      TREE_OPERAND (exp, 1)));
 
-         if (TREE_UNSIGNED (type) || TREE_OVERFLOW (negated))
-           /* If we can't negate the constant in TYPE, leave it alone and
-              expand_binop will negate it for us.  We used to try to do it
-              here in the signed version of TYPE, but that doesn't work
-              on POINTER_TYPEs.  */;
-         else
-           {
-             exp = build (PLUS_EXPR, type, TREE_OPERAND (exp, 0), negated);
-             goto plus_expr;
-           }
-       }
       this_optab = ! unsignedp && flag_trapv
                    && (GET_MODE_CLASS(mode) == MODE_INT)
                    ? subv_optab : sub_optab;
-      goto binop;
+
+      /* 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;
+
+      if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
+       subtarget = 0;
+
+      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, modifier);
+      op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, modifier);
+
+      /* Convert A - const to A + (-const).  */
+      if (GET_CODE (op1) == CONST_INT)
+       {
+         op1 = negate_rtx (mode, op1);
+         goto both_summands;
+       }
+
+      goto binop2;
 
     case MULT_EXPR:
       /* If first operand is constant, swap them.
@@ -8012,6 +8241,8 @@ expand_expr (exp, target, tmode, modifier)
       if (modifier == EXPAND_SUM && mode == ptr_mode
          && host_integerp (TREE_OPERAND (exp, 1), 0))
        {
+         tree exp1 = TREE_OPERAND (exp, 1);
+
          op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode,
                             EXPAND_SUM);
 
@@ -8030,14 +8261,17 @@ expand_expr (exp, target, tmode, modifier)
          if (GET_CODE (op0) != REG)
            op0 = copy_to_mode_reg (mode, op0);
 
-         return
-           gen_rtx_MULT (mode, op0,
-                         GEN_INT (tree_low_cst (TREE_OPERAND (exp, 1), 0)));
+         return gen_rtx_MULT (mode, op0,
+                              gen_int_mode (tree_low_cst (exp1, 0),
+                                            TYPE_MODE (TREE_TYPE (exp1))));
        }
 
       if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
        subtarget = 0;
 
+      if (modifier == EXPAND_STACK_PARM)
+       target = 0;
+
       /* 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,
@@ -8121,6 +8355,8 @@ expand_expr (exp, target, tmode, modifier)
     case EXACT_DIV_EXPR:
       if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
        subtarget = 0;
+      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.  */
@@ -8139,7 +8375,7 @@ expand_expr (exp, target, tmode, modifier)
                                   build (RDIV_EXPR, type,
                                          build_real (type, dconst1),
                                          TREE_OPERAND (exp, 1))),
-                           target, tmode, unsignedp);
+                           target, tmode, modifier);
       this_optab = sdiv_optab;
       goto binop;
 
@@ -8149,6 +8385,8 @@ expand_expr (exp, target, tmode, modifier)
     case ROUND_MOD_EXPR:
       if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
        subtarget = 0;
+      if (modifier == EXPAND_STACK_PARM)
+       target = 0;
       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
       op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
       return expand_divmod (1, code, mode, op0, op1, target, unsignedp);
@@ -8160,14 +8398,14 @@ expand_expr (exp, target, tmode, modifier)
 
     case FIX_TRUNC_EXPR:
       op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
-      if (target == 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);
-      if (target == 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.  */
@@ -8180,6 +8418,8 @@ expand_expr (exp, target, tmode, modifier)
 
     case NEGATE_EXPR:
       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+      if (modifier == EXPAND_STACK_PARM)
+       target = 0;
       temp = expand_unop (mode,
                          ! unsignedp && flag_trapv
                          && (GET_MODE_CLASS(mode) == MODE_INT)
@@ -8190,6 +8430,8 @@ expand_expr (exp, target, tmode, modifier)
 
     case ABS_EXPR:
       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+      if (modifier == EXPAND_STACK_PARM)
+       target = 0;
 
       /* Handle complex values specially.  */
       if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
@@ -8207,7 +8449,9 @@ expand_expr (exp, target, tmode, modifier)
     case MAX_EXPR:
     case MIN_EXPR:
       target = original_target;
-      if (target == 0 || ! safe_from_p (target, TREE_OPERAND (exp, 1), 1)
+      if (target == 0
+         || modifier == EXPAND_STACK_PARM
+         || ! safe_from_p (target, TREE_OPERAND (exp, 1), 1)
          || (GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
          || GET_MODE (target) != mode
          || (GET_CODE (target) == REG
@@ -8264,6 +8508,8 @@ expand_expr (exp, target, tmode, modifier)
 
     case BIT_NOT_EXPR:
       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+      if (modifier == EXPAND_STACK_PARM)
+       target = 0;
       temp = expand_unop (mode, one_cmpl_optab, op0, target, 1);
       if (temp == 0)
        abort ();
@@ -8271,18 +8517,48 @@ expand_expr (exp, target, tmode, modifier)
 
     case FFS_EXPR:
       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+      if (modifier == EXPAND_STACK_PARM)
+       target = 0;
       temp = expand_unop (mode, ffs_optab, op0, target, 1);
       if (temp == 0)
        abort ();
       return temp;
 
-      /* ??? 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.  */
+    case CLZ_EXPR:
+      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+      temp = expand_unop (mode, clz_optab, op0, target, 1);
+      if (temp == 0)
+       abort ();
+      return temp;
 
-      /* 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
+    case CTZ_EXPR:
+      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+      temp = expand_unop (mode, ctz_optab, op0, target, 1);
+      if (temp == 0)
+       abort ();
+      return temp;
+
+    case POPCOUNT_EXPR:
+      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+      temp = expand_unop (mode, popcount_optab, op0, target, 1);
+      if (temp == 0)
+       abort ();
+      return temp;
+
+    case PARITY_EXPR:
+      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+      temp = expand_unop (mode, parity_optab, op0, target, 1);
+      if (temp == 0)
+       abort ();
+      return temp;
+
+      /* ??? 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.  */
+
+      /* 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
@@ -8310,6 +8586,8 @@ expand_expr (exp, target, tmode, modifier)
     case RROTATE_EXPR:
       if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
        subtarget = 0;
+      if (modifier == EXPAND_STACK_PARM)
+       target = 0;
       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
       return expand_shift (code, mode, op0, TREE_OPERAND (exp, 1), target,
                           unsignedp);
@@ -8329,7 +8607,9 @@ expand_expr (exp, target, tmode, modifier)
     case UNGT_EXPR:
     case UNGE_EXPR:
     case UNEQ_EXPR:
-      temp = do_store_flag (exp, target, tmode != VOIDmode ? tmode : mode, 0);
+      temp = do_store_flag (exp,
+                           modifier != EXPAND_STACK_PARM ? target : NULL_RTX,
+                           tmode != VOIDmode ? tmode : mode, 0);
       if (temp != 0)
        return temp;
 
@@ -8378,7 +8658,9 @@ expand_expr (exp, target, tmode, modifier)
     case TRUTH_ANDIF_EXPR:
     case TRUTH_ORIF_EXPR:
       if (! ignore
-         && (target == 0 || ! safe_from_p (target, exp, 1)
+         && (target == 0
+             || modifier == EXPAND_STACK_PARM
+             || ! safe_from_p (target, exp, 1)
              /* Make sure we don't have a hard reg (such as function's return
                 value) live across basic blocks, if not optimizing.  */
              || (!optimize && GET_CODE (target) == REG
@@ -8398,6 +8680,8 @@ expand_expr (exp, target, tmode, modifier)
       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, 0);
       /* The parser is careful to generate TRUTH_NOT_EXPR
         only with operands that are always zero or one.  */
@@ -8412,7 +8696,7 @@ expand_expr (exp, target, tmode, modifier)
       emit_queue ();
       return expand_expr (TREE_OPERAND (exp, 1),
                          (ignore ? const0_rtx : target),
-                         VOIDmode, 0);
+                         VOIDmode, modifier);
 
     case COND_EXPR:
       /* If we would have a "singleton" (see below) were it not for a
@@ -8465,6 +8749,8 @@ expand_expr (exp, target, tmode, modifier)
                return const0_rtx;
              }
 
+           if (modifier == EXPAND_STACK_PARM)
+             target = 0;
            op0 = expand_expr (TREE_OPERAND (exp, 0), target, mode, modifier);
            if (GET_MODE (op0) == mode)
              return op0;
@@ -8505,6 +8791,8 @@ expand_expr (exp, target, tmode, modifier)
 
        if (ignore)
          temp = 0;
+       else if (modifier == EXPAND_STACK_PARM)
+         temp = assign_temp (type, 0, 0, 1);
        else if (original_target
                 && (safe_from_p (original_target, TREE_OPERAND (exp, 0), 1)
                     || (singleton && GET_CODE (original_target) == REG
@@ -8538,6 +8826,7 @@ expand_expr (exp, target, tmode, modifier)
            && TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<')
          {
            rtx result;
+           tree cond;
            optab boptab = (TREE_CODE (binary_op) == PLUS_EXPR
                            ? (TYPE_TRAP_SIGNED (TREE_TYPE (binary_op))
                               ? addv_optab : add_optab)
@@ -8547,20 +8836,14 @@ expand_expr (exp, target, tmode, modifier)
                            : TREE_CODE (binary_op) == BIT_IOR_EXPR ? ior_optab
                            : xor_optab);
 
-           /* If we had X ? A : A + 1, do this as A + (X == 0).
-
-              We have to invert the truth value here and then put it
-              back later if do_store_flag fails.  We cannot simply copy
-              TREE_OPERAND (exp, 0) to another variable and modify that
-              because invert_truthvalue can modify the tree pointed to
-              by its argument.  */
+           /* If we had X ? A : A + 1, do this as A + (X == 0).  */
            if (singleton == TREE_OPERAND (exp, 1))
-             TREE_OPERAND (exp, 0)
-               = invert_truthvalue (TREE_OPERAND (exp, 0));
+             cond = invert_truthvalue (TREE_OPERAND (exp, 0));
+           else
+             cond = TREE_OPERAND (exp, 0);
 
-           result = do_store_flag (TREE_OPERAND (exp, 0),
-                                   (safe_from_p (temp, singleton, 1)
-                                    ? temp : NULL_RTX),
+           result = do_store_flag (cond, (safe_from_p (temp, singleton, 1)
+                                          ? temp : NULL_RTX),
                                    mode, BRANCH_COST <= 1);
 
            if (result != 0 && ! integer_onep (TREE_OPERAND (binary_op, 1)))
@@ -8578,9 +8861,6 @@ expand_expr (exp, target, tmode, modifier)
                return expand_binop (mode, boptab, op1, result, temp,
                                     unsignedp, OPTAB_LIB_WIDEN);
              }
-           else if (singleton == TREE_OPERAND (exp, 1))
-             TREE_OPERAND (exp, 0)
-               = invert_truthvalue (TREE_OPERAND (exp, 0));
          }
 
        do_pending_stack_adjust ();
@@ -8600,7 +8880,8 @@ expand_expr (exp, target, tmode, modifier)
                    || (GET_CODE (temp) == REG
                        && REGNO (temp) < FIRST_PSEUDO_REGISTER))
                  temp = gen_reg_rtx (mode);
-               store_expr (singleton, temp, 0);
+               store_expr (singleton, temp,
+                           modifier == EXPAND_STACK_PARM ? 2 : 0);
              }
            else
              expand_expr (singleton,
@@ -8619,11 +8900,11 @@ expand_expr (exp, target, tmode, modifier)
              store_expr (build (TREE_CODE (binary_op), type,
                                 make_tree (type, temp),
                                 TREE_OPERAND (binary_op, 1)),
-                         temp, 0);
+                         temp, modifier == EXPAND_STACK_PARM ? 2 : 0);
            else
              store_expr (build1 (TREE_CODE (unary_op), type,
                                  make_tree (type, temp)),
-                         temp, 0);
+                         temp, modifier == EXPAND_STACK_PARM ? 2 : 0);
            op1 = op0;
          }
        /* Check for A op 0 ? A : FOO and A op 0 ? FOO : A where OP is any
@@ -8642,11 +8923,13 @@ expand_expr (exp, target, tmode, modifier)
            if (GET_CODE (temp) == REG
                && REGNO (temp) < FIRST_PSEUDO_REGISTER)
              temp = gen_reg_rtx (mode);
-           store_expr (TREE_OPERAND (exp, 1), temp, 0);
+           store_expr (TREE_OPERAND (exp, 1), temp,
+                       modifier == EXPAND_STACK_PARM ? 2 : 0);
            jumpif (TREE_OPERAND (exp, 0), op0);
 
            start_cleanup_deferral ();
-           store_expr (TREE_OPERAND (exp, 2), temp, 0);
+           store_expr (TREE_OPERAND (exp, 2), temp,
+                       modifier == EXPAND_STACK_PARM ? 2 : 0);
            op1 = op0;
          }
        else if (temp
@@ -8661,11 +8944,13 @@ expand_expr (exp, target, tmode, modifier)
            if (GET_CODE (temp) == REG
                && REGNO (temp) < FIRST_PSEUDO_REGISTER)
              temp = gen_reg_rtx (mode);
-           store_expr (TREE_OPERAND (exp, 2), temp, 0);
+           store_expr (TREE_OPERAND (exp, 2), temp,
+                       modifier == EXPAND_STACK_PARM ? 2 : 0);
            jumpifnot (TREE_OPERAND (exp, 0), op0);
 
            start_cleanup_deferral ();
-           store_expr (TREE_OPERAND (exp, 1), temp, 0);
+           store_expr (TREE_OPERAND (exp, 1), temp,
+                       modifier == EXPAND_STACK_PARM ? 2 : 0);
            op1 = op0;
          }
        else
@@ -8679,7 +8964,8 @@ expand_expr (exp, target, tmode, modifier)
               example A ? throw : E  */
            if (temp != 0
                && TREE_TYPE (TREE_OPERAND (exp, 1)) != void_type_node)
-             store_expr (TREE_OPERAND (exp, 1), temp, 0);
+             store_expr (TREE_OPERAND (exp, 1), temp,
+                         modifier == EXPAND_STACK_PARM ? 2 : 0);
            else
              expand_expr (TREE_OPERAND (exp, 1),
                           ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
@@ -8691,7 +8977,8 @@ expand_expr (exp, target, tmode, modifier)
            start_cleanup_deferral ();
            if (temp != 0
                && TREE_TYPE (TREE_OPERAND (exp, 2)) != void_type_node)
-             store_expr (TREE_OPERAND (exp, 2), temp, 0);
+             store_expr (TREE_OPERAND (exp, 2), temp,
+                         modifier == EXPAND_STACK_PARM ? 2 : 0);
            else
              expand_expr (TREE_OPERAND (exp, 2),
                           ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
@@ -8749,7 +9036,7 @@ expand_expr (exp, target, tmode, modifier)
                preserve_temp_slots (target);
                SET_DECL_RTL (slot, target);
                if (TREE_ADDRESSABLE (slot))
-                 put_var_into_stack (slot);
+                 put_var_into_stack (slot, /*rescan=*/false);
 
                /* Since SLOT is not known to the called function
                   to belong to its stack frame, we must build an explicit
@@ -8788,7 +9075,7 @@ expand_expr (exp, target, tmode, modifier)
                /* If we must have an addressable slot, then make sure that
                   the RTL that we just stored in slot is OK.  */
                if (TREE_ADDRESSABLE (slot))
-                 put_var_into_stack (slot);
+                 put_var_into_stack (slot, /*rescan=*/true);
              }
          }
 
@@ -8796,7 +9083,7 @@ expand_expr (exp, target, tmode, modifier)
        /* Mark it as expanded.  */
        TREE_OPERAND (exp, 1) = NULL_TREE;
 
-       store_expr (exp1, target, 0);
+       store_expr (exp1, target, modifier == EXPAND_STACK_PARM ? 2 : 0);
 
        expand_decl_cleanup_eh (NULL_TREE, cleanups, CLEANUP_EH_ONLY (exp));
 
@@ -8881,6 +9168,8 @@ expand_expr (exp, target, tmode, modifier)
       return expand_increment (exp, ! ignore, ignore);
 
     case ADDR_EXPR:
+      if (modifier == EXPAND_STACK_PARM)
+       target = 0;
       /* Are we taking the address of a nested function?  */
       if (TREE_CODE (TREE_OPERAND (exp, 0)) == FUNCTION_DECL
          && decl_function_context (TREE_OPERAND (exp, 0)) != 0
@@ -8930,13 +9219,14 @@ expand_expr (exp, target, tmode, modifier)
                                   op0);
          else if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
                   || GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF
-                  || GET_CODE (op0) == PARALLEL)
+                  || GET_CODE (op0) == PARALLEL || GET_CODE (op0) == LO_SUM)
            {
              /* If the operand is a SAVE_EXPR, we can deal with this by
                 forcing the SAVE_EXPR into memory.  */
              if (TREE_CODE (TREE_OPERAND (exp, 0)) == SAVE_EXPR)
                {
-                 put_var_into_stack (TREE_OPERAND (exp, 0));
+                 put_var_into_stack (TREE_OPERAND (exp, 0),
+                                     /*rescan=*/true);
                  op0 = SAVE_EXPR_RTL (TREE_OPERAND (exp, 0));
                }
              else
@@ -8989,20 +9279,30 @@ expand_expr (exp, target, tmode, modifier)
              && MEM_ALIGN (op0) < BIGGEST_ALIGNMENT)
            {
              tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
-             rtx new
-               = assign_stack_temp_for_type
-                 (TYPE_MODE (inner_type),
-                  MEM_SIZE (op0) ? INTVAL (MEM_SIZE (op0))
-                  : int_size_in_bytes (inner_type),
-                  1, build_qualified_type (inner_type,
-                                           (TYPE_QUALS (inner_type)
-                                            | TYPE_QUAL_CONST)));
+             rtx new;
 
              if (TYPE_ALIGN_OK (inner_type))
                abort ();
 
+             if (TREE_ADDRESSABLE (inner_type))
+               {
+                 /* We can't make a bitwise copy of this object, so fail.  */
+                 error ("cannot take the address of an unaligned member");
+                 return const0_rtx;
+               }
+
+             new = assign_stack_temp_for_type
+               (TYPE_MODE (inner_type),
+                MEM_SIZE (op0) ? INTVAL (MEM_SIZE (op0))
+                : int_size_in_bytes (inner_type),
+                1, build_qualified_type (inner_type,
+                                         (TYPE_QUALS (inner_type)
+                                          | TYPE_QUAL_CONST)));
+
              emit_block_move (new, op0, expr_size (TREE_OPERAND (exp, 0)),
-                              BLOCK_OP_NORMAL);
+                              (modifier == EXPAND_STACK_PARM
+                               ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
+
              op0 = new;
            }
 
@@ -9218,6 +9518,8 @@ expand_expr (exp, target, tmode, modifier)
   op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
   op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
  binop2:
+  if (modifier == EXPAND_STACK_PARM)
+    target = 0;
   temp = expand_binop (mode, this_optab, op0, op1, target,
                       unsignedp, OPTAB_LIB_WIDEN);
   if (temp == 0)
@@ -9276,7 +9578,7 @@ is_aligning_offset (offset, exp)
 }
 \f
 /* Return the tree node if an ARG corresponds to a string constant or zero
-   if it doesn't.  If we return non-zero, set *PTR_OFFSET to the offset
+   if it doesn't.  If we return nonzero, set *PTR_OFFSET to the offset
    in bytes within the string that ARG is accessing.  The type of the
    offset will be `sizetype'.  */
 
@@ -9523,987 +9825,13 @@ expand_increment (exp, post, ignore)
   return temp;
 }
 \f
-/* At the start of a function, record that we have no previously-pushed
-   arguments waiting to be popped.  */
-
-void
-init_pending_stack_adjust ()
-{
-  pending_stack_adjust = 0;
-}
-
-/* When exiting from function, if safe, clear out any pending stack adjust
-   so the adjustment won't get done.
-
-   Note, if the current function calls alloca, then it must have a
-   frame pointer regardless of the value of flag_omit_frame_pointer.  */
-
-void
-clear_pending_stack_adjust ()
-{
-#ifdef EXIT_IGNORE_STACK
-  if (optimize > 0
-      && (! flag_omit_frame_pointer || current_function_calls_alloca)
-      && EXIT_IGNORE_STACK
-      && ! (DECL_INLINE (current_function_decl) && ! flag_no_inline)
-      && ! flag_inline_functions)
-    {
-      stack_pointer_delta -= pending_stack_adjust,
-      pending_stack_adjust = 0;
-    }
-#endif
-}
-
-/* Pop any previously-pushed arguments that have not been popped yet.  */
-
-void
-do_pending_stack_adjust ()
-{
-  if (inhibit_defer_pop == 0)
-    {
-      if (pending_stack_adjust != 0)
-       adjust_stack (GEN_INT (pending_stack_adjust));
-      pending_stack_adjust = 0;
-    }
-}
-\f
-/* Expand conditional expressions.  */
-
-/* Generate code to evaluate EXP and jump to LABEL if the value is zero.
-   LABEL is an rtx of code CODE_LABEL, in this function and all the
-   functions here.  */
-
-void
-jumpifnot (exp, label)
-     tree exp;
-     rtx label;
-{
-  do_jump (exp, label, NULL_RTX);
-}
-
-/* Generate code to evaluate EXP and jump to LABEL if the value is nonzero.  */
-
-void
-jumpif (exp, label)
-     tree exp;
-     rtx label;
-{
-  do_jump (exp, NULL_RTX, label);
-}
-
-/* Generate code to evaluate EXP and jump to IF_FALSE_LABEL if
-   the result is zero, or IF_TRUE_LABEL if the result is one.
-   Either of IF_FALSE_LABEL and IF_TRUE_LABEL may be zero,
-   meaning fall through in that case.
-
-   do_jump always does any pending stack adjust except when it does not
-   actually perform a jump.  An example where there is no jump
-   is when EXP is `(foo (), 0)' and IF_FALSE_LABEL is null.
-
-   This function is responsible for optimizing cases such as
-   &&, || and comparison operators in EXP.  */
-
-void
-do_jump (exp, if_false_label, if_true_label)
-     tree exp;
-     rtx if_false_label, if_true_label;
-{
-  enum tree_code code = TREE_CODE (exp);
-  /* Some cases need to create a label to jump to
-     in order to properly fall through.
-     These cases set DROP_THROUGH_LABEL nonzero.  */
-  rtx drop_through_label = 0;
-  rtx temp;
-  int i;
-  tree type;
-  enum machine_mode mode;
-
-#ifdef MAX_INTEGER_COMPUTATION_MODE
-  check_max_integer_computation_mode (exp);
-#endif
-
-  emit_queue ();
-
-  switch (code)
-    {
-    case ERROR_MARK:
-      break;
-
-    case INTEGER_CST:
-      temp = integer_zerop (exp) ? if_false_label : if_true_label;
-      if (temp)
-       emit_jump (temp);
-      break;
-
-#if 0
-      /* This is not true with #pragma weak  */
-    case ADDR_EXPR:
-      /* The address of something can never be zero.  */
-      if (if_true_label)
-       emit_jump (if_true_label);
-      break;
-#endif
-
-    case NOP_EXPR:
-      if (TREE_CODE (TREE_OPERAND (exp, 0)) == COMPONENT_REF
-         || TREE_CODE (TREE_OPERAND (exp, 0)) == BIT_FIELD_REF
-         || TREE_CODE (TREE_OPERAND (exp, 0)) == ARRAY_REF
-         || TREE_CODE (TREE_OPERAND (exp, 0)) == ARRAY_RANGE_REF)
-       goto normal;
-    case CONVERT_EXPR:
-      /* If we are narrowing the operand, we have to do the compare in the
-        narrower mode.  */
-      if ((TYPE_PRECISION (TREE_TYPE (exp))
-          < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0)))))
-       goto normal;
-    case NON_LVALUE_EXPR:
-    case REFERENCE_EXPR:
-    case ABS_EXPR:
-    case NEGATE_EXPR:
-    case LROTATE_EXPR:
-    case RROTATE_EXPR:
-      /* These cannot change zero->non-zero or vice versa.  */
-      do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
-      break;
-
-    case WITH_RECORD_EXPR:
-      /* Put the object on the placeholder list, recurse through our first
-        operand, and pop the list.  */
-      placeholder_list = tree_cons (TREE_OPERAND (exp, 1), NULL_TREE,
-                                   placeholder_list);
-      do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
-      placeholder_list = TREE_CHAIN (placeholder_list);
-      break;
-
-#if 0
-      /* This is never less insns than evaluating the PLUS_EXPR followed by
-        a test and can be longer if the test is eliminated.  */
-    case PLUS_EXPR:
-      /* Reduce to minus.  */
-      exp = build (MINUS_EXPR, TREE_TYPE (exp),
-                  TREE_OPERAND (exp, 0),
-                  fold (build1 (NEGATE_EXPR, TREE_TYPE (TREE_OPERAND (exp, 1)),
-                                TREE_OPERAND (exp, 1))));
-      /* Process as MINUS.  */
-#endif
-
-    case MINUS_EXPR:
-      /* Non-zero iff operands of minus differ.  */
-      do_compare_and_jump (build (NE_EXPR, TREE_TYPE (exp),
-                                 TREE_OPERAND (exp, 0),
-                                 TREE_OPERAND (exp, 1)),
-                          NE, NE, if_false_label, if_true_label);
-      break;
-
-    case BIT_AND_EXPR:
-      /* If we are AND'ing with a small constant, do this comparison in the
-        smallest type that fits.  If the machine doesn't have comparisons
-        that small, it will be converted back to the wider comparison.
-        This helps if we are testing the sign bit of a narrower object.
-        combine can't do this for us because it can't know whether a
-        ZERO_EXTRACT or a compare in a smaller mode exists, but we do.  */
-
-      if (! SLOW_BYTE_ACCESS
-         && TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
-         && TYPE_PRECISION (TREE_TYPE (exp)) <= HOST_BITS_PER_WIDE_INT
-         && (i = tree_floor_log2 (TREE_OPERAND (exp, 1))) >= 0
-         && (mode = mode_for_size (i + 1, MODE_INT, 0)) != BLKmode
-         && (type = (*lang_hooks.types.type_for_mode) (mode, 1)) != 0
-         && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp))
-         && (cmp_optab->handlers[(int) TYPE_MODE (type)].insn_code
-             != CODE_FOR_nothing))
-       {
-         do_jump (convert (type, exp), if_false_label, if_true_label);
-         break;
-       }
-      goto normal;
-
-    case TRUTH_NOT_EXPR:
-      do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
-      break;
-
-    case TRUTH_ANDIF_EXPR:
-      if (if_false_label == 0)
-       if_false_label = drop_through_label = gen_label_rtx ();
-      do_jump (TREE_OPERAND (exp, 0), if_false_label, NULL_RTX);
-      start_cleanup_deferral ();
-      do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
-      end_cleanup_deferral ();
-      break;
-
-    case TRUTH_ORIF_EXPR:
-      if (if_true_label == 0)
-       if_true_label = drop_through_label = gen_label_rtx ();
-      do_jump (TREE_OPERAND (exp, 0), NULL_RTX, if_true_label);
-      start_cleanup_deferral ();
-      do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
-      end_cleanup_deferral ();
-      break;
-
-    case COMPOUND_EXPR:
-      push_temp_slots ();
-      expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
-      preserve_temp_slots (NULL_RTX);
-      free_temp_slots ();
-      pop_temp_slots ();
-      emit_queue ();
-      do_pending_stack_adjust ();
-      do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
-      break;
-
-    case COMPONENT_REF:
-    case BIT_FIELD_REF:
-    case ARRAY_REF:
-    case ARRAY_RANGE_REF:
-      {
-       HOST_WIDE_INT bitsize, bitpos;
-       int unsignedp;
-       enum machine_mode mode;
-       tree type;
-       tree offset;
-       int volatilep = 0;
-
-       /* Get description of this reference.  We don't actually care
-          about the underlying object here.  */
-       get_inner_reference (exp, &bitsize, &bitpos, &offset, &mode,
-                            &unsignedp, &volatilep);
-
-       type = (*lang_hooks.types.type_for_size) (bitsize, unsignedp);
-       if (! SLOW_BYTE_ACCESS
-           && type != 0 && bitsize >= 0
-           && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp))
-           && (cmp_optab->handlers[(int) TYPE_MODE (type)].insn_code
-               != CODE_FOR_nothing))
-         {
-           do_jump (convert (type, exp), if_false_label, if_true_label);
-           break;
-         }
-       goto normal;
-      }
-
-    case COND_EXPR:
-      /* Do (a ? 1 : 0) and (a ? 0 : 1) as special cases.  */
-      if (integer_onep (TREE_OPERAND (exp, 1))
-         && integer_zerop (TREE_OPERAND (exp, 2)))
-       do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
-
-      else if (integer_zerop (TREE_OPERAND (exp, 1))
-              && integer_onep (TREE_OPERAND (exp, 2)))
-       do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
-
-      else
-       {
-         rtx label1 = gen_label_rtx ();
-         drop_through_label = gen_label_rtx ();
-
-         do_jump (TREE_OPERAND (exp, 0), label1, NULL_RTX);
-
-         start_cleanup_deferral ();
-         /* Now the THEN-expression.  */
-         do_jump (TREE_OPERAND (exp, 1),
-                  if_false_label ? if_false_label : drop_through_label,
-                  if_true_label ? if_true_label : drop_through_label);
-         /* In case the do_jump just above never jumps.  */
-         do_pending_stack_adjust ();
-         emit_label (label1);
-
-         /* Now the ELSE-expression.  */
-         do_jump (TREE_OPERAND (exp, 2),
-                  if_false_label ? if_false_label : drop_through_label,
-                  if_true_label ? if_true_label : drop_through_label);
-         end_cleanup_deferral ();
-       }
-      break;
-
-    case EQ_EXPR:
-      {
-       tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
-
-       if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_FLOAT
-           || GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_INT)
-         {
-           tree exp0 = save_expr (TREE_OPERAND (exp, 0));
-           tree exp1 = save_expr (TREE_OPERAND (exp, 1));
-           do_jump
-             (fold
-              (build (TRUTH_ANDIF_EXPR, TREE_TYPE (exp),
-                      fold (build (EQ_EXPR, TREE_TYPE (exp),
-                                   fold (build1 (REALPART_EXPR,
-                                                 TREE_TYPE (inner_type),
-                                                 exp0)),
-                                   fold (build1 (REALPART_EXPR,
-                                                 TREE_TYPE (inner_type),
-                                                 exp1)))),
-                      fold (build (EQ_EXPR, TREE_TYPE (exp),
-                                   fold (build1 (IMAGPART_EXPR,
-                                                 TREE_TYPE (inner_type),
-                                                 exp0)),
-                                   fold (build1 (IMAGPART_EXPR,
-                                                 TREE_TYPE (inner_type),
-                                                 exp1)))))),
-              if_false_label, if_true_label);
-         }
-
-       else if (integer_zerop (TREE_OPERAND (exp, 1)))
-         do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
-
-       else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT
-                && !can_compare_p (EQ, TYPE_MODE (inner_type), ccp_jump))
-         do_jump_by_parts_equality (exp, if_false_label, if_true_label);
-       else
-         do_compare_and_jump (exp, EQ, EQ, if_false_label, if_true_label);
-       break;
-      }
-
-    case NE_EXPR:
-      {
-       tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
-
-       if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_FLOAT
-           || GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_INT)
-         {
-           tree exp0 = save_expr (TREE_OPERAND (exp, 0));
-           tree exp1 = save_expr (TREE_OPERAND (exp, 1));
-           do_jump
-             (fold
-              (build (TRUTH_ORIF_EXPR, TREE_TYPE (exp),
-                      fold (build (NE_EXPR, TREE_TYPE (exp),
-                                   fold (build1 (REALPART_EXPR,
-                                                 TREE_TYPE (inner_type),
-                                                 exp0)),
-                                   fold (build1 (REALPART_EXPR,
-                                                 TREE_TYPE (inner_type),
-                                                 exp1)))),
-                      fold (build (NE_EXPR, TREE_TYPE (exp),
-                                   fold (build1 (IMAGPART_EXPR,
-                                                 TREE_TYPE (inner_type),
-                                                 exp0)),
-                                   fold (build1 (IMAGPART_EXPR,
-                                                 TREE_TYPE (inner_type),
-                                                 exp1)))))),
-              if_false_label, if_true_label);
-         }
-
-       else if (integer_zerop (TREE_OPERAND (exp, 1)))
-         do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
-
-       else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT
-                && !can_compare_p (NE, TYPE_MODE (inner_type), ccp_jump))
-         do_jump_by_parts_equality (exp, if_true_label, if_false_label);
-       else
-         do_compare_and_jump (exp, NE, NE, if_false_label, if_true_label);
-       break;
-      }
-
-    case LT_EXPR:
-      mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
-      if (GET_MODE_CLASS (mode) == MODE_INT
-         && ! can_compare_p (LT, mode, ccp_jump))
-       do_jump_by_parts_greater (exp, 1, if_false_label, if_true_label);
-      else
-       do_compare_and_jump (exp, LT, LTU, if_false_label, if_true_label);
-      break;
-
-    case LE_EXPR:
-      mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
-      if (GET_MODE_CLASS (mode) == MODE_INT
-         && ! can_compare_p (LE, mode, ccp_jump))
-       do_jump_by_parts_greater (exp, 0, if_true_label, if_false_label);
-      else
-       do_compare_and_jump (exp, LE, LEU, if_false_label, if_true_label);
-      break;
-
-    case GT_EXPR:
-      mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
-      if (GET_MODE_CLASS (mode) == MODE_INT
-         && ! can_compare_p (GT, mode, ccp_jump))
-       do_jump_by_parts_greater (exp, 0, if_false_label, if_true_label);
-      else
-       do_compare_and_jump (exp, GT, GTU, if_false_label, if_true_label);
-      break;
-
-    case GE_EXPR:
-      mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
-      if (GET_MODE_CLASS (mode) == MODE_INT
-         && ! can_compare_p (GE, mode, ccp_jump))
-       do_jump_by_parts_greater (exp, 1, if_true_label, if_false_label);
-      else
-       do_compare_and_jump (exp, GE, GEU, if_false_label, if_true_label);
-      break;
-
-    case UNORDERED_EXPR:
-    case ORDERED_EXPR:
-      {
-       enum rtx_code cmp, rcmp;
-       int do_rev;
-
-       if (code == UNORDERED_EXPR)
-         cmp = UNORDERED, rcmp = ORDERED;
-       else
-         cmp = ORDERED, rcmp = UNORDERED;
-       mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
-
-       do_rev = 0;
-       if (! can_compare_p (cmp, mode, ccp_jump)
-           && (can_compare_p (rcmp, mode, ccp_jump)
-               /* If the target doesn't provide either UNORDERED or ORDERED
-                  comparisons, canonicalize on UNORDERED for the library.  */
-               || rcmp == UNORDERED))
-         do_rev = 1;
-
-       if (! do_rev)
-         do_compare_and_jump (exp, cmp, cmp, if_false_label, if_true_label);
-       else
-         do_compare_and_jump (exp, rcmp, rcmp, if_true_label, if_false_label);
-      }
-      break;
-
-    {
-      enum rtx_code rcode1;
-      enum tree_code tcode2;
-
-      case UNLT_EXPR:
-       rcode1 = UNLT;
-       tcode2 = LT_EXPR;
-       goto unordered_bcc;
-      case UNLE_EXPR:
-       rcode1 = UNLE;
-       tcode2 = LE_EXPR;
-       goto unordered_bcc;
-      case UNGT_EXPR:
-       rcode1 = UNGT;
-       tcode2 = GT_EXPR;
-       goto unordered_bcc;
-      case UNGE_EXPR:
-       rcode1 = UNGE;
-       tcode2 = GE_EXPR;
-       goto unordered_bcc;
-      case UNEQ_EXPR:
-       rcode1 = UNEQ;
-       tcode2 = EQ_EXPR;
-       goto unordered_bcc;
-
-      unordered_bcc:
-       mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
-       if (can_compare_p (rcode1, mode, ccp_jump))
-         do_compare_and_jump (exp, rcode1, rcode1, if_false_label,
-                              if_true_label);
-       else
-         {
-           tree op0 = save_expr (TREE_OPERAND (exp, 0));
-           tree op1 = save_expr (TREE_OPERAND (exp, 1));
-           tree cmp0, cmp1;
-
-           /* If the target doesn't support combined unordered
-              compares, decompose into UNORDERED + comparison.  */
-           cmp0 = fold (build (UNORDERED_EXPR, TREE_TYPE (exp), op0, op1));
-           cmp1 = fold (build (tcode2, TREE_TYPE (exp), op0, op1));
-           exp = build (TRUTH_ORIF_EXPR, TREE_TYPE (exp), cmp0, cmp1);
-           do_jump (exp, if_false_label, if_true_label);
-         }
-      }
-      break;
-
-      /* Special case:
-               __builtin_expect (<test>, 0)    and
-               __builtin_expect (<test>, 1)
-
-        We need to do this here, so that <test> is not converted to a SCC
-        operation on machines that use condition code registers and COMPARE
-        like the PowerPC, and then the jump is done based on whether the SCC
-        operation produced a 1 or 0.  */
-    case CALL_EXPR:
-      /* Check for a built-in function.  */
-      if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR)
-       {
-         tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
-         tree arglist = TREE_OPERAND (exp, 1);
-
-         if (TREE_CODE (fndecl) == FUNCTION_DECL
-             && DECL_BUILT_IN (fndecl)
-             && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT
-             && arglist != NULL_TREE
-             && TREE_CHAIN (arglist) != NULL_TREE)
-           {
-             rtx seq = expand_builtin_expect_jump (exp, if_false_label,
-                                                   if_true_label);
-
-             if (seq != NULL_RTX)
-               {
-                 emit_insn (seq);
-                 return;
-               }
-           }
-       }
-      /* fall through and generate the normal code.  */
-
-    default:
-    normal:
-      temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
-#if 0
-      /* This is not needed any more and causes poor code since it causes
-        comparisons and tests from non-SI objects to have different code
-        sequences.  */
-      /* Copy to register to avoid generating bad insns by cse
-        from (set (mem ...) (arithop))  (set (cc0) (mem ...)).  */
-      if (!cse_not_expected && GET_CODE (temp) == MEM)
-       temp = copy_to_reg (temp);
-#endif
-      do_pending_stack_adjust ();
-      /* Do any postincrements in the expression that was tested.  */
-      emit_queue ();
-
-      if (GET_CODE (temp) == CONST_INT
-         || (GET_CODE (temp) == CONST_DOUBLE && GET_MODE (temp) == VOIDmode)
-         || GET_CODE (temp) == LABEL_REF)
-       {
-         rtx target = temp == const0_rtx ? if_false_label : if_true_label;
-         if (target)
-           emit_jump (target);
-       }
-      else if (GET_MODE_CLASS (GET_MODE (temp)) == MODE_INT
-              && ! can_compare_p (NE, GET_MODE (temp), ccp_jump))
-       /* Note swapping the labels gives us not-equal.  */
-       do_jump_by_parts_equality_rtx (temp, if_true_label, if_false_label);
-      else if (GET_MODE (temp) != VOIDmode)
-       do_compare_rtx_and_jump (temp, CONST0_RTX (GET_MODE (temp)),
-                                NE, TREE_UNSIGNED (TREE_TYPE (exp)),
-                                GET_MODE (temp), NULL_RTX,
-                                if_false_label, if_true_label);
-      else
-       abort ();
-    }
-
-  if (drop_through_label)
-    {
-      /* If do_jump produces code that might be jumped around,
-        do any stack adjusts from that code, before the place
-        where control merges in.  */
-      do_pending_stack_adjust ();
-      emit_label (drop_through_label);
-    }
-}
-\f
-/* Given a comparison expression EXP for values too wide to be compared
-   with one insn, test the comparison and jump to the appropriate label.
-   The code of EXP is ignored; we always test GT if SWAP is 0,
-   and LT if SWAP is 1.  */
-
-static void
-do_jump_by_parts_greater (exp, swap, if_false_label, if_true_label)
-     tree exp;
-     int swap;
-     rtx if_false_label, if_true_label;
-{
-  rtx op0 = expand_expr (TREE_OPERAND (exp, swap), NULL_RTX, VOIDmode, 0);
-  rtx op1 = expand_expr (TREE_OPERAND (exp, !swap), NULL_RTX, VOIDmode, 0);
-  enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
-  int unsignedp = TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0)));
-
-  do_jump_by_parts_greater_rtx (mode, unsignedp, op0, op1, if_false_label, if_true_label);
-}
-
-/* Compare OP0 with OP1, word at a time, in mode MODE.
-   UNSIGNEDP says to do unsigned comparison.
-   Jump to IF_TRUE_LABEL if OP0 is greater, IF_FALSE_LABEL otherwise.  */
-
-void
-do_jump_by_parts_greater_rtx (mode, unsignedp, op0, op1, if_false_label, if_true_label)
-     enum machine_mode mode;
-     int unsignedp;
-     rtx op0, op1;
-     rtx if_false_label, if_true_label;
-{
-  int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD);
-  rtx drop_through_label = 0;
-  int i;
-
-  if (! if_true_label || ! if_false_label)
-    drop_through_label = gen_label_rtx ();
-  if (! if_true_label)
-    if_true_label = drop_through_label;
-  if (! if_false_label)
-    if_false_label = drop_through_label;
-
-  /* Compare a word at a time, high order first.  */
-  for (i = 0; i < nwords; i++)
-    {
-      rtx op0_word, op1_word;
-
-      if (WORDS_BIG_ENDIAN)
-       {
-         op0_word = operand_subword_force (op0, i, mode);
-         op1_word = operand_subword_force (op1, i, mode);
-       }
-      else
-       {
-         op0_word = operand_subword_force (op0, nwords - 1 - i, mode);
-         op1_word = operand_subword_force (op1, nwords - 1 - i, mode);
-       }
-
-      /* All but high-order word must be compared as unsigned.  */
-      do_compare_rtx_and_jump (op0_word, op1_word, GT,
-                              (unsignedp || i > 0), word_mode, NULL_RTX,
-                              NULL_RTX, if_true_label);
-
-      /* Consider lower words only if these are equal.  */
-      do_compare_rtx_and_jump (op0_word, op1_word, NE, unsignedp, word_mode,
-                              NULL_RTX, NULL_RTX, if_false_label);
-    }
-
-  if (if_false_label)
-    emit_jump (if_false_label);
-  if (drop_through_label)
-    emit_label (drop_through_label);
-}
-
-/* Given an EQ_EXPR expression EXP for values too wide to be compared
-   with one insn, test the comparison and jump to the appropriate label.  */
-
-static void
-do_jump_by_parts_equality (exp, if_false_label, if_true_label)
-     tree exp;
-     rtx if_false_label, if_true_label;
-{
-  rtx op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
-  rtx op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
-  enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
-  int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD);
-  int i;
-  rtx drop_through_label = 0;
-
-  if (! if_false_label)
-    drop_through_label = if_false_label = gen_label_rtx ();
-
-  for (i = 0; i < nwords; i++)
-    do_compare_rtx_and_jump (operand_subword_force (op0, i, mode),
-                            operand_subword_force (op1, i, mode),
-                            EQ, TREE_UNSIGNED (TREE_TYPE (exp)),
-                            word_mode, NULL_RTX, if_false_label, NULL_RTX);
-
-  if (if_true_label)
-    emit_jump (if_true_label);
-  if (drop_through_label)
-    emit_label (drop_through_label);
-}
-\f
-/* Jump according to whether OP0 is 0.
-   We assume that OP0 has an integer mode that is too wide
-   for the available compare insns.  */
-
-void
-do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label)
-     rtx op0;
-     rtx if_false_label, if_true_label;
-{
-  int nwords = GET_MODE_SIZE (GET_MODE (op0)) / UNITS_PER_WORD;
-  rtx part;
-  int i;
-  rtx drop_through_label = 0;
-
-  /* The fastest way of doing this comparison on almost any machine is to
-     "or" all the words and compare the result.  If all have to be loaded
-     from memory and this is a very wide item, it's possible this may
-     be slower, but that's highly unlikely.  */
-
-  part = gen_reg_rtx (word_mode);
-  emit_move_insn (part, operand_subword_force (op0, 0, GET_MODE (op0)));
-  for (i = 1; i < nwords && part != 0; i++)
-    part = expand_binop (word_mode, ior_optab, part,
-                        operand_subword_force (op0, i, GET_MODE (op0)),
-                        part, 1, OPTAB_WIDEN);
-
-  if (part != 0)
-    {
-      do_compare_rtx_and_jump (part, const0_rtx, EQ, 1, word_mode,
-                              NULL_RTX, if_false_label, if_true_label);
-
-      return;
-    }
-
-  /* If we couldn't do the "or" simply, do this with a series of compares.  */
-  if (! if_false_label)
-    drop_through_label = if_false_label = gen_label_rtx ();
-
-  for (i = 0; i < nwords; i++)
-    do_compare_rtx_and_jump (operand_subword_force (op0, i, GET_MODE (op0)),
-                            const0_rtx, EQ, 1, word_mode, NULL_RTX,
-                            if_false_label, NULL_RTX);
-
-  if (if_true_label)
-    emit_jump (if_true_label);
-
-  if (drop_through_label)
-    emit_label (drop_through_label);
-}
-\f
-/* Generate code for a comparison of OP0 and OP1 with rtx code CODE.
-   (including code to compute the values to be compared)
-   and set (CC0) according to the result.
-   The decision as to signed or unsigned comparison must be made by the caller.
-
-   We force a stack adjustment unless there are currently
-   things pushed on the stack that aren't yet used.
-
-   If MODE is BLKmode, SIZE is an RTX giving the size of the objects being
-   compared.  */
-
-rtx
-compare_from_rtx (op0, op1, code, unsignedp, mode, size)
-     rtx op0, op1;
-     enum rtx_code code;
-     int unsignedp;
-     enum machine_mode mode;
-     rtx size;
-{
-  enum rtx_code ucode;
-  rtx tem;
-
-  /* If one operand is constant, make it the second one.  Only do this
-     if the other operand is not constant as well.  */
-
-  if (swap_commutative_operands_p (op0, op1))
-    {
-      tem = op0;
-      op0 = op1;
-      op1 = tem;
-      code = swap_condition (code);
-    }
-
-  if (flag_force_mem)
-    {
-      op0 = force_not_mem (op0);
-      op1 = force_not_mem (op1);
-    }
-
-  do_pending_stack_adjust ();
-
-  ucode = unsignedp ? unsigned_condition (code) : code;
-  if ((tem = simplify_relational_operation (ucode, mode, op0, op1)) != 0)
-    return tem;
-
-#if 0
-  /* There's no need to do this now that combine.c can eliminate lots of
-     sign extensions.  This can be less efficient in certain cases on other
-     machines.  */
-
-  /* If this is a signed equality comparison, we can do it as an
-     unsigned comparison since zero-extension is cheaper than sign
-     extension and comparisons with zero are done as unsigned.  This is
-     the case even on machines that can do fast sign extension, since
-     zero-extension is easier to combine with other operations than
-     sign-extension is.  If we are comparing against a constant, we must
-     convert it to what it would look like unsigned.  */
-  if ((code == EQ || code == NE) && ! unsignedp
-      && GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT)
-    {
-      if (GET_CODE (op1) == CONST_INT
-         && (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0))) != INTVAL (op1))
-       op1 = GEN_INT (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0)));
-      unsignedp = 1;
-    }
-#endif
-
-  emit_cmp_insn (op0, op1, code, size, mode, unsignedp);
-
-#if HAVE_cc0
-  return gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);
-#else
-  return gen_rtx_fmt_ee (code, VOIDmode, op0, op1);
-#endif
-}
-
-/* Like do_compare_and_jump but expects the values to compare as two rtx's.
-   The decision as to signed or unsigned comparison must be made by the caller.
-
-   If MODE is BLKmode, SIZE is an RTX giving the size of the objects being
-   compared.  */
-
-void
-do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode, size,
-                        if_false_label, if_true_label)
-     rtx op0, op1;
-     enum rtx_code code;
-     int unsignedp;
-     enum machine_mode mode;
-     rtx size;
-     rtx if_false_label, if_true_label;
-{
-  enum rtx_code ucode;
-  rtx tem;
-  int dummy_true_label = 0;
-
-  /* Reverse the comparison if that is safe and we want to jump if it is
-     false.  */
-  if (! if_true_label && ! FLOAT_MODE_P (mode))
-    {
-      if_true_label = if_false_label;
-      if_false_label = 0;
-      code = reverse_condition (code);
-    }
-
-  /* If one operand is constant, make it the second one.  Only do this
-     if the other operand is not constant as well.  */
-
-  if (swap_commutative_operands_p (op0, op1))
-    {
-      tem = op0;
-      op0 = op1;
-      op1 = tem;
-      code = swap_condition (code);
-    }
-
-  if (flag_force_mem)
-    {
-      op0 = force_not_mem (op0);
-      op1 = force_not_mem (op1);
-    }
-
-  do_pending_stack_adjust ();
-
-  ucode = unsignedp ? unsigned_condition (code) : code;
-  if ((tem = simplify_relational_operation (ucode, mode, op0, op1)) != 0)
-    {
-      if (tem == const_true_rtx)
-       {
-         if (if_true_label)
-           emit_jump (if_true_label);
-       }
-      else
-       {
-         if (if_false_label)
-           emit_jump (if_false_label);
-       }
-      return;
-    }
-
-#if 0
-  /* There's no need to do this now that combine.c can eliminate lots of
-     sign extensions.  This can be less efficient in certain cases on other
-     machines.  */
-
-  /* If this is a signed equality comparison, we can do it as an
-     unsigned comparison since zero-extension is cheaper than sign
-     extension and comparisons with zero are done as unsigned.  This is
-     the case even on machines that can do fast sign extension, since
-     zero-extension is easier to combine with other operations than
-     sign-extension is.  If we are comparing against a constant, we must
-     convert it to what it would look like unsigned.  */
-  if ((code == EQ || code == NE) && ! unsignedp
-      && GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT)
-    {
-      if (GET_CODE (op1) == CONST_INT
-         && (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0))) != INTVAL (op1))
-       op1 = GEN_INT (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0)));
-      unsignedp = 1;
-    }
-#endif
-
-  if (! if_true_label)
-    {
-      dummy_true_label = 1;
-      if_true_label = gen_label_rtx ();
-    }
-
-  emit_cmp_and_jump_insns (op0, op1, code, size, mode, unsignedp,
-                          if_true_label);
-
-  if (if_false_label)
-    emit_jump (if_false_label);
-  if (dummy_true_label)
-    emit_label (if_true_label);
-}
-
-/* Generate code for a comparison expression EXP (including code to compute
-   the values to be compared) and a conditional jump to IF_FALSE_LABEL and/or
-   IF_TRUE_LABEL.  One of the labels can be NULL_RTX, in which case the
-   generated code will drop through.
-   SIGNED_CODE should be the rtx operation for this comparison for
-   signed data; UNSIGNED_CODE, likewise for use if data is unsigned.
-
-   We force a stack adjustment unless there are currently
-   things pushed on the stack that aren't yet used.  */
-
-static void
-do_compare_and_jump (exp, signed_code, unsigned_code, if_false_label,
-                    if_true_label)
-     tree exp;
-     enum rtx_code signed_code, unsigned_code;
-     rtx if_false_label, if_true_label;
-{
-  rtx op0, op1;
-  tree type;
-  enum machine_mode mode;
-  int unsignedp;
-  enum rtx_code code;
-
-  /* Don't crash if the comparison was erroneous.  */
-  op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
-  if (TREE_CODE (TREE_OPERAND (exp, 0)) == ERROR_MARK)
-    return;
-
-  op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
-  if (TREE_CODE (TREE_OPERAND (exp, 1)) == ERROR_MARK)
-    return;
-
-  type = TREE_TYPE (TREE_OPERAND (exp, 0));
-  mode = TYPE_MODE (type);
-  if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST
-      && (TREE_CODE (TREE_OPERAND (exp, 1)) != INTEGER_CST
-         || (GET_MODE_BITSIZE (mode)
-             > GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp,
-                                                                     1)))))))
-    {
-      /* op0 might have been replaced by promoted constant, in which
-        case the type of second argument should be used.  */
-      type = TREE_TYPE (TREE_OPERAND (exp, 1));
-      mode = TYPE_MODE (type);
-    }
-  unsignedp = TREE_UNSIGNED (type);
-  code = unsignedp ? unsigned_code : signed_code;
-
-#ifdef HAVE_canonicalize_funcptr_for_compare
-  /* If function pointers need to be "canonicalized" before they can
-     be reliably compared, then canonicalize them.  */
-  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))))
-         == FUNCTION_TYPE))
-    {
-      rtx new_op0 = gen_reg_rtx (mode);
-
-      emit_insn (gen_canonicalize_funcptr_for_compare (new_op0, op0));
-      op0 = new_op0;
-    }
-
-  if (HAVE_canonicalize_funcptr_for_compare
-      && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 1))) == POINTER_TYPE
-      && (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 1))))
-         == FUNCTION_TYPE))
-    {
-      rtx new_op1 = gen_reg_rtx (mode);
-
-      emit_insn (gen_canonicalize_funcptr_for_compare (new_op1, op1));
-      op1 = new_op1;
-    }
-#endif
-
-  /* Do any postincrements in the expression that was tested.  */
-  emit_queue ();
-
-  do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode,
-                          ((mode == BLKmode)
-                           ? expr_size (TREE_OPERAND (exp, 0)) : NULL_RTX),
-                          if_false_label, if_true_label);
-}
-\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.
 
    If TARGET is nonzero, store the result there if convenient.
 
-   If ONLY_CHEAP is non-zero, only do this if it is likely to be very
+   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
@@ -10918,6 +10246,9 @@ do_tablejump (index, mode, range, table_label, default_label)
 {
   rtx temp, vector;
 
+  if (INTVAL (range) > cfun->max_jumptable_ents)
+    cfun->max_jumptable_ents = INTVAL (range);
+
   /* Do an unsigned comparison (in the proper mode) between the index
      expression and the value which represents the length of the range.
      Since we just finished subtracting the lower bound of the range
@@ -10963,6 +10294,7 @@ do_tablejump (index, mode, range, table_label, default_label)
   temp = gen_reg_rtx (CASE_VECTOR_MODE);
   vector = gen_rtx_MEM (CASE_VECTOR_MODE, index);
   RTX_UNCHANGING_P (vector) = 1;
+  MEM_NOTRAP_P (vector) = 1;
   convert_move (temp, vector, 0);
 
   emit_jump_insn (gen_tablejump (temp, table_label));
@@ -11032,4 +10364,41 @@ vector_mode_valid_p (mode)
   return mov_optab->handlers[innermode].insn_code != CODE_FOR_nothing;
 }
 
+/* Return a CONST_VECTOR rtx for a VECTOR_CST tree.  */
+static rtx
+const_vector_from_tree (exp)
+     tree exp;
+{
+  rtvec v;
+  int units, i;
+  tree link, elt;
+  enum machine_mode inner, mode;
+
+  mode = TYPE_MODE (TREE_TYPE (exp));
+
+  if (is_zeros_p (exp))
+    return CONST0_RTX (mode);
+
+  units = GET_MODE_NUNITS (mode);
+  inner = GET_MODE_INNER (mode);
+
+  v = rtvec_alloc (units);
+
+  link = TREE_VECTOR_CST_ELTS (exp);
+  for (i = 0; link; link = TREE_CHAIN (link), ++i)
+    {
+      elt = TREE_VALUE (link);
+
+      if (TREE_CODE (elt) == REAL_CST)
+       RTVEC_ELT (v, i) = CONST_DOUBLE_FROM_REAL_VALUE (TREE_REAL_CST (elt),
+                                                        inner);
+      else
+       RTVEC_ELT (v, i) = immed_double_const (TREE_INT_CST_LOW (elt),
+                                              TREE_INT_CST_HIGH (elt),
+                                              inner);
+    }
+
+  return gen_rtx_raw_CONST_VECTOR (mode, v);
+}
+
 #include "gt-expr.h"