OSDN Git Service

* longlong.h (umul_ppmm): Add ColdFire support.
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index b9c8fb0..0dd4940 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.  */
@@ -121,60 +125,51 @@ struct store_by_pieces
   int explicit_inc_to;
   unsigned HOST_WIDE_INT len;
   HOST_WIDE_INT offset;
-  rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode));
-  PTR constfundata;
+  rtx (*constfun) (void *, HOST_WIDE_INT, enum machine_mode);
+  void *constfundata;
   int reverse;
 };
 
-static rtx enqueue_insn                PARAMS ((rtx, rtx));
-static unsigned HOST_WIDE_INT move_by_pieces_ninsns
-                               PARAMS ((unsigned HOST_WIDE_INT,
-                                        unsigned int));
-static void move_by_pieces_1   PARAMS ((rtx (*) (rtx, ...), enum machine_mode,
-                                        struct move_by_pieces *));
-static bool block_move_libcall_safe_for_call_parm PARAMS ((void));
-static bool emit_block_move_via_movstr PARAMS ((rtx, rtx, rtx, unsigned));
-static rtx emit_block_move_via_libcall PARAMS ((rtx, rtx, rtx));
-static tree emit_block_move_libcall_fn PARAMS ((int));
-static void emit_block_move_via_loop PARAMS ((rtx, rtx, rtx, unsigned));
-static rtx clear_by_pieces_1   PARAMS ((PTR, HOST_WIDE_INT,
-                                        enum machine_mode));
-static void clear_by_pieces    PARAMS ((rtx, unsigned HOST_WIDE_INT,
-                                        unsigned int));
-static void store_by_pieces_1  PARAMS ((struct store_by_pieces *,
-                                        unsigned int));
-static void store_by_pieces_2  PARAMS ((rtx (*) (rtx, ...),
-                                        enum machine_mode,
-                                        struct store_by_pieces *));
-static bool clear_storage_via_clrstr PARAMS ((rtx, rtx, unsigned));
-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 mostly_zeros_p      PARAMS ((tree));
-static void store_constructor_field PARAMS ((rtx, unsigned HOST_WIDE_INT,
-                                            HOST_WIDE_INT, enum machine_mode,
-                                            tree, tree, int, int));
-static void store_constructor  PARAMS ((tree, rtx, int, HOST_WIDE_INT));
-static rtx store_field         PARAMS ((rtx, HOST_WIDE_INT,
-                                        HOST_WIDE_INT, enum machine_mode,
-                                        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 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));
+static rtx enqueue_insn (rtx, rtx);
+static unsigned HOST_WIDE_INT move_by_pieces_ninsns (unsigned HOST_WIDE_INT,
+                                                    unsigned int);
+static void move_by_pieces_1 (rtx (*) (rtx, ...), enum machine_mode,
+                             struct move_by_pieces *);
+static bool block_move_libcall_safe_for_call_parm (void);
+static bool emit_block_move_via_movstr (rtx, rtx, rtx, unsigned);
+static rtx emit_block_move_via_libcall (rtx, rtx, rtx);
+static tree emit_block_move_libcall_fn (int);
+static void emit_block_move_via_loop (rtx, rtx, rtx, unsigned);
+static rtx clear_by_pieces_1 (void *, HOST_WIDE_INT, enum machine_mode);
+static void clear_by_pieces (rtx, unsigned HOST_WIDE_INT, unsigned int);
+static void store_by_pieces_1 (struct store_by_pieces *, unsigned int);
+static void store_by_pieces_2 (rtx (*) (rtx, ...), enum machine_mode,
+                              struct store_by_pieces *);
+static bool clear_storage_via_clrstr (rtx, rtx, unsigned);
+static rtx clear_storage_via_libcall (rtx, rtx);
+static tree clear_storage_libcall_fn (int);
+static rtx compress_float_constant (rtx, rtx);
+static rtx get_subtarget (rtx);
+static int is_zeros_p (tree);
+static void store_constructor_field (rtx, unsigned HOST_WIDE_INT,
+                                    HOST_WIDE_INT, enum machine_mode,
+                                    tree, tree, int, int);
+static void store_constructor (tree, rtx, int, HOST_WIDE_INT);
+static rtx store_field (rtx, HOST_WIDE_INT, HOST_WIDE_INT, enum machine_mode,
+                       tree, enum machine_mode, int, tree, int);
+static rtx var_rtx (tree);
+
+static unsigned HOST_WIDE_INT highest_pow2_factor (tree);
+static unsigned HOST_WIDE_INT highest_pow2_factor_for_type (tree, tree);
+
+static int is_aligning_offset (tree, tree);
+static rtx expand_increment (tree, int, int);
+static rtx do_store_flag (tree, rtx, enum machine_mode, int);
 #ifdef PUSH_ROUNDING
-static void emit_single_push_insn PARAMS ((enum machine_mode, rtx, tree));
+static void emit_single_push_insn (enum machine_mode, rtx, tree);
 #endif
-static void do_tablejump PARAMS ((rtx, enum machine_mode, rtx, rtx, rtx));
+static void do_tablejump (rtx, enum machine_mode, rtx, rtx, rtx);
+static rtx const_vector_from_tree (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,6 +220,13 @@ 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];
 
@@ -241,7 +243,7 @@ enum insn_code clrstr_optab[NUM_MACHINE_MODES];
    directly in memory and to initialize the block move optab.  */
 
 void
-init_expr_once ()
+init_expr_once (void)
 {
   rtx insn, pat;
   enum machine_mode mode;
@@ -334,9 +336,9 @@ init_expr_once ()
 /* This is run at the start of compiling a function.  */
 
 void
-init_expr ()
+init_expr (void)
 {
-  cfun->expr = (struct expr_status *) ggc_alloc (sizeof (struct expr_status));
+  cfun->expr = ggc_alloc (sizeof (struct expr_status));
 
   pending_chain = 0;
   pending_stack_adjust = 0;
@@ -350,7 +352,7 @@ init_expr ()
 /* Small sanity check that the queue is empty at the end of a function.  */
 
 void
-finish_expr_for_function ()
+finish_expr_for_function (void)
 {
   if (pending_chain)
     abort ();
@@ -367,8 +369,7 @@ finish_expr_for_function ()
    where you want to guarantee the pre-incrementation value of VAR.  */
 
 static rtx
-enqueue_insn (var, body)
-     rtx var, body;
+enqueue_insn (rtx var, rtx body)
 {
   pending_chain = gen_rtx_QUEUED (GET_MODE (var), var, NULL_RTX, NULL_RTX,
                                  body, pending_chain);
@@ -391,9 +392,7 @@ enqueue_insn (var, body)
    If the queue is flushed in between, incorrect code will result.  */
 
 rtx
-protect_from_queue (x, modify)
-     rtx x;
-     int modify;
+protect_from_queue (rtx x, int modify)
 {
   RTX_CODE code = GET_CODE (x);
 
@@ -477,8 +476,7 @@ protect_from_queue (x, modify)
    since memory addresses generally contain only those.  */
 
 int
-queued_subexp_p (x)
-     rtx x;
+queued_subexp_p (rtx x)
 {
   enum rtx_code code = GET_CODE (x);
   switch (code)
@@ -500,7 +498,7 @@ queued_subexp_p (x)
 /* Perform all the pending incrementations.  */
 
 void
-emit_queue ()
+emit_queue (void)
 {
   rtx p;
   while ((p = pending_chain))
@@ -540,9 +538,7 @@ emit_queue ()
    This causes zero-extension instead of sign-extension.  */
 
 void
-convert_move (to, from, unsignedp)
-     rtx to, from;
-     int unsignedp;
+convert_move (rtx to, rtx from, int unsignedp)
 {
   enum machine_mode to_mode = GET_MODE (to);
   enum machine_mode from_mode = GET_MODE (from);
@@ -595,6 +591,13 @@ convert_move (to, from, unsignedp)
       return;
     }
 
+  if (GET_CODE (to) == CONCAT && GET_CODE (from) == CONCAT)
+    {
+      convert_move (XEXP (to, 0), XEXP (from, 0), unsignedp);
+      convert_move (XEXP (to, 1), XEXP (from, 1), unsignedp);
+      return;
+    }
+
   if (to_real != from_real)
     abort ();
 
@@ -1314,10 +1317,7 @@ convert_move (to, from, unsignedp)
    except when putting X into an insn (in which case convert_move does it).  */
 
 rtx
-convert_to_mode (mode, x, unsignedp)
-     enum machine_mode mode;
-     rtx x;
-     int unsignedp;
+convert_to_mode (enum machine_mode mode, rtx x, int unsignedp)
 {
   return convert_modes (mode, VOIDmode, x, unsignedp);
 }
@@ -1336,10 +1336,7 @@ convert_to_mode (mode, x, unsignedp)
    except when putting X into an insn (in which case convert_move does it).  */
 
 rtx
-convert_modes (mode, oldmode, x, unsignedp)
-     enum machine_mode mode, oldmode;
-     rtx x;
-     int unsignedp;
+convert_modes (enum machine_mode mode, enum machine_mode oldmode, rtx x, int unsignedp)
 {
   rtx temp;
 
@@ -1395,6 +1392,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)))))))))
     {
@@ -1425,17 +1424,6 @@ convert_modes (mode, oldmode, x, unsignedp)
   return temp;
 }
 \f
