OSDN Git Service

* ifcvt.c (cond_exec_find_if_block): Return FALSE if no
[pf3gnuchains/gcc-fork.git] / gcc / calls.c
index 1613e88..9ef3b0e 100644 (file)
@@ -1,6 +1,6 @@
 /* Convert function calls to rtl insns, for GNU C compiler.
    Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -132,7 +132,8 @@ static int finalize_must_preallocate (int, int, struct arg_data *,
 static void precompute_arguments (int, int, struct arg_data *);
 static int compute_argument_block_size (int, struct args_size *, int);
 static void initialize_argument_information (int, struct arg_data *,
-                                            struct args_size *, int, tree,
+                                            struct args_size *, int,
+                                            tree, tree,
                                             tree, CUMULATIVE_ARGS *, int,
                                             rtx *, int *, int *, int *,
                                             bool *, bool);
@@ -148,7 +149,6 @@ static int check_sibcall_argument_overlap (rtx, struct arg_data *, int);
 
 static int combine_pending_stack_adjustment_and_call (int, struct args_size *,
                                                      unsigned int);
-static tree split_complex_values (tree);
 static tree split_complex_types (tree);
 
 #ifdef REG_PARM_STACK_SPACE
@@ -399,7 +399,7 @@ emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED,
   if (ecf_flags & ECF_RETURNS_TWICE)
     {
       REG_NOTES (call_insn) = gen_rtx_EXPR_LIST (REG_SETJMP, const0_rtx,
-                                                REG_NOTES (call_insn));
+                                                REG_NOTES (call_insn));
       current_function_calls_setjmp = 1;
     }
 
@@ -476,10 +476,10 @@ special_function_p (tree fndecl, int flags)
       /* Exclude functions not at the file scope, or not `extern',
         since they are not the magic functions we would otherwise
         think they are.
-         FIXME: this should be handled with attributes, not with this
-         hacky imitation of DECL_ASSEMBLER_NAME.  It's (also) wrong
-         because you can declare fork() inside a function if you
-         wish.  */
+        FIXME: this should be handled with attributes, not with this
+        hacky imitation of DECL_ASSEMBLER_NAME.  It's (also) wrong
+        because you can declare fork() inside a function if you
+        wish.  */
       && (DECL_CONTEXT (fndecl) == NULL_TREE
          || TREE_CODE (DECL_CONTEXT (fndecl)) == TRANSLATION_UNIT_DECL)
       && TREE_PUBLIC (fndecl))
@@ -527,7 +527,9 @@ special_function_p (tree fndecl, int flags)
       else if ((tname[0] == 'q' && tname[1] == 's'
                && ! strcmp (tname, "qsetjmp"))
               || (tname[0] == 'v' && tname[1] == 'f'
-                  && ! strcmp (tname, "vfork")))
+                  && ! strcmp (tname, "vfork"))
+              || (tname[0] == 'g' && tname[1] == 'e'
+                  && !strcmp (tname, "getcontext")))
        flags |= ECF_RETURNS_TWICE;
 
       else if (tname[0] == 'l' && tname[1] == 'o'
@@ -551,11 +553,10 @@ bool
 alloca_call_p (tree exp)
 {
   if (TREE_CODE (exp) == CALL_EXPR
-      && TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
-      && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
-         == FUNCTION_DECL)
-      && (special_function_p (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
-                             0) & ECF_MAY_BE_ALLOCA))
+      && TREE_CODE (CALL_EXPR_FN (exp)) == ADDR_EXPR
+      && (TREE_CODE (TREE_OPERAND (CALL_EXPR_FN (exp), 0)) == FUNCTION_DECL)
+      && (special_function_p (TREE_OPERAND (CALL_EXPR_FN (exp), 0), 0)
+         & ECF_MAY_BE_ALLOCA))
     return true;
   return false;
 }
@@ -570,17 +571,8 @@ flags_from_decl_or_type (tree exp)
 
   if (DECL_P (exp))
     {
-      struct cgraph_rtl_info *i = cgraph_rtl_info (exp);
       type = TREE_TYPE (exp);
 
-      if (i)
-       {
-         if (i->pure_function)
-           flags |= ECF_PURE | ECF_LIBCALL_BLOCK;
-         if (i->const_function)
-           flags |= ECF_CONST | ECF_LIBCALL_BLOCK;
-       }
-
       /* The function exp may have the `malloc' attribute.  */
       if (DECL_IS_MALLOC (exp))
        flags |= ECF_MALLOC;
@@ -591,7 +583,7 @@ flags_from_decl_or_type (tree exp)
 
       /* The function exp may have the `pure' attribute.  */
       if (DECL_IS_PURE (exp))
-       flags |= ECF_PURE | ECF_LIBCALL_BLOCK;
+       flags |= ECF_PURE;
 
       if (DECL_IS_NOVOPS (exp))
        flags |= ECF_NOVOPS;
@@ -600,7 +592,7 @@ flags_from_decl_or_type (tree exp)
        flags |= ECF_NOTHROW;
 
       if (TREE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp))
-       flags |= ECF_LIBCALL_BLOCK | ECF_CONST;
+       flags |= ECF_CONST;
 
       flags = special_function_p (exp, flags);
     }
@@ -615,7 +607,7 @@ flags_from_decl_or_type (tree exp)
   if (TREE_CODE (type) == FUNCTION_TYPE && TYPE_RETURNS_STACK_DEPRESSED (type))
     {
       flags |= ECF_SP_DEPRESSED;
-      flags &= ~(ECF_PURE | ECF_CONST | ECF_LIBCALL_BLOCK);
+      flags &= ~(ECF_PURE | ECF_CONST);
     }
 
   return flags;
@@ -633,7 +625,7 @@ call_expr_flags (tree t)
     flags = flags_from_decl_or_type (decl);
   else
     {
-      t = TREE_TYPE (TREE_OPERAND (t, 0));
+      t = TREE_TYPE (CALL_EXPR_FN (t));
       if (t && TREE_CODE (t) == POINTER_TYPE)
        flags = flags_from_decl_or_type (TREE_TYPE (t));
       else
@@ -666,8 +658,7 @@ precompute_register_parameters (int num_actuals, struct arg_data *args,
        if (args[i].value == 0)
          {
            push_temp_slots ();
-           args[i].value = expand_expr (args[i].tree_value, NULL_RTX,
-                                        VOIDmode, 0);
+           args[i].value = expand_normal (args[i].tree_value);
            preserve_temp_slots (args[i].value);
            pop_temp_slots ();
          }
@@ -850,7 +841,7 @@ store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals)
              = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
          }
 
