OSDN Git Service

* toplev.c (rest_of_compilation): Avoid cfg_cleanup calls when not
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index 5a14d7e..9643a55 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
 
@@ -225,6 +229,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];
 
@@ -2145,8 +2156,7 @@ move_block_from_reg (regno, x, nregs, size)
   /* 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)
+      && (mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0)) != BLKmode)
     {
       emit_move_insn (adjust_address (x, mode, 0), gen_rtx_REG (mode, regno));
       return;
@@ -2155,9 +2165,7 @@ move_block_from_reg (regno, x, nregs, size)
   /* 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)
+  if (size < UNITS_PER_WORD && BYTES_BIG_ENDIAN)
     {
       rtx tem = operand_subword (x, 0, 1, BLKmode);
       rtx shift;
@@ -2201,6 +2209,42 @@ move_block_from_reg (regno, x, nregs, size)
     }
 }
 
+/* Generate a PARALLEL rtx for a new non-consecutive group of registers from
+   ORIG, where ORIG is a non-consecutive group of registers represented by
+   a PARALLEL.  The clone is identical to the original except in that the
+   original set of registers is replaced by a new set of pseudo registers.
+   The new set has the same modes as the original set.  */
+
+rtx
+gen_group_rtx (orig)
+     rtx orig;
+{
+  int i, length;
+  rtx *tmps;
+
+  if (GET_CODE (orig) != PARALLEL)
+    abort ();
+
+  length = XVECLEN (orig, 0);
+  tmps = (rtx *) alloca (sizeof (rtx) * length);
+
+  /* Skip a NULL entry in first slot.  */
+  i = XEXP (XVECEXP (orig, 0, 0), 0) ? 0 : 1;
+
+  if (i)
+    tmps[0] = 0;
+
+  for (; i < length; i++)
+    {
+      enum machine_mode mode = GET_MODE (XEXP (XVECEXP (orig, 0, i), 0));
+      rtx offset = XEXP (XVECEXP (orig, 0, i), 1);
+
+      tmps[i] = gen_rtx_EXPR_LIST (VOIDmode, gen_reg_rtx (mode), offset);
+    }
+
+  return gen_rtx_PARALLEL (GET_MODE (orig), gen_rtvec_v (length, tmps));
+}
+
 /* Emit code to move a block SRC to a block DST, where DST is non-consecutive
    registers represented by a PARALLEL.  SSIZE represents the total size of
    block SRC in bytes, or -1 if not known.  */
@@ -2322,6 +2366,26 @@ emit_group_load (dst, orig_src, ssize)
     emit_move_insn (XEXP (XVECEXP (dst, 0, i), 0), tmps[i]);
 }
 
+/* Emit code to move a block SRC to block DST, where SRC and DST are
+   non-consecutive groups of registers, each represented by a PARALLEL.  */
+
+void
+emit_group_move (dst, src)
+     rtx dst, src;
+{
+  int i;
+
+  if (GET_CODE (src) != PARALLEL
+      || GET_CODE (dst) != PARALLEL
+      || XVECLEN (src, 0) != XVECLEN (dst, 0))
+    abort ();
+
+  /* Skip first entry if NULL.  */
+  for (i = XEXP (XVECEXP (src, 0, 0), 0) ? 0 : 1; i < XVECLEN (src, 0); i++)
+    emit_move_insn (XEXP (XVECEXP (dst, 0, i), 0),
+                   XEXP (XVECEXP (src, 0, i), 0));
+}
+
 /* Emit code to move a block SRC to a block DST, where SRC is non-consecutive
    registers represented by a PARALLEL.  SSIZE represents the total size of
    block DST, or -1 if not known.  */
@@ -2381,7 +2445,7 @@ emit_group_store (orig_dst, src, ssize)
     {
       dst = gen_reg_rtx (GET_MODE (orig_dst));
       /* Make life a bit easier for combine.  */
-      emit_move_insn (dst, const0_rtx);
+      emit_move_insn (dst, CONST0_RTX (GET_MODE (orig_dst)));
     }
 
   /* Process the pieces.  */