-/* This macro is used to determine what the largest unit size that
-   move_by_pieces can use is.  */
-
-/* MOVE_MAX_PIECES is the number of bytes at a time which we can
-   move efficiently, as opposed to  MOVE_MAX which is the maximum
-   number of bytes we can move with a single instruction.  */
-
-#ifndef MOVE_MAX_PIECES
-#define MOVE_MAX_PIECES   MOVE_MAX
-#endif
-
 /* STORE_MAX_PIECES is the number of bytes at a time that we can
    store efficiently.  Due to internal GCC limitations, this is
    MOVE_MAX_PIECES limited by the number of bytes GCC can represent
@@ -1443,6 +1431,17 @@ convert_modes (mode, oldmode, x, unsignedp)
 
 #define STORE_MAX_PIECES  MIN (MOVE_MAX_PIECES, 2 * sizeof (HOST_WIDE_INT))
 
+/* Determine whether the LEN bytes can be moved by using several move
+   instructions.  Return nonzero if a call to move_by_pieces should
+   succeed.  */
+
+int
+can_move_by_pieces (unsigned HOST_WIDE_INT len,
+                   unsigned int align ATTRIBUTE_UNUSED)
+{
+  return MOVE_BY_PIECES_P (len, align);
+}
+
 /* Generate several move instructions to copy LEN bytes from block FROM to
    block TO.  (These are MEM rtx's with BLKmode).  The caller must pass FROM
    and TO through protect_from_queue before calling.
@@ -1450,13 +1449,15 @@ 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)
-     rtx to, from;
-     unsigned HOST_WIDE_INT len;
-     unsigned int align;
+   If ENDP is 0 return to, if ENDP is 1 return memory at the end ala
+   mempcpy, and if ENDP is 2 return memory the end minus one byte ala
+   stpcpy.  */
+
+rtx
+move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len,
+               unsigned int align, int endp)
 {
   struct move_by_pieces data;
   rtx to_addr, from_addr = XEXP (from, 0);
@@ -1464,6 +1465,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)
@@ -1568,15 +1571,43 @@ move_by_pieces (to, from, len, align)
   /* The code above should have handled everything.  */
   if (data.len > 0)
     abort ();
+
+  if (endp)
+    {
+      rtx to1;
+
+      if (data.reverse)
+       abort ();
+      if (data.autinc_to)
+       {
+         if (endp == 2)
+           {
+             if (HAVE_POST_INCREMENT && data.explicit_inc_to > 0)
+               emit_insn (gen_add2_insn (data.to_addr, constm1_rtx));
+             else
+               data.to_addr = copy_addr_to_reg (plus_constant (data.to_addr,
+                                                               -1));
+           }
+         to1 = adjust_automodify_address (data.to, QImode, data.to_addr,
+                                          data.offset);
+       }
+      else
+       {
+         if (endp == 2)
+           --data.offset;
+         to1 = adjust_address (data.to, QImode, data.offset);
+       }
+      return to1;
+    }
+  else
+    return data.to;
 }
 
 /* Return number of insns required to move L bytes by pieces.
    ALIGN (in bits) is maximum alignment we can assume.  */
 
 static unsigned HOST_WIDE_INT
-move_by_pieces_ninsns (l, align)
-     unsigned HOST_WIDE_INT l;
-     unsigned int align;
+move_by_pieces_ninsns (unsigned HOST_WIDE_INT l, unsigned int align)
 {
   unsigned HOST_WIDE_INT n_insns = 0;
   unsigned HOST_WIDE_INT max_size = MOVE_MAX + 1;
@@ -1615,10 +1646,8 @@ move_by_pieces_ninsns (l, align)
    to make a move insn for that mode.  DATA has all the other info.  */
 
 static void
-move_by_pieces_1 (genfun, mode, data)
-     rtx (*genfun) PARAMS ((rtx, ...));
-     enum machine_mode mode;
-     struct move_by_pieces *data;
+move_by_pieces_1 (rtx (*genfun) (rtx, ...), enum machine_mode mode,
+                 struct move_by_pieces *data)
 {
   unsigned int size = GET_MODE_SIZE (mode);
   rtx to1 = NULL_RTX, from1;
@@ -1686,9 +1715,7 @@ move_by_pieces_1 (genfun, mode, data)
    0 otherwise.  */
 
 rtx
-emit_block_move (x, y, size, method)
-     rtx x, y, size;
-     enum block_op_methods method;
+emit_block_move (rtx x, rtx y, rtx size, enum block_op_methods method)
 {
   bool may_use_call;
   rtx retval = 0;
@@ -1738,6 +1765,9 @@ emit_block_move (x, y, size, method)
      can be incorrect is coming from __builtin_memcpy.  */
   if (GET_CODE (size) == CONST_INT)
     {
+      if (INTVAL (size) == 0)
+       return 0;
+
       x = shallow_copy_rtx (x);
       y = shallow_copy_rtx (y);
       set_mem_size (x, size);
@@ -1745,7 +1775,7 @@ emit_block_move (x, y, size, method)
     }
 
   if (GET_CODE (size) == CONST_INT && MOVE_BY_PIECES_P (INTVAL (size), align))
-    move_by_pieces (x, y, INTVAL (size), align);
+    move_by_pieces (x, y, INTVAL (size), align, 0);
   else if (emit_block_move_via_movstr (x, y, size, align))
     ;
   else if (may_use_call)
@@ -1759,12 +1789,12 @@ emit_block_move (x, y, size, method)
   return retval;
 }
 
-/* A subroutine of emit_block_move.  Returns true if calling the 
+/* A subroutine of emit_block_move.  Returns true if calling the
    block move libcall will not clobber any parameters which may have
    already been placed on the stack.  */
 
 static bool
-block_move_libcall_safe_for_call_parm ()
+block_move_libcall_safe_for_call_parm (void)
 {
   if (PUSH_ARGS)
     return true;
@@ -1818,24 +1848,22 @@ block_move_libcall_safe_for_call_parm ()
     }
 }
 
-/* A subroutine of emit_block_move.  Expand a movstr pattern; 
+/* A subroutine of emit_block_move.  Expand a movstr pattern;
    return true if successful.  */
 
 static bool
-emit_block_move_via_movstr (x, y, size, align)
-     rtx x, y, size;
-     unsigned int align;
+emit_block_move_via_movstr (rtx x, rtx y, rtx size, unsigned int align)
 {
-  /* Try the most limited insn first, because there's no point
-     including more than one in the machine description unless
-     the more limited one has some advantage.  */
-
   rtx opalign = GEN_INT (align / BITS_PER_UNIT);
   enum machine_mode mode;
 
   /* 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))
     {
@@ -1892,41 +1920,50 @@ emit_block_move_via_movstr (x, y, size, align)
    Return the return value from memcpy, 0 otherwise.  */
 
 static rtx
-emit_block_move_via_libcall (dst, src, size)
-     rtx dst, src, size;
+emit_block_move_via_libcall (rtx dst, rtx src, rtx 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));
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+  dst_addr = convert_memory_address (ptr_mode, dst_addr);
+  src_addr = convert_memory_address (ptr_mode, src_addr);
+#endif
 
-  dst = copy_to_mode_reg (Pmode, XEXP (dst, 0));
-  src = copy_to_mode_reg (Pmode, XEXP (src, 0));
+  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);
 