-       args[i].aligned_regs = xmalloc (sizeof (rtx) * args[i].n_aligned_regs);
+       args[i].aligned_regs = XNEWVEC (rtx, args[i].n_aligned_regs);
 
        /* Structures smaller than a word are normally aligned to the
           least significant byte.  On a BYTES_BIG_ENDIAN machine,
@@ -898,12 +889,15 @@ store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals)
 }
 
 /* Fill in ARGS_SIZE and ARGS array based on the parameters found in
-   ACTPARMS.
+   CALL_EXPR EXP.  
 
    NUM_ACTUALS is the total number of parameters.
 
    N_NAMED_ARGS is the total number of named arguments.
 
+   STRUCT_VALUE_ADDR_VALUE is the implicit argument for a struct return
+   value, or null.
+
    FNDECL is the tree code for the target of this call (if known)
 
    ARGS_SO_FAR holds state needed by the target to know where to place
@@ -929,7 +923,8 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
                                 struct arg_data *args,
                                 struct args_size *args_size,
                                 int n_named_args ATTRIBUTE_UNUSED,
-                                tree actparms, tree fndecl,
+                                tree exp, tree struct_value_addr_value,
+                                tree fndecl,
                                 CUMULATIVE_ARGS *args_so_far,
                                 int reg_parm_stack_space,
                                 rtx *old_stack_level, int *old_pending_adj,
@@ -943,7 +938,6 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
   int argpos;
 
   int i;
-  tree p;
 
   args_size->constant = 0;
   args_size->var = 0;
@@ -963,15 +957,45 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
       i = 0, inc = 1;
     }
 
+  /* First fill in the actual arguments in the ARGS array, splitting
+     complex arguments if necessary.  */
+  {
+    int j = i;
+    call_expr_arg_iterator iter;
+    tree arg;
+
+    if (struct_value_addr_value)
+      {
+       args[j].tree_value = struct_value_addr_value;
+       j += inc;
+      }
+    FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
+      {
+       tree argtype = TREE_TYPE (arg);
+       if (targetm.calls.split_complex_arg
+           && argtype
+           && TREE_CODE (argtype) == COMPLEX_TYPE
+           && targetm.calls.split_complex_arg (argtype))
+         {
+           tree subtype = TREE_TYPE (argtype);
+           arg = save_expr (arg);
+           args[j].tree_value = build1 (REALPART_EXPR, subtype, arg);
+           j += inc;
+           args[j].tree_value = build1 (IMAGPART_EXPR, subtype, arg);
+         }
+       else
+         args[j].tree_value = arg;
+       j += inc;
+      }
+  }
+
   /* I counts args in order (to be) pushed; ARGPOS counts in order written.  */