@@ -2413,6 +2477,15 @@ emit_group_store (orig_dst, src, ssize)
              bytepos -= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0)));
              dest = XEXP (dst, 1);
            }
+         else if (bytepos == 0 && XVECLEN (src, 0))
+           {
+             dest = assign_stack_temp (GET_MODE (dest),
+                                       GET_MODE_SIZE (GET_MODE (dest)), 0);
+             emit_move_insn (adjust_address (dest, GET_MODE (tmps[i]), bytepos),
+                             tmps[i]);
+             dst = dest;
+             break;
+           }
          else
            abort ();
        }
@@ -2431,7 +2504,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);
 }
 
@@ -2465,26 +2538,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));
@@ -2602,7 +2666,7 @@ can_store_by_pieces (len, constfun, constfundata, align)
   int reverse;
   rtx cst;
 
-  if (! MOVE_BY_PIECES_P (len, align))
+  if (! STORE_BY_PIECES_P (len, align))
     return 0;
 
   if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
@@ -2677,7 +2741,7 @@ store_by_pieces (to, len, constfun, constfundata, align)
 {
   struct store_by_pieces data;
 
-  if (! MOVE_BY_PIECES_P (len, align))
+  if (! STORE_BY_PIECES_P (len, align))
     abort ();
   to = protect_from_queue (to, 1);
   data.constfun = constfun;
@@ -3092,7 +3156,7 @@ emit_move_insn (x, y)
   else if (CONSTANT_P (y))
     {
       if (optimize
-         && FLOAT_MODE_P (GET_MODE (x))
+         && SCALAR_FLOAT_MODE_P (GET_MODE (x))
          && (last_insn = compress_float_constant (x, y)))
        return last_insn;
 
@@ -3100,6 +3164,12 @@ emit_move_insn (x, y)
        {
          y_cst = y;
          y = force_const_mem (mode, y);
+
+         /* If the target's cannot_force_const_mem prevented the spill,
+            assume that the target's move expanders will also take care
+            of the non-legitimate constant.  */
+         if (!y)
+           y = y_cst;
        }
     }
 
@@ -3150,11 +3220,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))
     {
@@ -3857,7 +3923,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 +3946,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)
            {
@@ -3972,7 +4036,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;
@@ -4200,7 +4265,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,9 +4280,12 @@ expand_assignment (to, from, want_value, suggest_reg)
    with no sequence point.  Will other languages need this to
    be more thorough?
 
-   If WANT_VALUE is 0, we return NULL, to make sure
+   If WANT_VALUE & 1 is 0, we return NULL, to make sure
    to catch quickly any cases where the caller uses the value
-   and fails to set WANT_VALUE.  */
+   and fails to set WANT_VALUE.
+
+   If WANT_VALUE & 2 is set, this is a store into a call param on the
+   stack, and block moves may need to be treated specially.  */
 
 rtx
 store_expr (exp, target, want_value)
@@ -4233,7 +4301,8 @@ store_expr (exp, target, want_value)
     {
       /* 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 +4322,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 +4345,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 +4371,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 +4386,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 +4399,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 +4417,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 +4446,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 +4461,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 +4478,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 +4549,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 +4559,17 @@ 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);
+             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.  */
@@ -4525,13 +4610,15 @@ store_expr (exp, target, want_value)
       else if (GET_CODE (target) == PARALLEL)
        emit_group_load (target, temp, int_size_in_bytes (TREE_TYPE (exp)));
       else if (GET_MODE (temp) == BLKmode)
-       emit_block_move (target, temp, expr_size (exp), BLOCK_OP_NORMAL);
+       emit_block_move (target, temp, expr_size (exp),
+                        (want_value & 2
+                         ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
       else
        emit_move_insn (target, temp);
     }
 
   /* If we don't want a value, return NULL_RTX.  */
-  if (! want_value)
+  if ((want_value & 1) == 0)
     return NULL_RTX;
 
   /* If we are supposed to return TEMP, do so as long as it isn't a MEM.
@@ -4540,7 +4627,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);
@@ -4760,7 +4848,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 +4865,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;
@@ -4999,7 +5085,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 +5124,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);
@@ -6357,7 +6442,14 @@ find_placeholder (exp, plist)
 
    EXPAND_CONST_ADDRESS says that it is okay to return a MEM
    with a constant address even if that address is not normally legitimate.
-   EXPAND_INITIALIZER and EXPAND_SUM also have this effect.  */
+   EXPAND_INITIALIZER and EXPAND_SUM also have this effect.
+
+   EXPAND_STACK_PARM is used when expanding to a TARGET on the stack for
+   a call parameter.  Such targets require special care as we haven't yet
+   marked TARGET so that it's safe from being trashed by libcalls.  We
+   don't want to use TARGET for anything but the final result;
+   Intermediate values must go elsewhere.   Additionally, calls to
+   emit_block_move will be flagged with BLOCK_OP_CALL_PARM.  */
 
 rtx
 expand_expr (exp, target, tmode, modifier)
@@ -6450,7 +6542,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,13 +6586,15 @@ 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)
     {
@@ -6686,7 +6780,7 @@ expand_expr (exp, target, tmode, modifier)
       return temp;
 
     case CONST_DECL:
-      return expand_expr (DECL_INITIAL (exp), target, VOIDmode, 0);
+      return expand_expr (DECL_INITIAL (exp), target, VOIDmode, modifier);
 
     case REAL_CST:
       /* If optimized, generate immediate CONST_DOUBLE
@@ -6802,7 +6896,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 +6991,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 +7005,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);
          }
@@ -6991,7 +7082,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)
@@ -7165,6 +7257,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)))
                  {
@@ -7219,10 +7314,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
@@ -7239,7 +7336,8 @@ expand_expr (exp, target, tmode, modifier)
 
        if (offset != 0)
          {
-           rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
+           rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode,
+                                         EXPAND_SUM);
 
            /* If this object is in a register, put it into memory.
               This case can't occur in C, but can in Ada if we have
@@ -7375,7 +7473,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 +7484,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 +7731,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 +7768,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.  */
@@ -7792,7 +7894,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 +7947,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)))
@@ -7912,9 +8017,10 @@ 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);
-         temp = simplify_binary_operation (PLUS, mode, op0, op1);
-         if (temp)
-           return temp;
+         if (op0 == const0_rtx)
+           return op1;
+         if (op1 == const0_rtx)
+           return op0;
          goto binop2;
        }
 