@@ -1938,8 +1975,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
@@ -1966,13 +2001,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
@@ -1981,15 +2020,13 @@ 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 (const char *asmspec)
 {
-  static bool emitted_extern;
-  tree fn = block_move_fn, args;
-
-  if (!fn)
+  if (!block_move_fn)
     {
+      tree args, fn;
+
       if (TARGET_MEM_FUNCTIONS)
        {
          fn = get_identifier ("memcpy");
@@ -2014,14 +2051,29 @@ 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 (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
@@ -2029,9 +2081,8 @@ emit_block_move_libcall_fn (for_call)
 /* ??? It'd be nice to copy in hunks larger than QImode.  */
 
 static void
-emit_block_move_via_loop (x, y, size, align)
-     rtx x, y, size;
-     unsigned int align ATTRIBUTE_UNUSED;
+emit_block_move_via_loop (rtx x, rtx y, rtx size,
+                         unsigned int align ATTRIBUTE_UNUSED)
 {
   rtx cmp_label, top_label, iter, x_addr, y_addr, tmp;
   enum machine_mode iter_mode;
@@ -2050,7 +2101,7 @@ emit_block_move_via_loop (x, y, size, align)
   y_addr = force_operand (XEXP (y, 0), NULL_RTX);
   do_pending_stack_adjust ();
 
-  emit_note (NULL, NOTE_INSN_LOOP_BEG);
+  emit_note (NOTE_INSN_LOOP_BEG);
 
   emit_jump (cmp_label);
   emit_label (top_label);
@@ -2068,24 +2119,20 @@ emit_block_move_via_loop (x, y, size, align)
   if (tmp != iter)
     emit_move_insn (iter, tmp);
 
-  emit_note (NULL, NOTE_INSN_LOOP_CONT);
+  emit_note (NOTE_INSN_LOOP_CONT);
   emit_label (cmp_label);
 
   emit_cmp_and_jump_insns (iter, size, LT, NULL_RTX, iter_mode,
                           true, top_label);
 
-  emit_note (NULL, NOTE_INSN_LOOP_END);
+  emit_note (NOTE_INSN_LOOP_END);
 }
 \f
 /* Copy all or part of a value X into registers starting at REGNO.
    The number of registers to be filled is NREGS.  */
 
 void
-move_block_to_reg (regno, x, nregs, mode)
-     int regno;
-     rtx x;
-     int nregs;
-     enum machine_mode mode;
+move_block_to_reg (int regno, rtx x, int nregs, enum machine_mode mode)
 {
   int i;
 #ifdef HAVE_load_multiple
@@ -2122,64 +2169,23 @@ 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)
-     int regno;
-     rtx x;
-     int nregs;
-     int size;
+move_block_from_reg (int regno, rtx x, int nregs)
 {
   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);
@@ -2201,20 +2207,48 @@ move_block_from_reg (regno, x, nregs, size)
     }
 }
 
-/* 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.  */
-/* ??? If SSIZE % UNITS_PER_WORD != 0, we make the blatant assumption that
-   the balance will be in what would be the low-order memory addresses, i.e.
-   left justified for big endian, right justified for little endian.  This
-   happens to be true for the targets currently using this support.  If this
-   ever changes, a new target macro along the lines of FUNCTION_ARG_PADDING
-   would be needed.  */
+/* 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 (rtx orig)
+{
+  int i, length;
+  rtx *tmps;
+
+  if (GET_CODE (orig) != PARALLEL)
+    abort ();
+
+  length = XVECLEN (orig, 0);
+  tmps = 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 ORIG_SRC of type TYPE to a block DST,
+   where DST is non-consecutive registers represented by a PARALLEL.
+   SSIZE represents the total size of block ORIG_SRC in bytes, or -1
+   if not known.  */ 
 
 void
-emit_group_load (dst, orig_src, ssize)
-     rtx dst, orig_src;
-     int ssize;
+emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
 {
   rtx *tmps, src;
   int start, i;
@@ -2229,7 +2263,7 @@ emit_group_load (dst, orig_src, ssize)
   else
     start = 1;
 
-  tmps = (rtx *) alloca (sizeof (rtx) * XVECLEN (dst, 0));
+  tmps = alloca (sizeof (rtx) * XVECLEN (dst, 0));
 
   /* Process the pieces.  */
   for (i = start; i < XVECLEN (dst, 0); i++)
@@ -2242,7 +2276,17 @@ emit_group_load (dst, orig_src, ssize)
       /* Handle trailing fragments that run over the size of the struct.  */
       if (ssize >= 0 && bytepos + (HOST_WIDE_INT) bytelen > ssize)
        {
-         shift = (bytelen - (ssize - bytepos)) * BITS_PER_UNIT;
+         /* Arrange to shift the fragment to where it belongs.
+            extract_bit_field loads to the lsb of the reg.  */
+         if (
+#ifdef BLOCK_REG_PADDING
+             BLOCK_REG_PADDING (GET_MODE (orig_src), type, i == start)
+             == (BYTES_BIG_ENDIAN ? upward : downward)
+#else
+             BYTES_BIG_ENDIAN
+#endif
+             )
+           shift = (bytelen - (ssize - bytepos)) * BITS_PER_UNIT;
          bytelen = ssize - bytepos;
          if (bytelen <= 0)
            abort ();
@@ -2267,7 +2311,8 @@ emit_group_load (dst, orig_src, ssize)
 
       /* Optimize the access just a bit.  */
       if (GET_CODE (src) == MEM
-         && MEM_ALIGN (src) >= GET_MODE_ALIGNMENT (mode)
+         && (! SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (src))
+             || MEM_ALIGN (src) >= GET_MODE_ALIGNMENT (mode))
          && bytepos * BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
          && bytelen == GET_MODE_SIZE (mode))
        {
@@ -2302,6 +2347,19 @@ emit_group_load (dst, orig_src, ssize)
          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;
@@ -2310,7 +2368,7 @@ emit_group_load (dst, orig_src, ssize)
                                     bytepos * BITS_PER_UNIT, 1, NULL_RTX,
                                     mode, mode, ssize);
 
-      if (BYTES_BIG_ENDIAN && shift)
+      if (shift)
        expand_binop (mode, ashl_optab, tmps[i], GEN_INT (shift),
                      tmps[i], 0, OPTAB_WIDEN);
     }
@@ -2322,14 +2380,32 @@ 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 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.  */
+/* 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 (rtx dst, rtx 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 ORIG_DST of type TYPE,
+   where SRC is non-consecutive registers represented by a PARALLEL.
+   SSIZE represents the total size of block ORIG_DST, or -1 if not
+   known.  */
 
 void
-emit_group_store (orig_dst, src, ssize)
-     rtx orig_dst, src;
-     int ssize;
+emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
 {
   rtx *tmps, dst;
   int start, i;
@@ -2344,7 +2420,7 @@ emit_group_store (orig_dst, src, ssize)
   else
     start = 1;
 
-  tmps = (rtx *) alloca (sizeof (rtx) * XVECLEN (src, 0));
+  tmps = alloca (sizeof (rtx) * XVECLEN (src, 0));
 
   /* Copy the (probable) hard regs into pseudos.  */
   for (i = start; i < XVECLEN (src, 0); i++)
@@ -2373,15 +2449,15 @@ emit_group_store (orig_dst, src, ssize)
         the temporary.  */
 
       temp = assign_stack_temp (GET_MODE (dst), ssize, 0);
-      emit_group_store (temp, src, ssize);
-      emit_group_load (dst, temp, ssize);
+      emit_group_store (temp, src, type, ssize);
+      emit_group_load (dst, temp, type, ssize);
       return;
     }
   else if (GET_CODE (dst) != MEM && GET_CODE (dst) != CONCAT)
     {
       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.  */
@@ -2395,7 +2471,16 @@ emit_group_store (orig_dst, src, ssize)
       /* Handle trailing fragments that run over the size of the struct.  */
       if (ssize >= 0 && bytepos + (HOST_WIDE_INT) bytelen > ssize)
        {
-         if (BYTES_BIG_ENDIAN)
+         /* store_bit_field always takes its value from the lsb.
+            Move the fragment to the lsb if it's not already there.  */
+         if (
+#ifdef BLOCK_REG_PADDING
+             BLOCK_REG_PADDING (GET_MODE (orig_dst), type, i == start)
+             == (BYTES_BIG_ENDIAN ? upward : downward)
+#else
+             BYTES_BIG_ENDIAN
+#endif
+             )
            {
              int shift = (bytelen - (ssize - bytepos)) * BITS_PER_UNIT;
              expand_binop (mode, ashr_optab, tmps[i], GEN_INT (shift),
@@ -2413,13 +2498,23 @@ 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 ();
        }
 
       /* Optimize the access just a bit.  */
       if (GET_CODE (dest) == MEM
-         && MEM_ALIGN (dest) >= GET_MODE_ALIGNMENT (mode)
+         && (! SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (dest))
+             || MEM_ALIGN (dest) >= GET_MODE_ALIGNMENT (mode))
          && bytepos * BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
          && bytelen == GET_MODE_SIZE (mode))
        emit_move_insn (adjust_address (dest, mode, bytepos), tmps[i]);
@@ -2431,7 +2526,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);
 }
 
@@ -2445,10 +2540,7 @@ emit_group_store (orig_dst, src, ssize)
    in registers regardless of the structure's alignment.  */
 
 rtx
-copy_blkmode_from_reg (tgtblk, srcreg, type)
-     rtx tgtblk;
-     rtx srcreg;
-     tree type;
+copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
 {
   unsigned HOST_WIDE_INT bytes = int_size_in_bytes (type);
   rtx src = NULL, dst = NULL;
@@ -2465,26 +2557,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));
@@ -2528,8 +2611,7 @@ copy_blkmode_from_reg (tgtblk, srcreg, type)
    to by CALL_FUSAGE.  REG must denote a hard register.  */
 
 void
-use_reg (call_fusage, reg)
-     rtx *call_fusage, reg;
+use_reg (rtx *call_fusage, rtx reg)
 {
   if (GET_CODE (reg) != REG
       || REGNO (reg) >= FIRST_PSEUDO_REGISTER)
@@ -2544,10 +2626,7 @@ use_reg (call_fusage, reg)
    starting at REGNO.  All of these registers must be hard registers.  */
 
 void
-use_regs (call_fusage, regno, nregs)
-     rtx *call_fusage;
-     int regno;
-     int nregs;
+use_regs (rtx *call_fusage, int regno, int nregs)
 {
   int i;
 
@@ -2563,9 +2642,7 @@ use_regs (call_fusage, regno, nregs)
    non-contiguous locations.  The Irix 6 ABI has examples of this.  */
 
 void
-use_group_regs (call_fusage, regs)
-     rtx *call_fusage;
-     rtx regs;
+use_group_regs (rtx *call_fusage, rtx regs)
 {
   int i;
 
@@ -2589,11 +2666,9 @@ use_group_regs (call_fusage, regs)
    call to store_by_pieces should succeed.  */
 
 int
-can_store_by_pieces (len, constfun, constfundata, align)
-     unsigned HOST_WIDE_INT len;
-     rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode));
-     PTR constfundata;
-     unsigned int align;
+can_store_by_pieces (unsigned HOST_WIDE_INT len,
+                    rtx (*constfun) (void *, HOST_WIDE_INT, enum machine_mode),
+                    void *constfundata, unsigned int align)
 {
   unsigned HOST_WIDE_INT max_size, l;
   HOST_WIDE_INT offset = 0;
@@ -2602,7 +2677,10 @@ can_store_by_pieces (len, constfun, constfundata, align)
   int reverse;
   rtx cst;
 
-  if (! MOVE_BY_PIECES_P (len, align))
+  if (len == 0)
+    return 1;
+
+  if (! STORE_BY_PIECES_P (len, align))
     return 0;
 
   if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
@@ -2665,19 +2743,26 @@ can_store_by_pieces (len, constfun, constfundata, align)
 /* Generate several move instructions to store LEN bytes generated by
    CONSTFUN to block TO.  (A MEM rtx with BLKmode).  CONSTFUNDATA is a
    pointer which will be passed as argument in every CONSTFUN call.
-   ALIGN is maximum alignment we can assume.  */
+   ALIGN is maximum alignment we can assume.
+   If ENDP is 0 return to, if ENDP is 1 return memory at the end ala
+   mempcpy, and if ENDP is 2 return memory the end minus one byte ala
+   stpcpy.  */
 
-void
-store_by_pieces (to, len, constfun, constfundata, align)
-     rtx to;
-     unsigned HOST_WIDE_INT len;
-     rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode));
-     PTR constfundata;
-     unsigned int align;
+rtx
+store_by_pieces (rtx to, unsigned HOST_WIDE_INT len,
+                rtx (*constfun) (void *, HOST_WIDE_INT, enum machine_mode),
+                void *constfundata, unsigned int align, int endp)
 {
   struct store_by_pieces data;
 
-  if (! MOVE_BY_PIECES_P (len, align))
+  if (len == 0)
+    {
+      if (endp == 2)
+       abort ();
+      return to;
+    }
+
+  if (! STORE_BY_PIECES_P (len, align))
     abort ();
   to = protect_from_queue (to, 1);
   data.constfun = constfun;
@@ -2685,6 +2770,35 @@ store_by_pieces (to, len, constfun, constfundata, align)
   data.len = len;
   data.to = to;
   store_by_pieces_1 (&data, align);
+  if (endp)
+    {
+      rtx to1;
+
+      if (data.reverse)
+       abort ();
+      if (data.autinc_to)
+       {
+         if (endp == 2)
+           {
+             if (HAVE_POST_INCREMENT && data.explicit_inc_to > 0)
+               emit_insn (gen_add2_insn (data.to_addr, constm1_rtx));
+             else
+               data.to_addr = copy_addr_to_reg (plus_constant (data.to_addr,
+                                                               -1));
+           }
+         to1 = adjust_automodify_address (data.to, QImode, data.to_addr,
+                                          data.offset);
+       }
+      else
+       {
+         if (endp == 2)
+           --data.offset;
+         to1 = adjust_address (data.to, QImode, data.offset);
+       }
+      return to1;
+    }
+  else
+    return data.to;
 }
 
 /* Generate several move instructions to clear LEN bytes of block TO.  (A MEM
@@ -2692,13 +2806,13 @@ store_by_pieces (to, len, constfun, constfundata, align)
    before calling. ALIGN is maximum alignment we can assume.  */
 
 static void
-clear_by_pieces (to, len, align)
-     rtx to;
-     unsigned HOST_WIDE_INT len;
-     unsigned int align;
+clear_by_pieces (rtx to, unsigned HOST_WIDE_INT len, unsigned int align)
 {
   struct store_by_pieces data;
 
+  if (len == 0)
+    return;
+
   data.constfun = clear_by_pieces_1;
   data.constfundata = NULL;
   data.len = len;
@@ -2710,10 +2824,9 @@ clear_by_pieces (to, len, align)
    Return const0_rtx unconditionally.  */
 
 static rtx
-clear_by_pieces_1 (data, offset, mode)
-     PTR data ATTRIBUTE_UNUSED;
-     HOST_WIDE_INT offset ATTRIBUTE_UNUSED;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+clear_by_pieces_1 (void *data ATTRIBUTE_UNUSED,
+                  HOST_WIDE_INT offset ATTRIBUTE_UNUSED,
+                  enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   return const0_rtx;
 }
@@ -2724,9 +2837,8 @@ clear_by_pieces_1 (data, offset, mode)
    before calling.  ALIGN is maximum alignment we can assume.  */
 
 static void
-store_by_pieces_1 (data, align)
-     struct store_by_pieces *data;
-     unsigned int align;
+store_by_pieces_1 (struct store_by_pieces *data ATTRIBUTE_UNUSED,
+                  unsigned int align ATTRIBUTE_UNUSED)
 {
   rtx to_addr = XEXP (data->to, 0);
   unsigned HOST_WIDE_INT max_size = STORE_MAX_PIECES + 1;
@@ -2810,10 +2922,8 @@ store_by_pieces_1 (data, align)
    to make a move insn for that mode.  DATA has all the other info.  */
 
 static void
-store_by_pieces_2 (genfun, mode, data)
-     rtx (*genfun) PARAMS ((rtx, ...));
-     enum machine_mode mode;
-     struct store_by_pieces *data;
+store_by_pieces_2 (rtx (*genfun) (rtx, ...), enum machine_mode mode,
+                  struct store_by_pieces *data)
 {
   unsigned int size = GET_MODE_SIZE (mode);
   rtx to1, cst;
@@ -2850,9 +2960,7 @@ store_by_pieces_2 (genfun, mode, data)
    its length in bytes.  */
 
 rtx
-clear_storage (object, size)
-     rtx object;
-     rtx size;
+clear_storage (rtx object, rtx size)
 {
   rtx retval = 0;
   unsigned int align = (GET_CODE (object) == MEM ? MEM_ALIGN (object)
@@ -2869,7 +2977,9 @@ clear_storage (object, size)
       object = protect_from_queue (object, 1);
       size = protect_from_queue (size, 0);
 
-      if (GET_CODE (size) == CONST_INT
+      if (size == const0_rtx)
+       ;
+      else if (GET_CODE (size) == CONST_INT
          && CLEAR_BY_PIECES_P (INTVAL (size), align))
        clear_by_pieces (object, INTVAL (size), align);
       else if (clear_storage_via_clrstr (object, size, align))
@@ -2885,9 +2995,7 @@ clear_storage (object, size)
    return true if successful.  */
 
 static bool
-clear_storage_via_clrstr (object, size, align)
-     rtx object, size;
-     unsigned int align;
+clear_storage_via_clrstr (rtx object, rtx size, unsigned int align)
 {
   /* Try the most limited insn first, because there's no point
      including more than one in the machine description unless
@@ -2943,8 +3051,7 @@ clear_storage_via_clrstr (object, size, align)
    Return the return value of memset, 0 otherwise.  */
 
 static rtx
-clear_storage_via_libcall (object, size)
-     rtx object, size;
+clear_storage_via_libcall (rtx object, rtx size)
 {
   tree call_expr, arg_list, fn, object_tree, size_tree;
   enum machine_mode size_mode;
@@ -3023,15 +3130,13 @@ 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 (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");
@@ -3055,14 +3160,29 @@ 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 (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.
@@ -3073,12 +3193,11 @@ clear_storage_libcall_fn (for_call)
    Return the last instruction emitted.  */
 
 rtx
-emit_move_insn (x, y)
-     rtx x, y;
+emit_move_insn (rtx x, rtx y)
 {
   enum machine_mode mode = GET_MODE (x);
   rtx y_cst = NULL_RTX;
-  rtx last_insn;
+  rtx last_insn, set;
 
   x = protect_from_queue (x, 1);
   y = protect_from_queue (y, 0);
@@ -3092,14 +3211,21 @@ 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;
 
+      y_cst = y;
+
       if (!LEGITIMATE_CONSTANT_P (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;
        }
     }
 
@@ -3123,7 +3249,10 @@ emit_move_insn (x, y)
 
   last_insn = emit_move_insn_1 (x, y);
 
-  if (y_cst && GET_CODE (x) == REG)
+  if (y_cst && GET_CODE (x) == REG
+      && (set = single_set (last_insn)) != NULL_RTX
+      && SET_DEST (set) == x
+      && ! rtx_equal_p (y_cst, SET_SRC (set)))
     set_unique_reg_note (last_insn, REG_EQUAL, y_cst);
 
   return last_insn;
@@ -3134,8 +3263,7 @@ emit_move_insn (x, y)
    are basically valid.  */
 
 rtx
-emit_move_insn_1 (x, y)
-     rtx x, y;
+emit_move_insn_1 (rtx x, rtx y)
 {
   enum machine_mode mode = GET_MODE (x);
   enum machine_mode submode;
@@ -3150,11 +3278,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))
     {
@@ -3162,8 +3286,8 @@ emit_move_insn_1 (x, y)
       int stack = push_operand (x, GET_MODE (x));
 
 #ifdef PUSH_ROUNDING
-      /* In case we output to the stack, but the size is smaller machine can
-        push exactly, we need to use move instructions.  */
+      /* In case we output to the stack, but the size is smaller than the
+        machine can push exactly, we need to use move instructions.  */
       if (stack
          && (PUSH_ROUNDING (GET_MODE_SIZE (submode))
              != GET_MODE_SIZE (submode)))
@@ -3220,19 +3344,15 @@ emit_move_insn_1 (x, y)
          /* Note that the real part always precedes the imag part in memory
             regardless of machine's endianness.  */
 #ifdef STACK_GROWS_DOWNWARD
-         emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
-                    (gen_rtx_MEM (submode, XEXP (x, 0)),
-                     gen_imagpart (submode, y)));
-         emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
-                    (gen_rtx_MEM (submode, XEXP (x, 0)),
-                     gen_realpart (submode, y)));
+         emit_move_insn (gen_rtx_MEM (submode, XEXP (x, 0)),
+                         gen_imagpart (submode, y));
+         emit_move_insn (gen_rtx_MEM (submode, XEXP (x, 0)),
+                         gen_realpart (submode, y));
 #else
-         emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
-                    (gen_rtx_MEM (submode, XEXP (x, 0)),
-                     gen_realpart (submode, y)));
-         emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
-                    (gen_rtx_MEM (submode, XEXP (x, 0)),
-                     gen_imagpart (submode, y)));
+         emit_move_insn (gen_rtx_MEM (submode, XEXP (x, 0)),
+                         gen_realpart (submode, y));
+         emit_move_insn (gen_rtx_MEM (submode, XEXP (x, 0)),
+                         gen_imagpart (submode, y));
 #endif
        }
       else
@@ -3307,15 +3427,68 @@ emit_move_insn_1 (x, y)
                  || GET_CODE (imagpart_x) == SUBREG))
            emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
 
-         emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
-                    (realpart_x, realpart_y));
-         emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
-                    (imagpart_x, imagpart_y));
+         emit_move_insn (realpart_x, realpart_y);
+         emit_move_insn (imagpart_x, imagpart_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.  */
@@ -3432,8 +3605,7 @@ emit_move_insn_1 (x, y)
    move as an extension.  */
 
 static rtx
-compress_float_constant (x, y)
-     rtx x, y;
+compress_float_constant (rtx x, rtx y)
 {
   enum machine_mode dstmode = GET_MODE (x);
   enum machine_mode orig_srcmode = GET_MODE (y);
@@ -3476,8 +3648,7 @@ compress_float_constant (x, y)
       last_insn = get_last_insn ();
 
       if (GET_CODE (x) == REG)
-       REG_NOTES (last_insn)
-         = gen_rtx_EXPR_LIST (REG_EQUAL, y, REG_NOTES (last_insn));
+       set_unique_reg_note (last_insn, REG_EQUAL, y);
 
       return last_insn;
     }
@@ -3497,9 +3668,7 @@ compress_float_constant (x, y)
    otherwise, the padding comes at high addresses.  */
 
 rtx
-push_block (size, extra, below)
-     rtx size;
-     int extra, below;
+push_block (rtx size, int extra, int below)
 {
   rtx temp;
 
@@ -3548,10 +3717,7 @@ push_block (size, extra, below)
 /* Emit single push insn.  */
 
 static void
-emit_single_push_insn (mode, x, type)
-     rtx x;
-     enum machine_mode mode;
-     tree type;
+emit_single_push_insn (enum machine_mode mode, rtx x, tree type)
 {
   rtx dest_addr;
   unsigned rounded_size = PUSH_ROUNDING (GET_MODE_SIZE (mode));
@@ -3573,12 +3739,48 @@ emit_single_push_insn (mode, x, type)
     }
   if (GET_MODE_SIZE (mode) == rounded_size)
     dest_addr = gen_rtx_fmt_e (STACK_PUSH_CODE, Pmode, stack_pointer_rtx);
+  /* If we are to pad downward, adjust the stack pointer first and
+     then store X into the stack location using an offset.  This is
+     because emit_move_insn does not know how to pad; it does not have
+     access to type.  */
+  else if (FUNCTION_ARG_PADDING (mode, type) == downward)
+    {
+      unsigned padding_size = rounded_size - GET_MODE_SIZE (mode);
+      HOST_WIDE_INT offset;
+
+      emit_move_insn (stack_pointer_rtx,
+                     expand_binop (Pmode,
+#ifdef STACK_GROWS_DOWNWARD
+                                   sub_optab,
+#else
+                                   add_optab,
+#endif
+                                   stack_pointer_rtx,
+                                   GEN_INT (rounded_size),
+                                   NULL_RTX, 0, OPTAB_LIB_WIDEN));
+
+      offset = (HOST_WIDE_INT) padding_size;
+#ifdef STACK_GROWS_DOWNWARD
+      if (STACK_PUSH_CODE == POST_DEC)
+       /* We have already decremented the stack pointer, so get the
+          previous value.  */
+       offset += (HOST_WIDE_INT) rounded_size;
+#else
+      if (STACK_PUSH_CODE == POST_INC)
+       /* We have already incremented the stack pointer, so get the
+          previous value.  */
+       offset -= (HOST_WIDE_INT) rounded_size;
+#endif
+      dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset));
+    }
   else
     {
 #ifdef STACK_GROWS_DOWNWARD
+      /* ??? This seems wrong if STACK_PUSH_CODE == POST_DEC.  */
       dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
                                GEN_INT (-(HOST_WIDE_INT) rounded_size));
 #else
+      /* ??? This seems wrong if STACK_PUSH_CODE == POST_INC.  */
       dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
                                GEN_INT (rounded_size));
 #endif
@@ -3635,21 +3837,10 @@ emit_single_push_insn (mode, x, type)
    of bytes required.  */
 
 void
-emit_push_insn (x, mode, type, size, align, partial, reg, extra,
-               args_addr, args_so_far, reg_parm_stack_space,
-               alignment_pad)
-     rtx x;
-     enum machine_mode mode;
-     tree type;
-     rtx size;
-     unsigned int align;
-     int partial;
-     rtx reg;
-     int extra;
-     rtx args_addr;
-     rtx args_so_far;
-     int reg_parm_stack_space;
-     rtx alignment_pad;
+emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
+               unsigned int align, int partial, rtx reg, int extra,
+               rtx args_addr, rtx args_so_far, int reg_parm_stack_space,
+               rtx alignment_pad)
 {
   rtx xinner;
   enum direction stack_direction
@@ -3706,6 +3897,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,
@@ -3723,7 +3915,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
              && where_pad != none && where_pad != stack_direction)
            anti_adjust_stack (GEN_INT (extra));
 
-         move_by_pieces (NULL, xinner, INTVAL (size) - used, align);
+         move_by_pieces (NULL, xinner, INTVAL (size) - used, align, 0);
        }
       else
 #endif /* PUSH_ROUNDING  */