-  for (p = actparms, argpos = 0; p; p = TREE_CHAIN (p), i += inc, argpos++)
+  for (argpos = 0; argpos < num_actuals; i += inc, argpos++)
     {
-      tree type = TREE_TYPE (TREE_VALUE (p));
+      tree type = TREE_TYPE (args[i].tree_value);
       int unsignedp;
       enum machine_mode mode;
 
-      args[i].tree_value = TREE_VALUE (p);
-
       /* Replace erroneous argument with constant zero.  */
       if (type == error_mark_node || !COMPLETE_TYPE_P (type))
        args[i].tree_value = integer_zero_node, type = integer_type_node;
@@ -1039,7 +1063,7 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
                {
                  /* This is a variable-sized object.  Make space on the stack
                     for it.  */
-                 rtx size_rtx = expr_size (TREE_VALUE (p));
+                 rtx size_rtx = expr_size (args[i].tree_value);
 
                  if (*old_stack_level == 0)
                    {
@@ -1198,13 +1222,12 @@ compute_argument_block_size (int reg_parm_stack_space,
            = size_binop (MAX_EXPR, args_size->var,
                          ssize_int (reg_parm_stack_space));
 
-#ifndef OUTGOING_REG_PARM_STACK_SPACE
          /* The area corresponding to register parameters is not to count in
             the size of the block we need.  So make the adjustment.  */
-         args_size->var
-           = size_binop (MINUS_EXPR, args_size->var,
-                         ssize_int (reg_parm_stack_space));
-#endif
+         if (!OUTGOING_REG_PARM_STACK_SPACE)
+           args_size->var
+             = size_binop (MINUS_EXPR, args_size->var,
+                           ssize_int (reg_parm_stack_space));
        }
     }
   else
@@ -1222,9 +1245,8 @@ compute_argument_block_size (int reg_parm_stack_space,
       args_size->constant = MAX (args_size->constant,
                                 reg_parm_stack_space);
 
-#ifndef OUTGOING_REG_PARM_STACK_SPACE
-      args_size->constant -= reg_parm_stack_space;
-#endif
+      if (!OUTGOING_REG_PARM_STACK_SPACE)
+       args_size->constant -= reg_parm_stack_space;
     }
   return unadjusted_args_size;
 }
@@ -1257,7 +1279,7 @@ precompute_arguments (int flags, int num_actuals, struct arg_data *args)
       gcc_assert (!TREE_ADDRESSABLE (TREE_TYPE (args[i].tree_value)));
 
       args[i].initial_value = args[i].value
-       = expand_expr (args[i].tree_value, NULL_RTX, VOIDmode, 0);
+       = expand_normal (args[i].tree_value);
 
       mode = TYPE_MODE (TREE_TYPE (args[i].tree_value));
       if (mode != args[i].mode)
@@ -1288,7 +1310,8 @@ precompute_arguments (int flags, int num_actuals, struct arg_data *args)
    compute and return the final value for MUST_PREALLOCATE.  */
 
 static int
-finalize_must_preallocate (int must_preallocate, int num_actuals, struct arg_data *args, struct args_size *args_size)
+finalize_must_preallocate (int must_preallocate, int num_actuals, 
+                          struct arg_data *args, struct args_size *args_size)
 {
   /* See if we have or want to preallocate stack space.
 
@@ -1363,9 +1386,13 @@ compute_argument_addresses (struct arg_data *args, rtx argblock, int num_actuals
          rtx slot_offset = ARGS_SIZE_RTX (args[i].locate.slot_offset);
          rtx addr;
          unsigned int align, boundary;
+         unsigned int units_on_stack = 0;
+         enum machine_mode partial_mode = VOIDmode;
 
          /* Skip this parm if it will not be passed on the stack.  */
-         if (! args[i].pass_on_stack && args[i].reg != 0)
+         if (! args[i].pass_on_stack
+             && args[i].reg != 0
+             && args[i].partial == 0)
            continue;
 
          if (GET_CODE (offset) == CONST_INT)
@@ -1374,9 +1401,23 @@ compute_argument_addresses (struct arg_data *args, rtx argblock, int num_actuals
            addr = gen_rtx_PLUS (Pmode, arg_reg, offset);
 
          addr = plus_constant (addr, arg_offset);
-         args[i].stack = gen_rtx_MEM (args[i].mode, addr);
-         set_mem_attributes (args[i].stack,
-                             TREE_TYPE (args[i].tree_value), 1);
+
+         if (args[i].partial != 0)
+           {
+             /* Only part of the parameter is being passed on the stack.
+                Generate a simple memory reference of the correct size.  */
+             units_on_stack = args[i].locate.size.constant;
+             partial_mode = mode_for_size (units_on_stack * BITS_PER_UNIT,
+                                           MODE_INT, 1);
+             args[i].stack = gen_rtx_MEM (partial_mode, addr);
+             set_mem_size (args[i].stack, GEN_INT (units_on_stack));
+           }
+         else
+           {
+             args[i].stack = gen_rtx_MEM (args[i].mode, addr);
+             set_mem_attributes (args[i].stack,
+                                 TREE_TYPE (args[i].tree_value), 1);
+           }
          align = BITS_PER_UNIT;
          boundary = args[i].locate.boundary;
          if (args[i].locate.where_pad != downward)
@@ -1394,9 +1435,21 @@ compute_argument_addresses (struct arg_data *args, rtx argblock, int num_actuals
            addr = gen_rtx_PLUS (Pmode, arg_reg, slot_offset);
 
          addr = plus_constant (addr, arg_offset);
-         args[i].stack_slot = gen_rtx_MEM (args[i].mode, addr);
-         set_mem_attributes (args[i].stack_slot,
-                             TREE_TYPE (args[i].tree_value), 1);
+
+         if (args[i].partial != 0)
+           {
+             /* Only part of the parameter is being passed on the stack.
+                Generate a simple memory reference of the correct size.
+              */
+             args[i].stack_slot = gen_rtx_MEM (partial_mode, addr);
+             set_mem_size (args[i].stack_slot, GEN_INT (units_on_stack));
+           }
+         else
+           {
+             args[i].stack_slot = gen_rtx_MEM (args[i].mode, addr);
+             set_mem_attributes (args[i].stack_slot,
+                                 TREE_TYPE (args[i].tree_value), 1);
+           }
          set_mem_align (args[i].stack_slot, args[i].locate.boundary);
 
          /* Function incoming arguments may overlap with sibling call
@@ -1440,12 +1493,52 @@ rtx_for_function_call (tree fndecl, tree addr)
     /* Generate an rtx (probably a pseudo-register) for the address.  */
     {
       push_temp_slots ();
-      funexp = expand_expr (addr, NULL_RTX, VOIDmode, 0);
+      funexp = expand_normal (addr);
       pop_temp_slots ();       /* FUNEXP can't be BLKmode.  */
     }
   return funexp;
 }
 
+/* Return true if and only if SIZE storage units (usually bytes)
+   starting from address ADDR overlap with already clobbered argument
+   area.  This function is used to determine if we should give up a
+   sibcall.  */
+
+static bool
+mem_overlaps_already_clobbered_arg_p (rtx addr, unsigned HOST_WIDE_INT size)
+{
+  HOST_WIDE_INT i;
+
+  if (addr == current_function_internal_arg_pointer)
+    i = 0;
+  else if (GET_CODE (addr) == PLUS
+          && XEXP (addr, 0) == current_function_internal_arg_pointer
+          && GET_CODE (XEXP (addr, 1)) == CONST_INT)
+    i = INTVAL (XEXP (addr, 1));
+  /* Return true for arg pointer based indexed addressing.  */
+  else if (GET_CODE (addr) == PLUS
+          && (XEXP (addr, 0) == current_function_internal_arg_pointer
+              || XEXP (addr, 1) == current_function_internal_arg_pointer))
+    return true;
+  else
+    return false;
+
+#ifdef ARGS_GROW_DOWNWARD
+  i = -i - size;
+#endif
+  if (size > 0)
+    {
+      unsigned HOST_WIDE_INT k;
+
+      for (k = 0; k < size; k++)
+       if (i + k < stored_args_map->n_bits
+           && TEST_BIT (stored_args_map, i + k))
+         return true;
+    }
+
+  return false;
+}
+
 /* Do the register loads required for any wholly-register parms or any
    parms which are passed both on the stack and in a register.  Their
    expressions were already evaluated.
@@ -1453,7 +1546,7 @@ rtx_for_function_call (tree fndecl, tree addr)
    Mark all register-parms as living through the call, putting these USE
    insns in the CALL_INSN_FUNCTION_USAGE field.
 
-   When IS_SIBCALL, perform the check_sibcall_overlap_argument_overlap
+   When IS_SIBCALL, perform the check_sibcall_argument_overlap
    checking, setting *SIBCALL_FAILURE if appropriate.  */
 
 static void
@@ -1543,6 +1636,12 @@ load_register_parameters (struct arg_data *args, int num_actuals,
            {
              rtx mem = validize_mem (args[i].value);
 
+             /* Check for overlap with already clobbered argument area.  */
+             if (is_sibcall
+                 && mem_overlaps_already_clobbered_arg_p (XEXP (args[i].value, 0),
+                                                          size))
+               *sibcall_failure = 1;
+
              /* Handle a BLKmode that needs shifting.  */
              if (nregs == 1 && size < UNITS_PER_WORD
 #ifdef BLOCK_REG_PADDING
@@ -1656,7 +1755,6 @@ check_sibcall_argument_overlap_1 (rtx x)
 {
   RTX_CODE code;
   int i, j;
-  unsigned int k;
   const char *fmt;
 
   if (x == NULL_RTX)
@@ -1665,28 +1763,8 @@ check_sibcall_argument_overlap_1 (rtx x)
   code = GET_CODE (x);
 
   if (code == MEM)
-    {
-      if (XEXP (x, 0) == current_function_internal_arg_pointer)
-       i = 0;
-      else if (GET_CODE (XEXP (x, 0)) == PLUS
-              && XEXP (XEXP (x, 0), 0) ==
-                 current_function_internal_arg_pointer
-              && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
-       i = INTVAL (XEXP (XEXP (x, 0), 1));
-      else
-       return 0;
-
-#ifdef ARGS_GROW_DOWNWARD
-      i = -i - GET_MODE_SIZE (GET_MODE (x));
-#endif
-
-      for (k = 0; k < GET_MODE_SIZE (GET_MODE (x)); k++)
-       if (i + k < stored_args_map->n_bits
-           && TEST_BIT (stored_args_map, i + k))
-         return 1;
-
-      return 0;
-    }
+    return mem_overlaps_already_clobbered_arg_p (XEXP (x, 0),
+                                                GET_MODE_SIZE (GET_MODE (x)));
 
   /* Scan all subexpressions.  */
   fmt = GET_RTX_FORMAT (code);
@@ -1766,7 +1844,7 @@ shift_return_value (enum machine_mode mode, bool left_p, rtx value)
   return true;
 }
 
-/* Generate all the code for a function call
+/* Generate all the code for a CALL_EXPR exp
    and return an rtx for its value.
    Store the value in TARGET (specified as an rtx) if convenient.
    If the value is stored in TARGET then TARGET is returned.
@@ -1778,8 +1856,6 @@ expand_call (tree exp, rtx target, int ignore)
   /* Nonzero if we are currently expanding a call.  */
   static int currently_expanding_call = 0;
 
-  /* List of actual parameters.  */
-  tree actparms = TREE_OPERAND (exp, 1);
   /* RTX for the function to be called.  */
   rtx funexp;
   /* Sequence of insns to perform a normal "call".  */
@@ -1807,6 +1883,8 @@ expand_call (tree exp, rtx target, int ignore)
      an extra, implicit first parameter.  Otherwise,
      it is passed by being copied directly into struct_value_rtx.  */
   int structure_value_addr_parm = 0;
+  /* Holds the value of implicit argument for the struct value.  */
+  tree structure_value_addr_value = NULL_TREE;
   /* Size of aggregate value wanted, or zero if none wanted
      or if we are using the non-reentrant PCC calling convention
      or expecting the value in registers.  */
@@ -1821,6 +1899,8 @@ expand_call (tree exp, rtx target, int ignore)
   /* Number of named args.  Args after this are anonymous ones
      and they must all go on the stack.  */
   int n_named_args;
+  /* Number of complex actual arguments that need to be split.  */
+  int num_complex_actuals = 0;
 
   /* Vector of information about each argument.
      Arguments are numbered in the order they will be pushed,
@@ -1880,8 +1960,8 @@ expand_call (tree exp, rtx target, int ignore)
   int old_stack_pointer_delta = 0;
 
   rtx call_fusage;
-  tree p = TREE_OPERAND (exp, 0);
-  tree addr = TREE_OPERAND (exp, 0);
+  tree p = CALL_EXPR_FN (exp);
+  tree addr = CALL_EXPR_FN (exp);
   int i;
   /* The alignment of the stack, in bits.  */
   unsigned HOST_WIDE_INT preferred_stack_boundary;
@@ -1923,9 +2003,10 @@ expand_call (tree exp, rtx target, int ignore)
     {
       bool volatilep = false;
       tree arg;
+      call_expr_arg_iterator iter;
 
-      for (arg = actparms; arg; arg = TREE_CHAIN (arg))
-       if (TREE_THIS_VOLATILE (TREE_VALUE (arg)))
+      FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
+       if (TREE_THIS_VOLATILE (arg))
          {
            volatilep = true;
            break;
@@ -1933,9 +2014,8 @@ expand_call (tree exp, rtx target, int ignore)
 
       if (! volatilep)
        {
-         for (arg = actparms; arg; arg = TREE_CHAIN (arg))
-           expand_expr (TREE_VALUE (arg), const0_rtx,
-                        VOIDmode, EXPAND_NORMAL);
+         FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
+           expand_expr (arg, const0_rtx, VOIDmode, EXPAND_NORMAL);
          return const0_rtx;
        }
     }
@@ -1944,10 +2024,8 @@ expand_call (tree exp, rtx target, int ignore)
   reg_parm_stack_space = REG_PARM_STACK_SPACE (fndecl);
 #endif
 
-#ifndef OUTGOING_REG_PARM_STACK_SPACE
-  if (reg_parm_stack_space > 0 && PUSH_ARGS)
+  if (!OUTGOING_REG_PARM_STACK_SPACE && reg_parm_stack_space > 0 && PUSH_ARGS)
     must_preallocate = 1;
-#endif
 
   /* Set up a place to return a structure.  */
 
@@ -1972,7 +2050,7 @@ expand_call (tree exp, rtx target, int ignore)
            /* For variable-sized objects, we must be called with a target
               specified.  If we were to allocate space on the stack here,
               we would have no way of knowing when to free it.  */
-           rtx d = assign_temp (TREE_TYPE (exp), 1, 1, 1);
+           rtx d = assign_temp (TREE_TYPE (exp), 0, 1, 1);
 
            mark_temp_addr_taken (d);
            structure_value_addr = XEXP (d, 0);
@@ -1996,12 +2074,21 @@ expand_call (tree exp, rtx target, int ignore)
   gcc_assert (POINTER_TYPE_P (funtype));
   funtype = TREE_TYPE (funtype);
 
-  /* Munge the tree to split complex arguments into their imaginary
-     and real parts.  */
+  /* Count whether there are actual complex arguments that need to be split
+     into their real and imaginary parts.  Munge the type_arg_types
+     appropriately here as well.  */
   if (targetm.calls.split_complex_arg)
     {
+      call_expr_arg_iterator iter;
+      tree arg;
+      FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
+       {
+         tree type = TREE_TYPE (arg);
+         if (type && TREE_CODE (type) == COMPLEX_TYPE
+             && targetm.calls.split_complex_arg (type))
+           num_complex_actuals++;
+       }
       type_arg_types = split_complex_types (TYPE_ARG_TYPES (funtype));
-      actparms = split_complex_values (actparms);
     }
   else
     type_arg_types = TYPE_ARG_TYPES (funtype);
@@ -2010,7 +2097,8 @@ expand_call (tree exp, rtx target, int ignore)
     current_function_calls_alloca = 1;
 
   /* If struct_value_rtx is 0, it means pass the address
-     as if it were an extra parameter.  */
+     as if it were an extra parameter.  Put the argument expression
+     in structure_value_addr_value.  */
   if (structure_value_addr && struct_value == 0)
     {
       /* If structure_value_addr is a REG other than
@@ -2026,17 +2114,14 @@ expand_call (tree exp, rtx target, int ignore)
                                      (Pmode, structure_value_addr))
                  : structure_value_addr);
 
-      actparms
-       = tree_cons (error_mark_node,
-                    make_tree (build_pointer_type (TREE_TYPE (funtype)),
-                               temp),
-                    actparms);
+      structure_value_addr_value =
+       make_tree (build_pointer_type (TREE_TYPE (funtype)), temp);
       structure_value_addr_parm = 1;
     }
 
   /* Count the arguments and set NUM_ACTUALS.  */
-  for (p = actparms, num_actuals = 0; p; p = TREE_CHAIN (p))
-    num_actuals++;
+  num_actuals =
+    call_expr_nargs (exp) + num_complex_actuals + structure_value_addr_parm;
 
   /* Compute number of named args.
      First, do a raw count of the args for INIT_CUMULATIVE_ARGS.  */
@@ -2094,7 +2179,8 @@ expand_call (tree exp, rtx target, int ignore)
   /* Build up entries in the ARGS array, compute the size of the
      arguments into ARGS_SIZE, etc.  */
   initialize_argument_information (num_actuals, args, &args_size,
-                                  n_named_args, actparms, fndecl,
+                                  n_named_args, exp,
+                                  structure_value_addr_value, fndecl,
                                   &args_so_far, reg_parm_stack_space,
                                   &old_stack_level, &old_pending_adj,
                                   &must_preallocate, &flags,
@@ -2156,12 +2242,12 @@ expand_call (tree exp, rtx target, int ignore)
         into a sibcall.  */
       || !targetm.function_ok_for_sibcall (fndecl, exp)
       /* Functions that do not return exactly once may not be sibcall
-         optimized.  */
+        optimized.  */
       || (flags & (ECF_RETURNS_TWICE | ECF_NORETURN))
       || TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (addr)))
       /* If the called function is nested in the current one, it might access
-         some of the caller's arguments, but could clobber them beforehand if
-         the argument areas are shared.  */
+        some of the caller's arguments, but could clobber them beforehand if
+        the argument areas are shared.  */
       || (fndecl && decl_function_context (fndecl) == current_function_decl)
       /* If this function requires more stack slots than the current
         function, we cannot change it into a sibling call.
@@ -2256,6 +2342,9 @@ expand_call (tree exp, rtx target, int ignore)
       if (pass && (flags & (ECF_LIBCALL_BLOCK | ECF_MALLOC)))
        start_sequence ();
 
+      if (pass == 0 && cfun->stack_protect_guard)
+       stack_protect_epilogue ();
+
       adjusted_args_size = args_size;
       /* Compute the actual size of the argument block required.  The variable
         and constant sizes must be combined, the size may have to be rounded,
@@ -2271,7 +2360,7 @@ expand_call (tree exp, rtx target, int ignore)
       old_stack_allocated = stack_pointer_delta - pending_stack_adjust;
 
       /* The argument block when performing a sibling call is the
-         incoming argument block.  */
+        incoming argument block.  */
       if (pass == 0)
        {
          argblock = virtual_incoming_args_rtx;
@@ -2337,12 +2426,11 @@ expand_call (tree exp, rtx target, int ignore)
                     Another approach might be to try to reorder the argument
                     evaluations to avoid this conflicting stack usage.  */
 
-#ifndef OUTGOING_REG_PARM_STACK_SPACE
                  /* Since we will be writing into the entire argument area,
                     the map must be allocated for its entire size, not just
                     the part that is the responsibility of the caller.  */
-                 needed += reg_parm_stack_space;
-#endif
+                 if (!OUTGOING_REG_PARM_STACK_SPACE)
+                   needed += reg_parm_stack_space;
 
 #ifdef ARGS_GROW_DOWNWARD
                  highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
@@ -2353,7 +2441,7 @@ expand_call (tree exp, rtx target, int ignore)
 #endif
                  if (stack_usage_map_buf)
                    free (stack_usage_map_buf);
-                 stack_usage_map_buf = xmalloc (highest_outgoing_arg_in_use);
+                 stack_usage_map_buf = XNEWVEC (char, highest_outgoing_arg_in_use);
                  stack_usage_map = stack_usage_map_buf;
 
                  if (initial_highest_arg_in_use)
@@ -2438,12 +2526,10 @@ expand_call (tree exp, rtx target, int ignore)
             an argument.  */
          if (stack_arg_under_construction)
            {
-#ifndef OUTGOING_REG_PARM_STACK_SPACE
-             rtx push_size = GEN_INT (reg_parm_stack_space
-                                      + adjusted_args_size.constant);
-#else
-             rtx push_size = GEN_INT (adjusted_args_size.constant);
-#endif
+             rtx push_size
+               = GEN_INT (adjusted_args_size.constant
+                          + (OUTGOING_REG_PARM_STACK_SPACE ? 0
+                             : reg_parm_stack_space));
              if (old_stack_level == 0)
                {
                  emit_stack_save (SAVE_BLOCK, &old_stack_level,
@@ -2461,9 +2547,8 @@ expand_call (tree exp, rtx target, int ignore)
                  /* Make a new map for the new argument list.  */
                  if (stack_usage_map_buf)
                    free (stack_usage_map_buf);
-                 stack_usage_map_buf = xmalloc (highest_outgoing_arg_in_use);
+                 stack_usage_map_buf = XCNEWVEC (char, highest_outgoing_arg_in_use);
                  stack_usage_map = stack_usage_map_buf;
-                 memset (stack_usage_map, 0, highest_outgoing_arg_in_use);
                  highest_outgoing_arg_in_use = 0;
                }
              allocate_dynamic_stack_space (push_size, NULL_RTX,
@@ -2517,18 +2602,31 @@ expand_call (tree exp, rtx target, int ignore)
        {
          if (pcc_struct_value)
            valreg = hard_function_value (build_pointer_type (TREE_TYPE (exp)),
-                                         fndecl, (pass == 0));
+                                         fndecl, NULL, (pass == 0));
          else
-           valreg = hard_function_value (TREE_TYPE (exp), fndecl, (pass == 0));
+           valreg = hard_function_value (TREE_TYPE (exp), fndecl, fntype,
+                                         (pass == 0));
+
+         /* If VALREG is a PARALLEL whose first member has a zero
+            offset, use that.  This is for targets such as m68k that
+            return the same value in multiple places.  */
+         if (GET_CODE (valreg) == PARALLEL)
+           {
+             rtx elem = XVECEXP (valreg, 0, 0);
+             rtx where = XEXP (elem, 0);
+             rtx offset = XEXP (elem, 1);
+             if (offset == const0_rtx
+                 && GET_MODE (where) == GET_MODE (valreg))
+               valreg = where;
+           }
        }
 
       /* Precompute all register parameters.  It isn't safe to compute anything
         once we have started filling any specific hard regs.  */
       precompute_register_parameters (num_actuals, args, &reg_parm_seen);
 
-      if (TREE_OPERAND (exp, 2))
-       static_chain_value = expand_expr (TREE_OPERAND (exp, 2),
-                                         NULL_RTX, VOIDmode, 0);
+      if (CALL_EXPR_STATIC_CHAIN (exp))
+       static_chain_value = expand_normal (CALL_EXPR_STATIC_CHAIN (exp));
       else
        static_chain_value = 0;
 
@@ -2601,11 +2699,9 @@ expand_call (tree exp, rtx target, int ignore)
       /* If register arguments require space on the stack and stack space
         was not preallocated, allocate stack space here for arguments
         passed in registers.  */
-#ifdef OUTGOING_REG_PARM_STACK_SPACE
-      if (!ACCUMULATE_OUTGOING_ARGS
+      if (OUTGOING_REG_PARM_STACK_SPACE && !ACCUMULATE_OUTGOING_ARGS
          && must_preallocate == 0 && reg_parm_stack_space > 0)
        anti_adjust_stack (GEN_INT (reg_parm_stack_space));
-#endif
 
       /* Pass the function the address in which to return a
         structure value.  */
@@ -2680,7 +2776,7 @@ expand_call (tree exp, rtx target, int ignore)
          rtx insn;
          bool failed = valreg == 0 || GET_CODE (valreg) == PARALLEL;
 
-          insns = get_insns ();
+         insns = get_insns ();
 
          /* Expansion of block moves possibly introduced a loop that may
             not appear inside libcall block.  */
@@ -2839,19 +2935,50 @@ expand_call (tree exp, rtx target, int ignore)
               && GET_MODE (target) == TYPE_MODE (TREE_TYPE (exp))
               && GET_MODE (target) == GET_MODE (valreg))
        {
-         /* TARGET and VALREG cannot be equal at this point because the
-            latter would not have REG_FUNCTION_VALUE_P true, while the
-            former would if it were referring to the same register.
-
-            If they refer to the same register, this move will be a no-op,
-            except when function inlining is being done.  */
-         emit_move_insn (target, valreg);
-
-         /* If we are setting a MEM, this code must be executed.  Since it is
-            emitted after the call insn, sibcall optimization cannot be
-            performed in that case.  */
-         if (MEM_P (target))
-           sibcall_failure = 1;
+         bool may_overlap = false;
+
+         /* We have to copy a return value in a CLASS_LIKELY_SPILLED hard
+            reg to a plain register.  */
+         if (REG_P (valreg)
+             && HARD_REGISTER_P (valreg)
+             && CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (REGNO (valreg)))
+             && !(REG_P (target) && !HARD_REGISTER_P (target)))
+           valreg = copy_to_reg (valreg);
+
+         /* If TARGET is a MEM in the argument area, and we have
+            saved part of the argument area, then we can't store
+            directly into TARGET as it may get overwritten when we
+            restore the argument save area below.  Don't work too
+            hard though and simply force TARGET to a register if it
+            is a MEM; the optimizer is quite likely to sort it out.  */
+         if (ACCUMULATE_OUTGOING_ARGS && pass && MEM_P (target))
+           for (i = 0; i < num_actuals; i++)
+             if (args[i].save_area)
+               {
+                 may_overlap = true;
+                 break;
+               }
+
+         if (may_overlap)
+           target = copy_to_reg (valreg);
+         else
+           {
+             /* TARGET and VALREG cannot be equal at this point
+                because the latter would not have
+                REG_FUNCTION_VALUE_P true, while the former would if
+                it were referring to the same register.
+
+                If they refer to the same register, this move will be
+                a no-op, except when function inlining is being
+                done.  */
+             emit_move_insn (target, valreg);
+
+             /* If we are setting a MEM, this code must be executed.
+                Since it is emitted after the call insn, sibcall
+                optimization cannot be performed in that case.  */
+             if (MEM_P (target))
+               sibcall_failure = 1;
+           }
        }
       else if (TYPE_MODE (TREE_TYPE (exp)) == BLKmode)
        {
@@ -2875,11 +3002,11 @@ expand_call (tree exp, rtx target, int ignore)
              int unsignedp = TYPE_UNSIGNED (type);
              int offset = 0;
              enum machine_mode pmode;
-             
+
              pmode = promote_mode (type, TYPE_MODE (type), &unsignedp, 1);
              /* If we don't promote as expected, something is wrong.  */
              gcc_assert (GET_MODE (target) == pmode);
-             
+
              if ((WORDS_BIG_ENDIAN || BYTES_BIG_ENDIAN)
                  && (GET_MODE_SIZE (GET_MODE (target))
                      > GET_MODE_SIZE (TYPE_MODE (type))))
@@ -3041,79 +3168,20 @@ fixup_tail_calls (void)
 
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
     {
+      rtx note;
+
       /* There are never REG_EQUIV notes for the incoming arguments
         after the NOTE_INSN_FUNCTION_BEG note, so stop if we see it.  */
       if (NOTE_P (insn)
          && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG)
        break;
 
-      while (1)
-       {
-         rtx note = find_reg_note (insn, REG_EQUIV, 0);
-         if (note)
-           {
-             /* Remove the note and keep looking at the notes for
-                this insn.  */
-             remove_note (insn, note);
-             continue;
-           }
-         break;
-       }
-    }
-}
-
-/* Traverse an argument list in VALUES and expand all complex
-   arguments into their components.  */
-static tree
-split_complex_values (tree values)
-{
-  tree p;
-
-  /* Before allocating memory, check for the common case of no complex.  */
-  for (p = values; p; p = TREE_CHAIN (p))
-    {
-      tree type = TREE_TYPE (TREE_VALUE (p));
-      if (type && TREE_CODE (type) == COMPLEX_TYPE
-         && targetm.calls.split_complex_arg (type))
-        goto found;
-    }
-  return values;
-
- found:
-  values = copy_list (values);
-
-  for (p = values; p; p = TREE_CHAIN (p))
-    {
-      tree complex_value = TREE_VALUE (p);
-      tree complex_type;
-
-      complex_type = TREE_TYPE (complex_value);
-      if (!complex_type)
-       continue;
-
-      if (TREE_CODE (complex_type) == COMPLEX_TYPE
-         && targetm.calls.split_complex_arg (complex_type))
-       {
-         tree subtype;
-         tree real, imag, next;
-
-         subtype = TREE_TYPE (complex_type);
-         complex_value = save_expr (complex_value);
-         real = build1 (REALPART_EXPR, subtype, complex_value);
-         imag = build1 (IMAGPART_EXPR, subtype, complex_value);
-
-         TREE_VALUE (p) = real;
-         next = TREE_CHAIN (p);
-         imag = build_tree_list (NULL_TREE, imag);
-         TREE_CHAIN (p) = imag;
-         TREE_CHAIN (imag) = next;
-
-         /* Skip the newly created node.  */
-         p = TREE_CHAIN (p);
-       }
+      note = find_reg_note (insn, REG_EQUIV, 0);
+      if (note)
+       remove_note (insn, note);
+      note = find_reg_note (insn, REG_EQUIV, 0);
+      gcc_assert (!note);
     }
-
-  return values;
 }
 
 /* Traverse a list of TYPES and expand all complex types into their
@@ -3129,7 +3197,7 @@ split_complex_types (tree types)
       tree type = TREE_VALUE (p);
       if (TREE_CODE (type) == COMPLEX_TYPE
          && targetm.calls.split_complex_arg (type))
-        goto found;
+       goto found;
     }
   return types;
 
@@ -3266,7 +3334,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
        {
 #ifdef PCC_STATIC_STRUCT_RETURN
          rtx pointer_reg
-           = hard_function_value (build_pointer_type (tfom), 0, 0);
+           = hard_function_value (build_pointer_type (tfom), 0, 0, 0);
          mem_value = gen_rtx_MEM (outmode, pointer_reg);
          pcc_struct_value = 1;
          if (value == 0)
@@ -3320,7 +3388,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
   if (mem_value && struct_value == 0 && ! pcc_struct_value)
     {
       rtx addr = XEXP (mem_value, 0);
-      
+
       nargs++;
 
       /* Make sure it is a reasonable operand for a move or push insn.  */
@@ -3338,7 +3406,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
 
       locate_and_pad_parm (Pmode, NULL_TREE,
 #ifdef STACK_PARMS_IN_REG_PARM_AREA
-                           1,
+                          1,
 #else
                           argvec[count].reg != 0,
 #endif
@@ -3455,9 +3523,8 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
   args_size.constant = MAX (args_size.constant,
                            reg_parm_stack_space);
 
-#ifndef OUTGOING_REG_PARM_STACK_SPACE
-  args_size.constant -= reg_parm_stack_space;
-#endif
+  if (!OUTGOING_REG_PARM_STACK_SPACE)
+    args_size.constant -= reg_parm_stack_space;
 
   if (args_size.constant > current_function_outgoing_args_size)
     current_function_outgoing_args_size = args_size.constant;
@@ -3478,12 +3545,11 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
 
       needed = args_size.constant;
 
-#ifndef OUTGOING_REG_PARM_STACK_SPACE
       /* Since we will be writing into the entire argument area, the
         map must be allocated for its entire size, not just the part that
         is the responsibility of the caller.  */
-      needed += reg_parm_stack_space;
-#endif
+      if (!OUTGOING_REG_PARM_STACK_SPACE)
+       needed += reg_parm_stack_space;
 
 #ifdef ARGS_GROW_DOWNWARD
       highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
@@ -3492,7 +3558,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
       highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
                                         needed);
 #endif
-      stack_usage_map_buf = xmalloc (highest_outgoing_arg_in_use);
+      stack_usage_map_buf = XNEWVEC (char, highest_outgoing_arg_in_use);
       stack_usage_map = stack_usage_map_buf;
 
       if (initial_highest_arg_in_use)
@@ -3505,7 +3571,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
       needed = 0;
 
       /* We must be careful to use virtual regs before they're instantiated,
-         and real regs afterwards.  Loop optimization, for example, can create
+        and real regs afterwards.  Loop optimization, for example, can create
         new libcalls after we've instantiated the virtual regs, and if we
         use virtuals anyway, they won't match the rtl patterns.  */
 
@@ -3602,11 +3668,11 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
                    {
                      argvec[argnum].save_area
                        = assign_stack_temp (BLKmode,
-                                            argvec[argnum].locate.size.constant,
+                                            argvec[argnum].locate.size.constant,
                                             0);
 
                      emit_block_move (validize_mem (argvec[argnum].save_area),
-                                      stack_area,
+                                      stack_area,
                                       GEN_INT (argvec[argnum].locate.size.constant),
                                       BLOCK_OP_CALL_PARM);
                    }
@@ -3631,6 +3697,28 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
              stack_usage_map[i] = 1;
 
          NO_DEFER_POP;
+
+         if (flags & ECF_CONST)
+           {
+             rtx use;
+
+             /* Indicate argument access so that alias.c knows that these
+                values are live.  */
+             if (argblock)
+               use = plus_constant (argblock,
+                                    argvec[argnum].locate.offset.constant);
+             else
+               /* When arguments are pushed, trying to tell alias.c where
+                  exactly this argument is won't work, because the
+                  auto-increment causes confusion.  So we merely indicate
+                  that we access something with a known mode somewhere on
+                  the stack.  */
+               use = gen_rtx_PLUS (Pmode, virtual_outgoing_args_rtx,
+                                   gen_rtx_SCRATCH (Pmode));
+             use = gen_rtx_MEM (argvec[argnum].mode, use);
+             use = gen_rtx_USE (VOIDmode, use);
+             call_fusage = gen_rtx_EXPR_LIST (VOIDmode, use, call_fusage);
+           }
        }
     }
 
@@ -3675,7 +3763,18 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
       if (reg != 0 && GET_CODE (reg) == PARALLEL)
        use_group_regs (&call_fusage, reg);
       else if (reg != 0)
-       use_reg (&call_fusage, reg);
+        {
+         int partial = argvec[count].partial;
+         if (partial)
+           {
+             int nregs;
+              gcc_assert (partial % UNITS_PER_WORD == 0);
+             nregs = partial / UNITS_PER_WORD;
+             use_regs (&call_fusage, REGNO (reg), nregs);
+           }
+         else
+           use_reg (&call_fusage, reg);
+       }
     }
 
   /* Pass the function the address in which to return a structure value.  */
@@ -3810,10 +3909,25 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
            value = gen_reg_rtx (outmode);
          emit_group_store (value, valreg, NULL_TREE, GET_MODE_SIZE (outmode));
        }
-      else if (value != 0)
-       emit_move_insn (value, valreg);
       else
-       value = valreg;
+       {
+         /* Convert to the proper mode if PROMOTE_MODE has been active.  */
+         if (GET_MODE (valreg) != outmode)
+           {
+             int unsignedp = TYPE_UNSIGNED (tfom);
+
+             gcc_assert (targetm.calls.promote_function_return (tfom));
+             gcc_assert (promote_mode (tfom, outmode, &unsignedp, 0)
+                         == GET_MODE (valreg));
+
+             valreg = convert_modes (outmode, GET_MODE (valreg), valreg, 0);
+           }
+
+         if (value != 0)
+           emit_move_insn (value, valreg);
+         else
+           value = valreg;
+       }
     }
 
   if (ACCUMULATE_OUTGOING_ARGS)
@@ -3836,7 +3950,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
 
            if (save_mode == BLKmode)
              emit_block_move (stack_area,
-                              validize_mem (argvec[count].save_area),
+                              validize_mem (argvec[count].save_area),
                               GEN_INT (argvec[count].locate.size.constant),
                               BLOCK_OP_CALL_PARM);
            else
@@ -3988,7 +4102,7 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags,
                  arg->save_area = assign_temp (nt, 0, 1, 1);
                  preserve_temp_slots (arg->save_area);
                  emit_block_move (validize_mem (arg->save_area), stack_area,
-                                  expr_size (arg->tree_value),
+                                  GEN_INT (arg->locate.size.constant),
                                   BLOCK_OP_CALL_PARM);
                }
              else
@@ -4014,7 +4128,7 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags,
   /* Being passed entirely in a register.  We shouldn't be called in
      this case.  */
   gcc_assert (reg == 0 || partial != 0);
-  
+
   /* If this arg needs special alignment, don't load the registers
      here.  */
   if (arg->n_aligned_regs != 0)
@@ -4062,6 +4176,13 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags,
        stack_arg_under_construction--;
     }
 
+  /* Check for overlap with already clobbered argument area.  */
+  if ((flags & ECF_SIBCALL)
+      && MEM_P (arg->value)
+      && mem_overlaps_already_clobbered_arg_p (XEXP (arg->value, 0),
+                                              arg->locate.size.constant))
+    sibcall_failure = 1;
+
   /* Don't allow anything left on stack from computation
      of argument to alloca.  */
   if (flags & ECF_MAY_BE_ALLOCA)
@@ -4073,6 +4194,7 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags,
   else if (arg->mode != BLKmode)
     {
       int size;
+      unsigned int parm_align;
 
       /* Argument is a scalar, not entirely passed in registers.
         (If part is passed in registers, arg->partial says how much
@@ -4100,10 +4222,22 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags,
                 / (PARM_BOUNDARY / BITS_PER_UNIT))
                * (PARM_BOUNDARY / BITS_PER_UNIT));
 
+      /* Compute the alignment of the pushed argument.  */
+      parm_align = arg->locate.boundary;
+      if (FUNCTION_ARG_PADDING (arg->mode, TREE_TYPE (pval)) == downward)
+       {
+         int pad = used - size;
+         if (pad)
+           {
+             unsigned int pad_align = (pad & -pad) * BITS_PER_UNIT;
+             parm_align = MIN (parm_align, pad_align);
+           }
+       }
+
       /* This isn't already where we want it on the stack, so put it there.
         This can either be done with push or copy insns.  */
       emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX,
-                     PARM_BOUNDARY, partial, reg, used - size, argblock,
+                     parm_align, partial, reg, used - size, argblock,
                      ARGS_SIZE_RTX (arg->locate.offset), reg_parm_stack_space,
                      ARGS_SIZE_RTX (arg->locate.alignment_pad));