@@ -8037,6 +8143,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);
 
@@ -8055,14 +8163,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,
@@ -8146,6 +8257,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.  */
@@ -8164,7 +8277,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;
 
@@ -8174,6 +8287,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);
@@ -8185,14 +8300,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.  */
@@ -8205,6 +8320,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)
@@ -8215,6 +8332,8 @@ expand_expr (exp, target, tmode, modifier)
 
     case ABS_EXPR:
       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+      if (modifier == EXPAND_STACK_PARM)
+       target = 0;
 
       /* Handle complex values specially.  */
       if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
@@ -8232,7 +8351,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
@@ -8289,6 +8410,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 ();
@@ -8296,11 +8419,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)
@@ -8335,6 +8488,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);
@@ -8354,7 +8509,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;
 
@@ -8403,7 +8560,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
@@ -8423,6 +8582,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.  */
@@ -8437,7 +8598,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
@@ -8490,6 +8651,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;
@@ -8530,6 +8693,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
@@ -8563,6 +8728,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)
@@ -8572,20 +8738,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)))
@@ -8603,9 +8763,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 ();
@@ -8625,7 +8782,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,
@@ -8644,11 +8802,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
@@ -8667,11 +8825,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
@@ -8686,11 +8846,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
@@ -8704,7 +8866,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);
@@ -8716,7 +8879,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);
@@ -8821,7 +8985,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));
 
@@ -8906,6 +9070,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
@@ -9027,7 +9193,8 @@ expand_expr (exp, target, tmode, modifier)
                abort ();
 
              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;
            }
 
@@ -9243,6 +9410,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)