@@ -3857,7 +4049,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,
@@ -3881,7 +4072,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)
            {
@@ -3905,7 +4095,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
       /* Handle calls that pass values in multiple non-contiguous locations.
         The Irix 6 ABI has examples of this.  */
       if (GET_CODE (reg) == PARALLEL)
-       emit_group_load (reg, x, -1);  /* ??? size? */
+       emit_group_load (reg, x, type, -1);
       else
        move_block_to_reg (REGNO (reg), x, partial, mode);
     }
@@ -3921,8 +4111,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
    operations.  */
 
 static rtx
-get_subtarget (x)
-     rtx x;
+get_subtarget (rtx x)
 {
   return ((x == 0
           /* Only registers can be subtargets.  */
@@ -3941,18 +4130,10 @@ get_subtarget (x)
    If WANT_VALUE is nonzero, return an rtx for the value of TO.
    (This may contain a QUEUED rtx;
    if the value is constant, this rtx is a constant.)
-   Otherwise, the returned value is NULL_RTX.
-
-   SUGGEST_REG is no longer actually used.
-   It used to mean, copy the value through a register
-   and return that register, if that is possible.
-   We now use WANT_VALUE to decide whether to do this.  */
+   Otherwise, the returned value is NULL_RTX.  */
 
 rtx
-expand_assignment (to, from, want_value, suggest_reg)
-     tree to, from;
-     int want_value;
-     int suggest_reg ATTRIBUTE_UNUSED;
+expand_assignment (tree to, tree from, int want_value)
 {
   rtx to_rtx = 0;
   rtx result;
@@ -3972,7 +4153,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;
@@ -4003,7 +4185,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);
@@ -4107,7 +4289,8 @@ expand_assignment (to, from, want_value, suggest_reg)
       /* Handle calls that return values in multiple non-contiguous locations.
         The Irix 6 ABI has examples of this.  */
       if (GET_CODE (to_rtx) == PARALLEL)
-       emit_group_load (to_rtx, value, int_size_in_bytes (TREE_TYPE (from)));
+       emit_group_load (to_rtx, value, TREE_TYPE (from),
+                        int_size_in_bytes (TREE_TYPE (from)));
       else if (GET_MODE (to_rtx) == BLKmode)
        emit_block_move (to_rtx, value, expr_size (from), BLOCK_OP_NORMAL);
       else
@@ -4141,7 +4324,8 @@ expand_assignment (to, from, want_value, suggest_reg)
       temp = expand_expr (from, 0, GET_MODE (to_rtx), 0);
 
       if (GET_CODE (to_rtx) == PARALLEL)
-       emit_group_load (to_rtx, temp, int_size_in_bytes (TREE_TYPE (from)));
+       emit_group_load (to_rtx, temp, TREE_TYPE (from),
+                        int_size_in_bytes (TREE_TYPE (from)));
       else
        emit_move_insn (to_rtx, temp);
 
@@ -4200,7 +4384,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
@@ -4215,25 +4399,36 @@ 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)
-     tree exp;
-     rtx target;
-     int want_value;
+store_expr (tree exp, rtx target, int want_value)
 {
   rtx temp;
   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 nonexistent 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);
     }
@@ -4253,20 +4448,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
@@ -4276,18 +4471,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,
@@ -4296,7 +4497,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
@@ -4310,7 +4512,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.  */
@@ -4323,7 +4525,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))
@@ -4340,14 +4543,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
@@ -4368,7 +4572,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)
            {
@@ -4383,11 +4587,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.
@@ -4399,7 +4604,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;
     }
 
@@ -4470,7 +4675,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.  */
@@ -4478,13 +4685,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.  */
@@ -4502,8 +4714,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,
@@ -4523,15 +4735,18 @@ store_expr (exp, target, want_value)
       /* Handle calls that return values in multiple non-contiguous locations.
         The Irix 6 ABI has examples of this.  */
       else if (GET_CODE (target) == PARALLEL)
-       emit_group_load (target, temp, int_size_in_bytes (TREE_TYPE (exp)));
+       emit_group_load (target, temp, TREE_TYPE (exp),
+                        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.
@@ -4540,7 +4755,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);
@@ -4549,11 +4765,10 @@ store_expr (exp, target, want_value)
     return target;
 }
 \f
-/* Return 1 if EXP just contains zeros.  */
+/* Return 1 if EXP just contains zeros.  FIXME merge with initializer_zerop.  */
 
 static int
-is_zeros_p (exp)
-     tree exp;
+is_zeros_p (tree exp)
 {
   tree elt;
 
@@ -4599,9 +4814,8 @@ is_zeros_p (exp)
 
 /* Return 1 if EXP contains mostly (3/4)  zeros.  */
 
-static int
-mostly_zeros_p (exp)
-     tree exp;
+int
+mostly_zeros_p (tree exp)
 {
   if (TREE_CODE (exp) == CONSTRUCTOR)
     {
@@ -4642,15 +4856,9 @@ mostly_zeros_p (exp)
    clear a substructure if the outer structure has already been cleared.  */
 
 static void
-store_constructor_field (target, bitsize, bitpos, mode, exp, type, cleared,
-                        alias_set)
-     rtx target;
-     unsigned HOST_WIDE_INT bitsize;
-     HOST_WIDE_INT bitpos;
-     enum machine_mode mode;
-     tree exp, type;
-     int cleared;
-     int alias_set;
+store_constructor_field (rtx target, unsigned HOST_WIDE_INT bitsize,
+                        HOST_WIDE_INT bitpos, enum machine_mode mode,
+                        tree exp, tree type, int cleared, int alias_set)
 {
   if (TREE_CODE (exp) == CONSTRUCTOR
       && bitpos % BITS_PER_UNIT == 0
@@ -4692,11 +4900,7 @@ store_constructor_field (target, bitsize, bitpos, mode, exp, type, cleared,
    which has been packed to exclude padding bits.  */
 
 static void
-store_constructor (exp, target, cleared, size)
-     tree exp;
-     rtx target;
-     int cleared;
-     HOST_WIDE_INT size;
+store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
 {
   tree type = TREE_TYPE (exp);
 #ifdef WORD_REGISTER_OPERATIONS
@@ -4708,11 +4912,13 @@ store_constructor (exp, target, cleared, size)
     {
       tree elt;
 
+      /* If size is zero or the target is already cleared, do nothing.  */
+      if (size == 0 || cleared)
+       cleared = 1;
       /* We either clear the aggregate or indicate the value is dead.  */
-      if ((TREE_CODE (type) == UNION_TYPE
-          || TREE_CODE (type) == QUAL_UNION_TYPE)
-         && ! cleared
-         && ! CONSTRUCTOR_ELTS (exp))
+      else if ((TREE_CODE (type) == UNION_TYPE
+               || TREE_CODE (type) == QUAL_UNION_TYPE)
+              && ! CONSTRUCTOR_ELTS (exp))
        /* If the constructor is empty, clear the union.  */
        {
          clear_storage (target, expr_size (exp));
@@ -4723,7 +4929,7 @@ store_constructor (exp, target, cleared, size)
         set the initial value as zero so we can fold the value into
         a constant.  But if more than one register is involved,
         this probably loses.  */
-      else if (! cleared && GET_CODE (target) == REG && TREE_STATIC (exp)
+      else if (GET_CODE (target) == REG && TREE_STATIC (exp)
               && GET_MODE_SIZE (GET_MODE (target)) <= UNITS_PER_WORD)
        {
          emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
@@ -4735,15 +4941,21 @@ store_constructor (exp, target, cleared, size)
         clear the whole structure first.  Don't do this if TARGET is a
         register whose mode size isn't equal to SIZE since clear_storage
         can't handle this case.  */
-      else if (! cleared && size > 0
-              && ((list_length (CONSTRUCTOR_ELTS (exp))
-                   != fields_length (type))
-                  || mostly_zeros_p (exp))
+      else if (((list_length (CONSTRUCTOR_ELTS (exp)) != fields_length (type))
+               || mostly_zeros_p (exp))
               && (GET_CODE (target) != REG
                   || ((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;
        }
 
@@ -4760,7 +4972,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;
 
@@ -4778,7 +4989,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;
@@ -4797,7 +5007,7 @@ store_constructor (exp, target, cleared, size)
            {
              rtx offset_rtx;
 
-             if (contains_placeholder_p (offset))
+             if (CONTAINS_PLACEHOLDER_P (offset))
                offset = build (WITH_RECORD_EXPR, sizetype,
                                offset, make_tree (TREE_TYPE (exp), target));
 
@@ -4807,7 +5017,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);
@@ -4999,7 +5209,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;
@@ -5038,8 +5248,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);
@@ -5178,7 +5387,7 @@ store_constructor (exp, target, cleared, size)
        {
          unsigned int set_word_size = TYPE_ALIGN (TREE_TYPE (exp));
          enum machine_mode mode = mode_for_size (set_word_size, MODE_INT, 1);
-         char *bit_buffer = (char *) alloca (nbits);
+         char *bit_buffer = alloca (nbits);
          HOST_WIDE_INT word = 0;
          unsigned int bit_pos = 0;
          unsigned int ibit = 0;
@@ -5300,8 +5509,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));
@@ -5334,17 +5543,9 @@ store_constructor (exp, target, cleared, size)
    reference to the containing structure.  */
 
 static rtx
-store_field (target, bitsize, bitpos, mode, exp, value_mode, unsignedp, type,
-            alias_set)
-     rtx target;
-     HOST_WIDE_INT bitsize;
-     HOST_WIDE_INT bitpos;
-     enum machine_mode mode;
-     tree exp;
-     enum machine_mode value_mode;
-     int unsignedp;
-     tree type;
-     int alias_set;
+store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
+            enum machine_mode mode, tree exp, enum machine_mode value_mode,
+            int unsignedp, tree type, int alias_set)
 {
   HOST_WIDE_INT width_mask = 0;
 
@@ -5355,7 +5556,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
@@ -5367,15 +5568,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)))
@@ -5411,9 +5610,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.  */
@@ -5433,7 +5634,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.  */
@@ -5548,15 +5749,10 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode, unsignedp, type,
    this case, but the address of the object can be found.  */
 
 tree
-get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
-                    punsignedp, pvolatilep)
-     tree exp;
-     HOST_WIDE_INT *pbitsize;
-     HOST_WIDE_INT *pbitpos;
-     tree *poffset;
-     enum machine_mode *pmode;
-     int *punsignedp;
-     int *pvolatilep;
+get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
+                    HOST_WIDE_INT *pbitpos, tree *poffset,
+                    enum machine_mode *pmode, int *punsignedp,
+                    int *pvolatilep)
 {
   tree size_tree = 0;
   enum machine_mode mode = VOIDmode;
@@ -5615,8 +5811,7 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
             made during type construction.  */
          if (this_offset == 0)
            break;
-         else if (! TREE_CONSTANT (this_offset)
-                  && contains_placeholder_p (this_offset))
+         else if (CONTAINS_PLACEHOLDER_P (this_offset))
            this_offset = build (WITH_RECORD_EXPR, sizetype, this_offset, exp);
 
          offset = size_binop (PLUS_EXPR, offset, this_offset);
@@ -5646,11 +5841,9 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
          /* If the index has a self-referential type, pass it to a
             WITH_RECORD_EXPR; if the component size is, pass our
             component to one.  */
-         if (! TREE_CONSTANT (index)
-             && contains_placeholder_p (index))
+         if (CONTAINS_PLACEHOLDER_P (index))
            index = build (WITH_RECORD_EXPR, TREE_TYPE (index), index, exp);
-         if (! TREE_CONSTANT (unit_size)
-             && contains_placeholder_p (unit_size))
+         if (CONTAINS_PLACEHOLDER_P (unit_size))
            unit_size = build (WITH_RECORD_EXPR, sizetype, unit_size, array);
 
          offset = size_binop (PLUS_EXPR, offset,
@@ -5673,8 +5866,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))
@@ -5706,8 +5911,7 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
 /* Return 1 if T is an expression that get_inner_reference handles.  */
 
 int
-handled_component_p (t)
-     tree t;
+handled_component_p (tree t)
 {
   switch (TREE_CODE (t))
     {
@@ -5719,6 +5923,9 @@ handled_component_p (t)
     case VIEW_CONVERT_EXPR:
       return 1;
 
+    /* ??? Sure they are handled, but get_inner_reference may return
+       a different PBITSIZE, depending upon whether the expression is
+       wrapped up in a NOP_EXPR or not, e.g. for bitfields.  */
     case NOP_EXPR:
     case CONVERT_EXPR:
       return (TYPE_MODE (TREE_TYPE (t))
@@ -5737,8 +5944,7 @@ handled_component_p (t)
    The returned value may be a REG, SUBREG, MEM or constant.  */
 
 rtx
-force_operand (value, target)
-     rtx value, target;
+force_operand (rtx value, rtx target)
 {
   rtx op1, op2;
   /* Use subtarget as the target for operand 0 of a binary operation.  */
@@ -5869,10 +6075,7 @@ force_operand (value, target)
    searches for optimization opportunities.  */
 
 int
-safe_from_p (x, exp, top_p)
-     rtx x;
-     tree exp;
-     int top_p;
+safe_from_p (rtx x, tree exp, int top_p)
 {
   rtx exp_rtl = 0;
   int i, nops;
@@ -5944,22 +6147,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':
@@ -6050,10 +6262,6 @@ safe_from_p (x, exp, top_p)
             part of the expression.  */
          return safe_from_p (x, TREE_OPERAND (exp, 1), 0);
 
-       case METHOD_CALL_EXPR:
-         /* This takes an rtx argument, but shouldn't appear here.  */
-         abort ();
-
        default:
          break;
        }
@@ -6104,8 +6312,7 @@ safe_from_p (x, exp, top_p)
    variable or parameter; else return 0.  */
 
 static rtx
-var_rtx (exp)
-     tree exp;
+var_rtx (tree exp)
 {
   STRIP_NOPS (exp);
   switch (TREE_CODE (exp))
@@ -6121,8 +6328,7 @@ var_rtx (exp)
 #ifdef MAX_INTEGER_COMPUTATION_MODE
 
 void
-check_max_integer_computation_mode (exp)
-     tree exp;
+check_max_integer_computation_mode (tree exp)
 {
   enum tree_code code;
   enum machine_mode mode;
@@ -6176,11 +6382,10 @@ 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
-highest_pow2_factor (exp)
-     tree exp;
+static unsigned HOST_WIDE_INT
+highest_pow2_factor (tree exp)
 {
-  HOST_WIDE_INT c0, c1;
+  unsigned HOST_WIDE_INT c0, c1;
 
   switch (TREE_CODE (exp))
     {
@@ -6188,7 +6393,7 @@ highest_pow2_factor (exp)
       /* We can find the lowest bit that's a one.  If the low
         HOST_BITS_PER_WIDE_INT bits are zero, return BIGGEST_ALIGNMENT.
         We need to handle this case since we can find it in a COND_EXPR,
-        a MIN_EXPR, or a MAX_EXPR.  If the constant overlows, we have an
+        a MIN_EXPR, or a MAX_EXPR.  If the constant overflows, we have an
         erroneous program, so return BIGGEST_ALIGNMENT to avoid any
         later ICE.  */
       if (TREE_CONSTANT_OVERFLOW (exp))
@@ -6246,12 +6451,10 @@ 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
-highest_pow2_factor_for_type (type, exp)
-     tree type;
-     tree exp;
+static unsigned HOST_WIDE_INT
+highest_pow2_factor_for_type (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;
@@ -6267,9 +6470,7 @@ highest_pow2_factor_for_type (type, exp)
    the placeholder list at which the object is found is placed.  */
 
 tree
-find_placeholder (exp, plist)
-     tree exp;
-     tree *plist;
+find_placeholder (tree exp, tree *plist)
 {
   tree type = TREE_TYPE (exp);
   tree placeholder_expr;
@@ -6357,14 +6558,17 @@ 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)
-     tree exp;
-     rtx target;
-     enum machine_mode tmode;
-     enum expand_modifier modifier;
+expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier modifier)
 {
   rtx op0, op1, temp;
   tree type = TREE_TYPE (exp);
@@ -6450,7 +6654,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
@@ -6494,38 +6698,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;
@@ -6535,7 +6733,8 @@ expand_expr (exp, target, tmode, modifier)
     case PARM_DECL:
       if (!DECL_RTL_SET_P (exp))
        {
-         error_with_decl (exp, "prior parameter's size depends on `%s'");
+         error ("%Hprior parameter's size depends on '%D'",
+                 &DECL_SOURCE_LOCATION (exp), exp);
          return CONST0_RTX (mode);
        }
 
@@ -6544,23 +6743,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 ...  */
 
@@ -6685,8 +6871,11 @@ expand_expr (exp, target, tmode, modifier)
 
       return temp;
 
-    case CONST_DECL:
-      return expand_expr (DECL_INITIAL (exp), target, VOIDmode, 0);
+    case VECTOR_CST:
+      return const_vector_from_tree (exp);
+
+    case CONST_DECL:
+      return expand_expr (DECL_INITIAL (exp), target, VOIDmode, modifier);
 
     case REAL_CST:
       /* If optimized, generate immediate CONST_DOUBLE
@@ -6703,37 +6892,55 @@ expand_expr (exp, target, tmode, modifier)
                                           TYPE_MODE (TREE_TYPE (exp)));
 
     case COMPLEX_CST:
+      /* Handle evaluating a complex constant in a CONCAT target.  */
+      if (original_target && GET_CODE (original_target) == CONCAT)
+       {
+         enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
+         rtx rtarg, itarg;
+
+         rtarg = XEXP (original_target, 0);
+         itarg = XEXP (original_target, 1);
+
+         /* Move the real and imaginary parts separately.  */
+         op0 = expand_expr (TREE_REALPART (exp), rtarg, mode, 0);
+         op1 = expand_expr (TREE_IMAGPART (exp), itarg, mode, 0);
+
+         if (op0 != rtarg)
+           emit_move_insn (rtarg, op0);
+         if (op1 != itarg)
+           emit_move_insn (itarg, op1);
+
+         return original_target;
+       }
+
+      /* ... fall through ...  */
+
     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_location);
        /* 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;
       }
 
@@ -6762,7 +6969,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)
@@ -6789,12 +6996,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);
            }
@@ -6802,7 +7009,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;
        }
@@ -6896,7 +7104,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.  */
@@ -6911,10 +7118,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);
          }
@@ -6975,7 +7179,9 @@ expand_expr (exp, target, tmode, modifier)
                        && ((TREE_CODE (type) == VECTOR_TYPE
                             && !is_zeros_p (exp))
                            || ! mostly_zeros_p (exp)))))
-              || (modifier == EXPAND_INITIALIZER && TREE_CONSTANT (exp)))
+              || ((modifier == EXPAND_INITIALIZER
+                   || modifier == EXPAND_CONST_ADDRESS)
+                  && TREE_CONSTANT (exp)))
        {
          rtx constructor = output_constant_def (exp, 1);
 
@@ -6991,7 +7197,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)
@@ -7061,7 +7268,9 @@ expand_expr (exp, target, tmode, modifier)
           Don't fold if this is for wide characters since it's too
           difficult to do correctly and this is a very rare case.  */
 
-       if (modifier != EXPAND_CONST_ADDRESS && modifier != EXPAND_INITIALIZER
+       if (modifier != EXPAND_CONST_ADDRESS
+           && modifier != EXPAND_INITIALIZER
+           && modifier != EXPAND_MEMORY
            && TREE_CODE (array) == STRING_CST
            && TREE_CODE (index) == INTEGER_CST
            && compare_tree_int (index, TREE_STRING_LENGTH (array)) < 0
@@ -7075,8 +7284,11 @@ expand_expr (exp, target, tmode, modifier)
           we have an explicit constructor and when our operand is a variable
           that was declared const.  */
 
-       if (modifier != EXPAND_CONST_ADDRESS && modifier != EXPAND_INITIALIZER
-           && TREE_CODE (array) == CONSTRUCTOR && ! TREE_SIDE_EFFECTS (array)
+       if (modifier != EXPAND_CONST_ADDRESS
+           && modifier != EXPAND_INITIALIZER
+           && modifier != EXPAND_MEMORY
+           && TREE_CODE (array) == CONSTRUCTOR
+           && ! TREE_SIDE_EFFECTS (array)
            && TREE_CODE (index) == INTEGER_CST
            && 0 > compare_tree_int (index,
                                     list_length (CONSTRUCTOR_ELTS
@@ -7097,6 +7309,7 @@ expand_expr (exp, target, tmode, modifier)
        else if (optimize >= 1
                 && modifier != EXPAND_CONST_ADDRESS
                 && modifier != EXPAND_INITIALIZER
+                && modifier != EXPAND_MEMORY
                 && TREE_READONLY (array) && ! TREE_SIDE_EFFECTS (array)
                 && TREE_CODE (array) == VAR_DECL && DECL_INITIAL (array)
                 && TREE_CODE (DECL_INITIAL (array)) != ERROR_MARK)
@@ -7134,18 +7347,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;
 
@@ -7165,6 +7372,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)))
                  {
@@ -7194,7 +7404,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;
@@ -7219,10 +7433,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
@@ -7237,43 +7453,47 @@ expand_expr (exp, target, tmode, modifier)
              op0 = validize_mem (force_const_mem (mode, op0));
          }
 
-       if (offset != 0)
+       /* Otherwise, if this object not in memory and we either have an
+          offset or a BLKmode result, put it there.  This case can't occur in
+          C, but can in Ada if we have unchecked conversion of an expression
+          from a scalar type to an array or record type or for an
+          ARRAY_RANGE_REF whose type is BLKmode.  */
+       else if (GET_CODE (op0) != MEM
+                && (offset != 0
+                    || (code == ARRAY_RANGE_REF && mode == BLKmode)))
          {
-           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
-              unchecked conversion of an expression from a scalar type to
-              an array or record type.  */
-           if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
-               || GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF)
+           /* 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)
              {
-               /* 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));
-                   op0 = SAVE_EXPR_RTL (TREE_OPERAND (exp, 0));
-                 }
-               else
-                 {
-                   tree nt
-                     = build_qualified_type (TREE_TYPE (tem),
-                                             (TYPE_QUALS (TREE_TYPE (tem))
-                                              | TYPE_QUAL_CONST));
-                   rtx memloc = assign_temp (nt, 1, 1, 1);
-
-                   emit_move_insn (memloc, op0);
-                   op0 = memloc;
-                 }
+               put_var_into_stack (TREE_OPERAND (exp, 0),
+                                   /*rescan=*/true);
+               op0 = SAVE_EXPR_RTL (TREE_OPERAND (exp, 0));
+             }
+           else
+             {
+               tree nt
+                 = build_qualified_type (TREE_TYPE (tem),
+                                         (TYPE_QUALS (TREE_TYPE (tem))
+                                          | TYPE_QUAL_CONST));
+               rtx memloc = assign_temp (nt, 1, 1, 1);
+               
+               emit_move_insn (memloc, op0);
+               op0 = memloc;
              }
+         }
+
+       if (offset != 0)
+         {
+           rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode,
+                                         EXPAND_SUM);
 
            if (GET_CODE (op0) != MEM)
              abort ();
 
 #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);
@@ -7338,10 +7558,13 @@ 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))
+                    && ((modifier == EXPAND_CONST_ADDRESS
+                         || modifier == EXPAND_INITIALIZER)
+                        ? STRICT_ALIGNMENT
+                        : SLOW_UNALIGNED_ACCESS (mode1, MEM_ALIGN (op0))))
+                   || (bitpos % BITS_PER_UNIT != 0)))
            /* If the type and the field are a constant size and the
               size of the type isn't the same size as the bitfield,
               we must use bitfield operations.  */
@@ -7375,7 +7598,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;
              }
@@ -7385,8 +7609,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
@@ -7630,8 +7856,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);
        }
@@ -7667,7 +7893,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.  */
@@ -7735,12 +7962,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);
@@ -7792,7 +8021,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);
 
@@ -7844,6 +8074,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)))
@@ -7911,7 +8143,11 @@ expand_expr (exp, target, tmode, modifier)
          || mode != ptr_mode)
        {
          op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
-         op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
+         if (! operand_equal_p (TREE_OPERAND (exp, 0),
+                                TREE_OPERAND (exp, 1), 0))
+           op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
+         else
+           op1 = op0;
          if (op0 == const0_rtx)
            return op1;
          if (op1 == const0_rtx)
@@ -7920,7 +8156,12 @@ expand_expr (exp, target, tmode, modifier)
        }
 
       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, modifier);
-      op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, modifier);
+      if (! operand_equal_p (TREE_OPERAND (exp, 0),
+                            TREE_OPERAND (exp, 1), 0))
+       op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX,
+                          VOIDmode, modifier);
+      else
+       op1 = op0;
 
       /* We come here from MINUS_EXPR when the second operand is a
          constant.  */
@@ -8038,6 +8279,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);
 
@@ -8056,14 +8299,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,
@@ -8137,7 +8383,11 @@ 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);
+      if (! operand_equal_p (TREE_OPERAND (exp, 0),
+                            TREE_OPERAND (exp, 1), 0))
+       op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
+      else
+       op1 = op0;
       return expand_mult (mode, op0, op1, target, unsignedp);
 
     case TRUNC_DIV_EXPR:
@@ -8147,6 +8397,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.  */
@@ -8165,7 +8417,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;
 
@@ -8175,6 +8427,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);
@@ -8186,14 +8440,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.  */
@@ -8206,6 +8460,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)
@@ -8216,11 +8472,13 @@ 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.  */
+      /* ABS_EXPR is not valid for complex arguments.  */
       if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
          || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
-       return expand_complex_abs (mode, op0, target, unsignedp);
+       abort ();
 
       /* Unsigned abs is simply the operand.  Testing here means we don't
         risk generating incorrect code below.  */
@@ -8233,7 +8491,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
@@ -8290,6 +8550,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 ();
@@ -8297,11 +8559,41 @@ 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;
 
+    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;
+
+    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)
@@ -8336,6 +8628,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);
@@ -8355,7 +8649,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;
 
@@ -8404,7 +8700,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
@@ -8424,6 +8722,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.  */
@@ -8438,7 +8738,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
@@ -8491,6 +8791,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;
@@ -8531,6 +8833,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
@@ -8564,6 +8868,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)
@@ -8573,20 +8878,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)))
@@ -8604,9 +8903,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 ();
@@ -8626,7 +8922,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,
@@ -8645,11 +8942,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
@@ -8668,11 +8965,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
@@ -8687,11 +8986,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
@@ -8705,7 +9006,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);
@@ -8717,7 +9019,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);
@@ -8775,7 +9078,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
@@ -8814,7 +9117,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);
              }
          }
 
@@ -8822,7 +9125,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));
 
@@ -8834,7 +9137,7 @@ expand_expr (exp, target, tmode, modifier)
        tree lhs = TREE_OPERAND (exp, 0);
        tree rhs = TREE_OPERAND (exp, 1);
 
-       temp = expand_assignment (lhs, rhs, ! ignore, original_target != 0);
+       temp = expand_assignment (lhs, rhs, ! ignore);
        return temp;
       }
 
@@ -8879,13 +9182,13 @@ expand_expr (exp, target, tmode, modifier)
                                             (TREE_CODE (rhs) == BIT_IOR_EXPR
                                              ? integer_one_node
                                              : integer_zero_node)),
-                              0, 0);
+                              0);
            do_pending_stack_adjust ();
            emit_label (label);
            return const0_rtx;
          }
 
-       temp = expand_assignment (lhs, rhs, ! ignore, original_target != 0);
+       temp = expand_assignment (lhs, rhs, ! ignore);
 
        return temp;
       }
@@ -8907,6 +9210,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
@@ -8956,13 +9261,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
@@ -8975,7 +9281,7 @@ expand_expr (exp, target, tmode, modifier)
                    /* Handle calls that pass values in multiple
                       non-contiguous locations.  The Irix 6 ABI has examples
                       of this.  */
-                   emit_group_store (memloc, op0,
+                   emit_group_store (memloc, op0, inner_type,
                                      int_size_in_bytes (inner_type));
                  else
                    emit_move_insn (memloc, op0);
@@ -9015,20 +9321,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;
            }
 
@@ -9244,6 +9560,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)
@@ -9256,9 +9574,7 @@ expand_expr (exp, target, tmode, modifier)
    aligned more than BIGGEST_ALIGNMENT.  */
 
 static int
-is_aligning_offset (offset, exp)
-     tree offset;
-     tree exp;
+is_aligning_offset (tree offset, tree exp)
 {
   /* Strip off any conversions and WITH_RECORD_EXPR nodes.  */
   while (TREE_CODE (offset) == NON_LVALUE_EXPR
@@ -9307,9 +9623,7 @@ is_aligning_offset (offset, exp)
    offset will be `sizetype'.  */
 
 tree
-string_constant (arg, ptr_offset)
-     tree arg;
-     tree *ptr_offset;
+string_constant (tree arg, tree *ptr_offset)
 {
   STRIP_NOPS (arg);
 
@@ -9349,9 +9663,7 @@ string_constant (arg, ptr_offset)
    POST is 1 for postinc/decrements and 0 for preinc/decrements.  */
 
 static rtx
-expand_increment (exp, post, ignore)
-     tree exp;
-     int post, ignore;
+expand_increment (tree exp, int post, int ignore)
 {
   rtx op0, op1;
   rtx temp, value;
@@ -9479,7 +9791,7 @@ expand_increment (exp, post, ignore)
          incremented = TREE_OPERAND (incremented, 0);
        }
 
-      temp = expand_assignment (incremented, newexp, ! post && ! ignore , 0);
+      temp = expand_assignment (incremented, newexp, ! post && ! ignore);
       return post ? op0 : temp;
     }
 
@@ -9549,980 +9861,6 @@ 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->nonzero 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:
-      /* Nonzero 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.
@@ -10544,11 +9882,7 @@ do_compare_and_jump (exp, signed_code, unsigned_code, if_false_label,
    set/jump/set sequence.  */
 
 static rtx
-do_store_flag (exp, target, mode, only_cheap)
-     tree exp;
-     rtx target;
-     enum machine_mode mode;
-     int only_cheap;
+do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
 {
   enum rtx_code code;
   tree arg0, arg1, type;
@@ -10678,64 +10012,19 @@ do_store_flag (exp, target, mode, only_cheap)
      do this by shifting the bit being tested to the low-order bit and
      masking the result with the constant 1.  If the condition was EQ,
      we xor it with 1.  This does not require an scc insn and is faster
-     than an scc insn even if we have it.  */
+     than an scc insn even if we have it.
+
+     The code to make this transformation was moved into fold_single_bit_test,
+     so we just call into the folder and expand its result.  */
 
   if ((code == NE || code == EQ)
       && TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1)
       && integer_pow2p (TREE_OPERAND (arg0, 1)))
     {
-      tree inner = TREE_OPERAND (arg0, 0);
-      int bitnum = tree_log2 (TREE_OPERAND (arg0, 1));
-      int ops_unsignedp;
-
-      /* If INNER is a right shift of a constant and it plus BITNUM does
-        not overflow, adjust BITNUM and INNER.  */
-
-      if (TREE_CODE (inner) == RSHIFT_EXPR
-         && TREE_CODE (TREE_OPERAND (inner, 1)) == INTEGER_CST
-         && TREE_INT_CST_HIGH (TREE_OPERAND (inner, 1)) == 0
-         && bitnum < TYPE_PRECISION (type)
-         && 0 > compare_tree_int (TREE_OPERAND (inner, 1),
-                                  bitnum - TYPE_PRECISION (type)))
-       {
-         bitnum += TREE_INT_CST_LOW (TREE_OPERAND (inner, 1));
-         inner = TREE_OPERAND (inner, 0);
-       }
-
-      /* If we are going to be able to omit the AND below, we must do our
-        operations as unsigned.  If we must use the AND, we have a choice.
-        Normally unsigned is faster, but for some machines signed is.  */
-      ops_unsignedp = (bitnum == TYPE_PRECISION (type) - 1 ? 1
-#ifdef LOAD_EXTEND_OP
-                      : (LOAD_EXTEND_OP (operand_mode) == SIGN_EXTEND ? 0 : 1)
-#else
-                      : 1
-#endif
-                      );
-
-      if (! get_subtarget (subtarget)
-         || GET_MODE (subtarget) != operand_mode
-         || ! safe_from_p (subtarget, inner, 1))
-       subtarget = 0;
-
-      op0 = expand_expr (inner, subtarget, VOIDmode, 0);
-
-      if (bitnum != 0)
-       op0 = expand_shift (RSHIFT_EXPR, operand_mode, op0,
-                           size_int (bitnum), subtarget, ops_unsignedp);
-
-      if (GET_MODE (op0) != mode)
-       op0 = convert_to_mode (mode, op0, ops_unsignedp);
-
-      if ((code == EQ && ! invert) || (code == NE && invert))
-       op0 = expand_binop (mode, xor_optab, op0, const1_rtx, subtarget,
-                           ops_unsignedp, OPTAB_LIB_WIDEN);
-
-      /* Put the AND last so it can combine with more things.  */
-      if (bitnum != TYPE_PRECISION (type) - 1)
-       op0 = expand_and (mode, op0, const1_rtx, subtarget);
-
-      return op0;
+      tree type = (*lang_hooks.types.type_for_mode) (mode, unsignedp);
+      return expand_expr (fold_single_bit_test (code == NE ? NE_EXPR : EQ_EXPR,
+                                               arg0, arg1, type), 
+                         target, VOIDmode, EXPAND_NORMAL);
     }
 
   /* Now see if we are likely to be able to do this.  Return if not.  */
@@ -10839,7 +10128,7 @@ do_store_flag (exp, target, mode, only_cheap)
 #endif /* CASE_VALUES_THRESHOLD */
 
 unsigned int
-case_values_threshold ()
+case_values_threshold (void)
 {
   return CASE_VALUES_THRESHOLD;
 }
@@ -10847,11 +10136,8 @@ case_values_threshold ()
 /* Attempt to generate a casesi instruction.  Returns 1 if successful,
    0 otherwise (i.e. if there is no casesi instruction).  */
 int
-try_casesi (index_type, index_expr, minval, range,
-           table_label, default_label)
-     tree index_type, index_expr, minval, range;
-     rtx table_label ATTRIBUTE_UNUSED;
-     rtx default_label;
+try_casesi (tree index_type, tree index_expr, tree minval, tree range,
+           rtx table_label ATTRIBUTE_UNUSED, rtx default_label)
 {
   enum machine_mode index_mode = SImode;
   int index_bits = GET_MODE_BITSIZE (index_mode);
@@ -10938,9 +10224,8 @@ try_casesi (index_type, index_expr, minval, range,
    index value is out of range.  */
 
 static void
-do_tablejump (index, mode, range, table_label, default_label)
-     rtx index, range, table_label, default_label;
-     enum machine_mode mode;
+do_tablejump (rtx index, enum machine_mode mode, rtx range, rtx table_label,
+             rtx default_label)
 {
   rtx temp, vector;
 
@@ -10992,6 +10277,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));
@@ -11003,10 +10289,8 @@ do_tablejump (index, mode, range, table_label, default_label)
 }
 
 int
-try_tablejump (index_type, index_expr, minval, range,
-              table_label, default_label)
-     tree index_type, index_expr, minval, range;
-     rtx table_label, default_label;
+try_tablejump (tree index_type, tree index_expr, tree minval, tree range,
+              rtx table_label, rtx default_label)
 {
   rtx index;
 
@@ -11036,8 +10320,7 @@ try_tablejump (index_type, index_expr, minval, range,
    vector mode, but we can emulate with narrower modes.  */
 
 int
-vector_mode_valid_p (mode)
-     enum machine_mode mode;
+vector_mode_valid_p (enum machine_mode mode)
 {
   enum mode_class class = GET_MODE_CLASS (mode);
   enum machine_mode innermode;
@@ -11061,4 +10344,44 @@ 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 (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);
+    }
+
+  /* Initialize remaining elements to 0.  */
+  for (; i < units; ++i)
+    RTVEC_ELT (v, i) = CONST0_RTX (inner);
+
+  return gen_rtx_raw_CONST_VECTOR (mode, v);
+}
+
 #include "gt-expr.h"