OSDN Git Service

* cp-tree.h (build_lang_field_decl): Remove.
[pf3gnuchains/gcc-fork.git] / gcc / calls.c
index b8f825c..b646be8 100644 (file)
@@ -24,6 +24,7 @@ Boston, MA 02111-1307, USA.  */
 #include "tree.h"
 #include "flags.h"
 #include "expr.h"
+#include "function.h"
 #include "regs.h"
 #include "insn-flags.h"
 #include "toplev.h"
@@ -127,8 +128,8 @@ int stack_arg_under_construction;
 static int calls_function      PROTO ((tree, int));
 static int calls_function_1    PROTO ((tree, int));
 static void emit_call_1                PROTO ((rtx, tree, tree, HOST_WIDE_INT,
-                                       HOST_WIDE_INT, rtx, rtx,
-                                       int, rtx, int));
+                                       HOST_WIDE_INT, HOST_WIDE_INT, rtx,
+                                       rtx, int, rtx, int));
 static void special_function_p PROTO ((char *, tree, int *, int *,
                                        int *, int *));
 static void precompute_register_parameters     PROTO ((int, struct arg_data *,
@@ -137,6 +138,26 @@ static void store_one_arg  PROTO ((struct arg_data *, rtx, int, int,
                                        int));
 static void store_unaligned_arguments_into_pseudos PROTO ((struct arg_data *,
                                                           int));
+static int finalize_must_preallocate           PROTO ((int, int,
+                                                       struct arg_data *,
+                                                       struct args_size *));
+static void precompute_arguments               PROTO ((int, int, int,
+                                                       struct arg_data *,
+                                                       struct args_size *));
+static int compute_argument_block_size         PROTO ((int, 
+                                                       struct args_size *));
+static void initialize_argument_information    PROTO ((int,
+                                                       struct arg_data *,
+                                                       struct args_size *,
+                                                       int, tree, tree,
+                                                       CUMULATIVE_ARGS *,
+                                                       int, rtx *, int *,
+                                                       int *, int *));
+static void compute_argument_addresses         PROTO ((struct arg_data *,
+                                                       rtx, int));
+static rtx rtx_for_function_call               PROTO ((tree, tree));
+static void load_register_parameters           PROTO ((struct arg_data *,
+                                                       int, rtx *));
 
 #if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)
 static rtx save_fixed_argument_area    PROTO ((int, rtx, int *, int *));
@@ -198,8 +219,7 @@ calls_function_1 (exp, which)
          if ((DECL_BUILT_IN (fndecl)
               && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_ALLOCA)
              || (DECL_SAVED_INSNS (fndecl)
-                 && (FUNCTION_FLAGS (DECL_SAVED_INSNS (fndecl))
-                     & FUNCTION_FLAGS_CALLS_ALLOCA)))
+                 && DECL_SAVED_INSNS (fndecl)->calls_alloca))
            return 1;
        }
 
@@ -354,13 +374,14 @@ prepare_call_address (funexp, fndecl, call_fusage, reg_parm_seen)
    IS_CONST is true if this is a `const' call.  */
 
 static void
-emit_call_1 (funexp, fndecl, funtype, stack_size, struct_value_size, 
-             next_arg_reg, valreg, old_inhibit_defer_pop, call_fusage,
-            is_const)
+emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
+            struct_value_size, next_arg_reg, valreg, old_inhibit_defer_pop,
+            call_fusage, is_const)
      rtx funexp;
      tree fndecl ATTRIBUTE_UNUSED;
      tree funtype ATTRIBUTE_UNUSED;
      HOST_WIDE_INT stack_size;
+     HOST_WIDE_INT rounded_stack_size;
      HOST_WIDE_INT struct_value_size;
      rtx next_arg_reg;
      rtx valreg;
@@ -368,11 +389,12 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, struct_value_size,
      rtx call_fusage;
      int is_const;
 {
-  rtx stack_size_rtx = GEN_INT (stack_size);
+  rtx rounded_stack_size_rtx = GEN_INT (rounded_stack_size);
   rtx struct_value_size_rtx = GEN_INT (struct_value_size);
   rtx call_insn;
 #ifndef ACCUMULATE_OUTGOING_ARGS
   int already_popped = 0;
+  HOST_WIDE_INT n_popped = RETURN_POPS_ARGS (fndecl, funtype, stack_size);
 #endif
 
   /* Ensure address is valid.  SYMBOL_REF is already valid, so no need,
@@ -383,11 +405,9 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, struct_value_size,
 
 #ifndef ACCUMULATE_OUTGOING_ARGS
 #if defined (HAVE_call_pop) && defined (HAVE_call_value_pop)
-  if (HAVE_call_pop && HAVE_call_value_pop
-      && (RETURN_POPS_ARGS (fndecl, funtype, stack_size) > 0 
-          || stack_size == 0))
+  if (HAVE_call_pop && HAVE_call_value_pop && n_popped > 0)
     {
-      rtx n_pop = GEN_INT (RETURN_POPS_ARGS (fndecl, funtype, stack_size));
+      rtx n_pop = GEN_INT (n_popped);
       rtx pat;
 
       /* If this subroutine pops its own args, record that in the call insn
@@ -396,10 +416,10 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, struct_value_size,
       if (valreg)
        pat = gen_call_value_pop (valreg,
                                  gen_rtx_MEM (FUNCTION_MODE, funexp),
-                                 stack_size_rtx, next_arg_reg, n_pop);
+                                 rounded_stack_size_rtx, next_arg_reg, n_pop);
       else
        pat = gen_call_pop (gen_rtx_MEM (FUNCTION_MODE, funexp),
-                           stack_size_rtx, next_arg_reg, n_pop);
+                           rounded_stack_size_rtx, next_arg_reg, n_pop);
 
       emit_call_insn (pat);
       already_popped = 1;
@@ -414,11 +434,11 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, struct_value_size,
       if (valreg)
        emit_call_insn (gen_call_value (valreg,
                                        gen_rtx_MEM (FUNCTION_MODE, funexp),
-                                       stack_size_rtx, next_arg_reg,
+                                       rounded_stack_size_rtx, next_arg_reg,
                                        NULL_RTX));
       else
        emit_call_insn (gen_call (gen_rtx_MEM (FUNCTION_MODE, funexp),
-                                 stack_size_rtx, next_arg_reg,
+                                 rounded_stack_size_rtx, next_arg_reg,
                                  struct_value_size_rtx));
     }
   else
@@ -465,23 +485,23 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, struct_value_size,
      If returning from the subroutine does pop the args, indicate that the
      stack pointer will be changed.  */
 
-  if (stack_size != 0 && RETURN_POPS_ARGS (fndecl, funtype, stack_size) > 0)
+  if (n_popped > 0)
     {
       if (!already_popped)
        CALL_INSN_FUNCTION_USAGE (call_insn)
          = gen_rtx_EXPR_LIST (VOIDmode,
                               gen_rtx_CLOBBER (VOIDmode, stack_pointer_rtx),
                               CALL_INSN_FUNCTION_USAGE (call_insn));
-      stack_size -= RETURN_POPS_ARGS (fndecl, funtype, stack_size);
-      stack_size_rtx = GEN_INT (stack_size);
+      rounded_stack_size -= n_popped;
+      rounded_stack_size_rtx = GEN_INT (rounded_stack_size);
     }
 
-  if (stack_size != 0)
+  if (rounded_stack_size != 0)
     {
       if (flag_defer_pop && inhibit_defer_pop == 0 && !is_const)
-       pending_stack_adjust += stack_size;
+       pending_stack_adjust += rounded_stack_size;
       else
-       adjust_stack (stack_size_rtx);
+       adjust_stack (rounded_stack_size_rtx);
     }
 #endif
 }
@@ -822,6 +842,675 @@ store_unaligned_arguments_into_pseudos (args, num_actuals)
       }
 }
 
+/* Fill in ARGS_SIZE and ARGS array based on the parameters found in
+   ACTPARMS. 
+
+   NUM_ACTUALS is the total number of parameters.
+
+   N_NAMED_ARGS is the total number of named arguments.
+
+   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
+   the next argument.
+
+   REG_PARM_STACK_SPACE is the number of bytes of stack space reserved
+   for arguments which are passed in registers.
+
+   OLD_STACK_LEVEL is a pointer to an rtx which olds the old stack level
+   and may be modified by this routine.
+
+   OLD_PENDING_ADJ, MUST_PREALLOCATE and IS_CONST are pointers to integer
+   flags which may may be modified by this routine.  */
+
+static void
+initialize_argument_information (num_actuals, args, args_size, n_named_args,
+                                actparms, fndecl, args_so_far,
+                                reg_parm_stack_space, old_stack_level,
+                                old_pending_adj, must_preallocate, is_const)
+     int num_actuals ATTRIBUTE_UNUSED;
+     struct arg_data *args;
+     struct args_size *args_size;
+     int n_named_args ATTRIBUTE_UNUSED;
+     tree actparms;
+     tree fndecl;
+     CUMULATIVE_ARGS *args_so_far;
+     int reg_parm_stack_space;
+     rtx *old_stack_level;
+     int *old_pending_adj;
+     int *must_preallocate;
+     int *is_const;
+{
+  /* 1 if scanning parms front to back, -1 if scanning back to front.  */
+  int inc;
+
+  /* Count arg position in order args appear.  */
+  int argpos;
+
+  int i;
+  tree p;
+  
+  args_size->constant = 0;
+  args_size->var = 0;
+
+  /* In this loop, we consider args in the order they are written.
+     We fill up ARGS from the front or from the back if necessary
+     so that in any case the first arg to be pushed ends up at the front.  */
+
+#ifdef PUSH_ARGS_REVERSED
+  i = num_actuals - 1, inc = -1;
+  /* In this case, must reverse order of args
+     so that we compute and push the last arg first.  */
+#else
+  i = 0, inc = 1;
+#endif
+
+  /* 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++)
+    {
+      tree type = TREE_TYPE (TREE_VALUE (p));
+      int unsignedp;
+      enum machine_mode mode;
+
+      args[i].tree_value = TREE_VALUE (p);
+
+      /* Replace erroneous argument with constant zero.  */
+      if (type == error_mark_node || TYPE_SIZE (type) == 0)
+       args[i].tree_value = integer_zero_node, type = integer_type_node;
+
+      /* If TYPE is a transparent union, pass things the way we would
+        pass the first field of the union.  We have already verified that
+        the modes are the same.  */
+      if (TYPE_TRANSPARENT_UNION (type))
+       type = TREE_TYPE (TYPE_FIELDS (type));
+
+      /* Decide where to pass this arg.
+
+        args[i].reg is nonzero if all or part is passed in registers.
+
+        args[i].partial is nonzero if part but not all is passed in registers,
+        and the exact value says how many words are passed in registers.
+
+        args[i].pass_on_stack is nonzero if the argument must at least be
+        computed on the stack.  It may then be loaded back into registers
+        if args[i].reg is nonzero.
+
+        These decisions are driven by the FUNCTION_... macros and must agree
+        with those made by function.c.  */
+
+      /* See if this argument should be passed by invisible reference.  */
+      if ((TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST
+          && contains_placeholder_p (TYPE_SIZE (type)))
+         || TREE_ADDRESSABLE (type)
+#ifdef FUNCTION_ARG_PASS_BY_REFERENCE
+         || FUNCTION_ARG_PASS_BY_REFERENCE (*args_so_far, TYPE_MODE (type),
+                                            type, argpos < n_named_args)
+#endif
+         )
+       {
+         /* If we're compiling a thunk, pass through invisible
+             references instead of making a copy.  */
+         if (current_function_is_thunk
+#ifdef FUNCTION_ARG_CALLEE_COPIES
+             || (FUNCTION_ARG_CALLEE_COPIES (*args_so_far, TYPE_MODE (type),
+                                            type, argpos < n_named_args)
+                 /* If it's in a register, we must make a copy of it too.  */
+                 /* ??? Is this a sufficient test?  Is there a better one? */
+                 && !(TREE_CODE (args[i].tree_value) == VAR_DECL
+                      && REG_P (DECL_RTL (args[i].tree_value)))
+                 && ! TREE_ADDRESSABLE (type))
+#endif
+             )
+           {
+             /* C++ uses a TARGET_EXPR to indicate that we want to make a
+                new object from the argument.  If we are passing by
+                invisible reference, the callee will do that for us, so we
+                can strip off the TARGET_EXPR.  This is not always safe,
+                but it is safe in the only case where this is a useful
+                optimization; namely, when the argument is a plain object.
+                In that case, the frontend is just asking the backend to
+                make a bitwise copy of the argument. */
+                
+             if (TREE_CODE (args[i].tree_value) == TARGET_EXPR
+                 && (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND
+                                                 (args[i].tree_value, 1)))
+                     == 'd')
+                 && ! REG_P (DECL_RTL (TREE_OPERAND (args[i].tree_value, 1))))
+               args[i].tree_value = TREE_OPERAND (args[i].tree_value, 1);
+
+             args[i].tree_value = build1 (ADDR_EXPR,
+                                          build_pointer_type (type),
+                                          args[i].tree_value);
+             type = build_pointer_type (type);
+           }
+         else
+           {
+             /* We make a copy of the object and pass the address to the
+                function being called.  */
+             rtx copy;
+
+             if (TYPE_SIZE (type) == 0
+                 || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST
+                 || (flag_stack_check && ! STACK_CHECK_BUILTIN
+                     && (TREE_INT_CST_HIGH (TYPE_SIZE (type)) != 0
+                         || (TREE_INT_CST_LOW (TYPE_SIZE (type))
+                             > STACK_CHECK_MAX_VAR_SIZE * BITS_PER_UNIT))))
+               {
+                 /* This is a variable-sized object.  Make space on the stack
+                    for it.  */
+                 rtx size_rtx = expr_size (TREE_VALUE (p));
+
+                 if (*old_stack_level == 0)
+                   {
+                     emit_stack_save (SAVE_BLOCK, old_stack_level, NULL_RTX);
+                     *old_pending_adj = pending_stack_adjust;
+                     pending_stack_adjust = 0;
+                   }
+
+                 copy = gen_rtx_MEM (BLKmode,
+                                     allocate_dynamic_stack_space (size_rtx,
+                                                                   NULL_RTX,
+                                                                   TYPE_ALIGN (type)));
+               }
+             else
+               {
+                 int size = int_size_in_bytes (type);
+                 copy = assign_stack_temp (TYPE_MODE (type), size, 0);
+               }
+
+             MEM_SET_IN_STRUCT_P (copy, AGGREGATE_TYPE_P (type));
+
+             store_expr (args[i].tree_value, copy, 0);
+             *is_const = 0;
+
+             args[i].tree_value = build1 (ADDR_EXPR,
+                                          build_pointer_type (type),
+                                          make_tree (type, copy));
+             type = build_pointer_type (type);
+           }
+       }
+
+      mode = TYPE_MODE (type);
+      unsignedp = TREE_UNSIGNED (type);
+
+#ifdef PROMOTE_FUNCTION_ARGS
+      mode = promote_mode (type, mode, &unsignedp, 1);
+#endif
+
+      args[i].unsignedp = unsignedp;
+      args[i].mode = mode;
+      args[i].reg = FUNCTION_ARG (*args_so_far, mode, type,
+                                 argpos < n_named_args);
+#ifdef FUNCTION_ARG_PARTIAL_NREGS
+      if (args[i].reg)
+       args[i].partial
+         = FUNCTION_ARG_PARTIAL_NREGS (*args_so_far, mode, type,
+                                       argpos < n_named_args);
+#endif
+
+      args[i].pass_on_stack = MUST_PASS_IN_STACK (mode, type);
+
+      /* If FUNCTION_ARG returned a (parallel [(expr_list (nil) ...) ...]),
+        it means that we are to pass this arg in the register(s) designated
+        by the PARALLEL, but also to pass it in the stack.  */
+      if (args[i].reg && GET_CODE (args[i].reg) == PARALLEL
+         && XEXP (XVECEXP (args[i].reg, 0, 0), 0) == 0)
+       args[i].pass_on_stack = 1;
+
+      /* If this is an addressable type, we must preallocate the stack
+        since we must evaluate the object into its final location.
+
+        If this is to be passed in both registers and the stack, it is simpler
+        to preallocate.  */
+      if (TREE_ADDRESSABLE (type)
+         || (args[i].pass_on_stack && args[i].reg != 0))
+       *must_preallocate = 1;
+
+      /* If this is an addressable type, we cannot pre-evaluate it.  Thus,
+        we cannot consider this function call constant.  */
+      if (TREE_ADDRESSABLE (type))
+       *is_const = 0;
+
+      /* Compute the stack-size of this argument.  */
+      if (args[i].reg == 0 || args[i].partial != 0
+         || reg_parm_stack_space > 0
+         || args[i].pass_on_stack)
+       locate_and_pad_parm (mode, type,
+#ifdef STACK_PARMS_IN_REG_PARM_AREA
+                            1,
+#else
+                            args[i].reg != 0,
+#endif
+                            fndecl, args_size, &args[i].offset,
+                            &args[i].size);
+
+#ifndef ARGS_GROW_DOWNWARD
+      args[i].slot_offset = *args_size;
+#endif
+
+      /* If a part of the arg was put into registers,
+        don't include that part in the amount pushed.  */
+      if (reg_parm_stack_space == 0 && ! args[i].pass_on_stack)
+       args[i].size.constant -= ((args[i].partial * UNITS_PER_WORD)
+                                 / (PARM_BOUNDARY / BITS_PER_UNIT)
+                                 * (PARM_BOUNDARY / BITS_PER_UNIT));
+      
+      /* Update ARGS_SIZE, the total stack space for args so far.  */
+
+      args_size->constant += args[i].size.constant;
+      if (args[i].size.var)
+       {
+         ADD_PARM_SIZE (*args_size, args[i].size.var);
+       }
+
+      /* Since the slot offset points to the bottom of the slot,
+        we must record it after incrementing if the args grow down.  */
+#ifdef ARGS_GROW_DOWNWARD
+      args[i].slot_offset = *args_size;
+
+      args[i].slot_offset.constant = -args_size->constant;
+      if (args_size->var)
+       {
+         SUB_PARM_SIZE (args[i].slot_offset, args_size->var);
+       }
+#endif
+
+      /* Increment ARGS_SO_FAR, which has info about which arg-registers
+        have been used, etc.  */
+
+      FUNCTION_ARG_ADVANCE (*args_so_far, TYPE_MODE (type), type,
+                           argpos < n_named_args);
+    }
+}
+
+/* Update ARGS_SIZE to contain the total size for the argument block.
+   Return the original constant component of the argument block's size.
+
+   REG_PARM_STACK_SPACE holds the number of bytes of stack space reserved
+   for arguments passed in registers.  */
+
+static int
+compute_argument_block_size (reg_parm_stack_space, args_size)
+     int reg_parm_stack_space;
+     struct args_size *args_size;
+{
+  int unadjusted_args_size = args_size->constant;
+
+  /* Compute the actual size of the argument block required.  The variable
+     and constant sizes must be combined, the size may have to be rounded,
+     and there may be a minimum required size.  */
+
+  if (args_size->var)
+    {
+      args_size->var = ARGS_SIZE_TREE (*args_size);
+      args_size->constant = 0;
+
+#ifdef PREFERRED_STACK_BOUNDARY
+      if (PREFERRED_STACK_BOUNDARY != BITS_PER_UNIT)
+       args_size->var = round_up (args_size->var, STACK_BYTES);
+#endif
+
+      if (reg_parm_stack_space > 0)
+       {
+         args_size->var
+           = size_binop (MAX_EXPR, args_size->var,
+                         size_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,
+                         size_int (reg_parm_stack_space));
+#endif
+       }
+    }
+  else
+    {
+#ifdef PREFERRED_STACK_BOUNDARY
+      args_size->constant = (((args_size->constant
+                              + pending_stack_adjust
+                              + STACK_BYTES - 1)
+                             / STACK_BYTES * STACK_BYTES)
+                            - pending_stack_adjust);
+#endif
+
+      args_size->constant = MAX (args_size->constant,
+                                reg_parm_stack_space);
+
+#ifdef MAYBE_REG_PARM_STACK_SPACE
+      if (reg_parm_stack_space == 0)
+       args_size->constant = 0;
+#endif
+
+#ifndef OUTGOING_REG_PARM_STACK_SPACE
+      args_size->constant -= reg_parm_stack_space;
+#endif
+    }
+  return unadjusted_args_size;
+}
+
+/* Precompute parameters has needed for a function call.
+
+   IS_CONST indicates the target function is a pure function.
+
+   MUST_PREALLOCATE indicates that we must preallocate stack space for
+   any stack arguments.
+
+   NUM_ACTUALS is the number of arguments.
+
+   ARGS is an array containing information for each argument; this routine
+   fills in the INITIAL_VALUE and VALUE fields for each precomputed argument.
+
+   ARGS_SIZE contains information about the size of the arg list.  */
+
+static void
+precompute_arguments (is_const, must_preallocate, num_actuals, args, args_size)
+     int is_const;
+     int must_preallocate;
+     int num_actuals;
+     struct arg_data *args;
+     struct args_size *args_size;
+{
+  int i;
+
+  /* If this function call is cse'able, precompute all the parameters.
+     Note that if the parameter is constructed into a temporary, this will
+     cause an additional copy because the parameter will be constructed
+     into a temporary location and then copied into the outgoing arguments.
+     If a parameter contains a call to alloca and this function uses the
+     stack, precompute the parameter.  */
+
+  /* If we preallocated the stack space, and some arguments must be passed
+     on the stack, then we must precompute any parameter which contains a
+     function call which will store arguments on the stack.
+     Otherwise, evaluating the parameter may clobber previous parameters
+     which have already been stored into the stack.  */
+
+  for (i = 0; i < num_actuals; i++)
+    if (is_const
+       || ((args_size->var != 0 || args_size->constant != 0)
+           && calls_function (args[i].tree_value, 1))
+       || (must_preallocate
+           && (args_size->var != 0 || args_size->constant != 0)
+           && calls_function (args[i].tree_value, 0)))
+      {
+       /* If this is an addressable type, we cannot pre-evaluate it.  */
+       if (TREE_ADDRESSABLE (TREE_TYPE (args[i].tree_value)))
+         abort ();
+
+       push_temp_slots ();
+
+       args[i].initial_value = args[i].value
+         = expand_expr (args[i].tree_value, NULL_RTX, VOIDmode, 0);
+
+       preserve_temp_slots (args[i].value);
+       pop_temp_slots ();
+
+       /* ANSI doesn't require a sequence point here,
+          but PCC has one, so this will avoid some problems.  */
+       emit_queue ();
+
+       args[i].initial_value = args[i].value
+         = protect_from_queue (args[i].initial_value, 0);
+
+       if (TYPE_MODE (TREE_TYPE (args[i].tree_value)) != args[i].mode)
+         args[i].value
+           = convert_modes (args[i].mode, 
+                            TYPE_MODE (TREE_TYPE (args[i].tree_value)),
+                            args[i].value, args[i].unsignedp);
+      }
+}
+
+/* Given the current state of MUST_PREALLOCATE and information about
+   arguments to a function call in NUM_ACTUALS, ARGS and ARGS_SIZE,
+   compute and return the final value for MUST_PREALLOCATE.  */
+
+static int
+finalize_must_preallocate (must_preallocate, num_actuals, args, args_size)
+     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.
+
+     If we would have to push a partially-in-regs parm
+     before other stack parms, preallocate stack space instead.
+
+     If the size of some parm is not a multiple of the required stack
+     alignment, we must preallocate.
+
+     If the total size of arguments that would otherwise create a copy in
+     a temporary (such as a CALL) is more than half the total argument list
+     size, preallocation is faster.
+
+     Another reason to preallocate is if we have a machine (like the m88k)
+     where stack alignment is required to be maintained between every
+     pair of insns, not just when the call is made.  However, we assume here
+     that such machines either do not have push insns (and hence preallocation
+     would occur anyway) or the problem is taken care of with
+     PUSH_ROUNDING.  */
+
+  if (! must_preallocate)
+    {
+      int partial_seen = 0;
+      int copy_to_evaluate_size = 0;
+      int i;
+
+      for (i = 0; i < num_actuals && ! must_preallocate; i++)
+       {
+         if (args[i].partial > 0 && ! args[i].pass_on_stack)
+           partial_seen = 1;
+         else if (partial_seen && args[i].reg == 0)
+           must_preallocate = 1;
+
+         if (TYPE_MODE (TREE_TYPE (args[i].tree_value)) == BLKmode
+             && (TREE_CODE (args[i].tree_value) == CALL_EXPR
+                 || TREE_CODE (args[i].tree_value) == TARGET_EXPR
+                 || TREE_CODE (args[i].tree_value) == COND_EXPR
+                 || TREE_ADDRESSABLE (TREE_TYPE (args[i].tree_value))))
+           copy_to_evaluate_size
+             += int_size_in_bytes (TREE_TYPE (args[i].tree_value));
+       }
+
+      if (copy_to_evaluate_size * 2 >= args_size->constant
+         && args_size->constant > 0)
+       must_preallocate = 1;
+    }
+  return must_preallocate;
+}
+
+/* If we preallocated stack space, compute the address of each argument
+   and store it into the ARGS array.
+
+   We need not ensure it is a valid memory address here; it will be 
+   validized when it is used.
+
+   ARGBLOCK is an rtx for the address of the outgoing arguments.  */
+
+static void
+compute_argument_addresses (args, argblock, num_actuals)
+     struct arg_data *args;
+     rtx argblock;
+     int num_actuals;
+{
+  if (argblock)
+    {
+      rtx arg_reg = argblock;
+      int i, arg_offset = 0;
+
+      if (GET_CODE (argblock) == PLUS)
+       arg_reg = XEXP (argblock, 0), arg_offset = INTVAL (XEXP (argblock, 1));
+
+      for (i = 0; i < num_actuals; i++)
+       {
+         rtx offset = ARGS_SIZE_RTX (args[i].offset);
+         rtx slot_offset = ARGS_SIZE_RTX (args[i].slot_offset);
+         rtx addr;
+
+         /* Skip this parm if it will not be passed on the stack.  */
+         if (! args[i].pass_on_stack && args[i].reg != 0)
+           continue;
+
+         if (GET_CODE (offset) == CONST_INT)
+           addr = plus_constant (arg_reg, INTVAL (offset));
+         else
+           addr = gen_rtx_PLUS (Pmode, arg_reg, offset);
+
+         addr = plus_constant (addr, arg_offset);
+         args[i].stack = gen_rtx_MEM (args[i].mode, addr);
+         MEM_SET_IN_STRUCT_P 
+           (args[i].stack,
+            AGGREGATE_TYPE_P (TREE_TYPE (args[i].tree_value)));
+
+         if (GET_CODE (slot_offset) == CONST_INT)
+           addr = plus_constant (arg_reg, INTVAL (slot_offset));
+         else
+           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);
+       }
+    }
+}
+                                              
+/* Given a FNDECL and EXP, return an rtx suitable for use as a target address
+   in a call instruction.
+
+   FNDECL is the tree node for the target function.  For an indirect call
+   FNDECL will be NULL_TREE.
+
+   EXP is the CALL_EXPR for this call.  */
+
+static rtx
+rtx_for_function_call (fndecl, exp)
+     tree fndecl;
+     tree exp;
+{
+  rtx funexp;
+
+  /* Get the function to call, in the form of RTL.  */
+  if (fndecl)
+    {
+      /* If this is the first use of the function, see if we need to
+        make an external definition for it.  */
+      if (! TREE_USED (fndecl))
+       {
+         assemble_external (fndecl);
+         TREE_USED (fndecl) = 1;
+       }
+
+      /* Get a SYMBOL_REF rtx for the function address.  */
+      funexp = XEXP (DECL_RTL (fndecl), 0);
+    }
+  else
+    /* Generate an rtx (probably a pseudo-register) for the address.  */
+    {
+      rtx funaddr;
+      push_temp_slots ();
+      funaddr = funexp = 
+         expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
+      pop_temp_slots ();       /* FUNEXP can't be BLKmode */
+
+      /* Check the function is executable.  */
+      if (current_function_check_memory_usage)
+       {
+#ifdef POINTERS_EXTEND_UNSIGNED
+         /* It might be OK to convert funexp in place, but there's
+            a lot going on between here and when it happens naturally
+            that this seems safer. */
+          funaddr = convert_memory_address (Pmode, funexp);
+#endif
+         emit_library_call (chkr_check_exec_libfunc, 1,
+                            VOIDmode, 1,
+                            funaddr, Pmode);
+       }
+      emit_queue ();
+    }
+  return funexp;
+}
+
+/* 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. 
+
+   Mark all register-parms as living through the call, putting these USE
+   insns in the CALL_INSN_FUNCTION_USAGE field.  */
+
+static void
+load_register_parameters (args, num_actuals, call_fusage)
+     struct arg_data *args;
+     int num_actuals;
+     rtx *call_fusage;
+{
+  int i, j;
+
+#ifdef LOAD_ARGS_REVERSED
+  for (i = num_actuals - 1; i >= 0; i--)
+#else
+  for (i = 0; i < num_actuals; i++)
+#endif
+    {
+      rtx reg = args[i].reg;
+      int partial = args[i].partial;
+      int nregs;
+
+      if (reg)
+       {
+         /* Set to non-negative if must move a word at a time, even if just
+            one word (e.g, partial == 1 && mode == DFmode).  Set to -1 if
+            we just use a normal move insn.  This value can be zero if the
+            argument is a zero size structure with no fields.  */
+         nregs = (partial ? partial
+                  : (TYPE_MODE (TREE_TYPE (args[i].tree_value)) == BLKmode
+                     ? ((int_size_in_bytes (TREE_TYPE (args[i].tree_value))
+                         + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
+                     : -1));
+
+         /* Handle calls that pass values in multiple non-contiguous
+            locations.  The Irix 6 ABI has examples of this.  */
+
+         if (GET_CODE (reg) == PARALLEL)
+           {
+             emit_group_load (reg, args[i].value,
+                              int_size_in_bytes (TREE_TYPE (args[i].tree_value)),
+                              (TYPE_ALIGN (TREE_TYPE (args[i].tree_value))
+                               / BITS_PER_UNIT));
+           }
+
+         /* If simple case, just do move.  If normal partial, store_one_arg
+            has already loaded the register for us.  In all other cases,
+            load the register(s) from memory.  */
+
+         else if (nregs == -1)
+           emit_move_insn (reg, args[i].value);
+
+         /* If we have pre-computed the values to put in the registers in
+            the case of non-aligned structures, copy them in now.  */
+
+         else if (args[i].n_aligned_regs != 0)
+           for (j = 0; j < args[i].n_aligned_regs; j++)
+             emit_move_insn (gen_rtx_REG (word_mode, REGNO (reg) + j),
+                             args[i].aligned_regs[j]);
+
+         else if (partial == 0 || args[i].pass_on_stack)
+           move_block_to_reg (REGNO (reg),
+                              validize_mem (args[i].value), nregs,
+                              args[i].mode);
+
+         /* Handle calls that pass values in multiple non-contiguous
+            locations.  The Irix 6 ABI has examples of this.  */
+         if (GET_CODE (reg) == PARALLEL)
+           use_group_regs (call_fusage, reg);
+         else if (nregs == -1)
+           use_reg (call_fusage, reg);
+         else
+           use_regs (call_fusage, REGNO (reg), nregs == 0 ? 1 : nregs);
+       }
+    }
+}
+
 /* Generate all the code for a function call
    and return an rtx for its value.
    Store the value in TARGET (specified as an rtx) if convenient.
@@ -868,8 +1557,6 @@ expand_call (exp, target, ignore)
   /* Number of named args.  Args after this are anonymous ones
      and they must all go on the stack.  */
   int n_named_args;
-  /* Count arg position in order args appear.  */
-  int argpos;
 
   /* Vector of information about each argument.
      Arguments are numbered in the order they will be pushed,
@@ -879,7 +1566,7 @@ expand_call (exp, target, ignore)
   /* Total size in bytes of all the stack-parms scanned so far.  */
   struct args_size args_size;
   /* Size of arguments before any adjustments (such as rounding).  */
-  struct args_size original_args_size;
+  int unadjusted_args_size;
   /* Data on reg parms scanned so far.  */
   CUMULATIVE_ARGS args_so_far;
   /* Nonzero if a reg parm has been scanned.  */
@@ -901,8 +1588,6 @@ expand_call (exp, target, ignore)
   /* Size of the stack reserved for parameter registers.  */
   int reg_parm_stack_space = 0;
 
-  /* 1 if scanning parms front to back, -1 if scanning back to front.  */
-  int inc;
   /* Address of space preallocated for stack parms
      (on machines that lack push insns), or 0 if space not preallocated.  */
   rtx argblock = 0;
@@ -940,7 +1625,7 @@ expand_call (exp, target, ignore)
   int old_inhibit_defer_pop = inhibit_defer_pop;
   rtx call_fusage = 0;
   register tree p;
-  register int i, j;
+  register int i;
 
   /* The value of the function call can be put in a hard register.  But
      if -fcheck-memory-usage, code which invokes functions (and thus
@@ -964,7 +1649,7 @@ expand_call (exp, target, ignore)
              && fndecl != current_function_decl
              && DECL_INLINE (fndecl)
              && DECL_SAVED_INSNS (fndecl)
-             && RTX_INTEGRATED_P (DECL_SAVED_INSNS (fndecl)))
+             && DECL_SAVED_INSNS (fndecl)->inlinable)
            is_integrable = 1;
          else if (! TREE_ADDRESSABLE (fndecl))
            {
@@ -1101,11 +1786,11 @@ expand_call (exp, target, ignore)
              rtx insn, seq;
 
              /* Look for a call in the inline function code.
-                If OUTGOING_ARGS_SIZE (DECL_SAVED_INSNS (fndecl)) is
+                If DECL_SAVED_INSNS (fndecl)->outgoing_args_size is
                 nonzero then there is a call and it is not necessary
                 to scan the insns.  */
 
-             if (OUTGOING_ARGS_SIZE (DECL_SAVED_INSNS (fndecl)) == 0)
+             if (DECL_SAVED_INSNS (fndecl)->outgoing_args_size == 0)
                for (insn = first_insn; insn; insn = NEXT_INSN (insn))
                  if (GET_CODE (insn) == CALL_INSN)
                    break;
@@ -1129,7 +1814,7 @@ expand_call (exp, target, ignore)
                     value of reg_parm_stack_space is wrong, but gives
                     correct results on all supported machines.  */
 
-                 int adjust = (OUTGOING_ARGS_SIZE (DECL_SAVED_INSNS (fndecl))
+                 int adjust = (DECL_SAVED_INSNS (fndecl)->outgoing_args_size
                                + reg_parm_stack_space);
 
                  start_sequence ();
@@ -1164,11 +1849,6 @@ expand_call (exp, target, ignore)
       mark_addressable (fndecl);
     }
 
-  /* When calling a const function, we must pop the stack args right away,
-     so that the pop is deleted or moved with the call.  */
-  if (is_const)
-    NO_DEFER_POP;
-
   function_call_count++;
 
   if (fndecl && DECL_NAME (fndecl))
@@ -1182,6 +1862,17 @@ expand_call (exp, target, ignore)
   if (may_be_alloca)
     current_function_calls_alloca = 1;
 
+  /* Operand 0 is a pointer-to-function; get the type of the function.  */
+  funtype = TREE_TYPE (TREE_OPERAND (exp, 0));
+  if (! POINTER_TYPE_P (funtype))
+    abort ();
+  funtype = TREE_TYPE (funtype);
+
+  /* When calling a const function, we must pop the stack args right away,
+     so that the pop is deleted or moved with the call.  */
+  if (is_const)
+    NO_DEFER_POP;
+
   /* Don't let pending stack adjusts add up to too much.
      Also, do all pending adjustments now
      if there is any chance this might be a call to alloca.  */
@@ -1190,13 +1881,6 @@ expand_call (exp, target, ignore)
       || (pending_stack_adjust > 0 && may_be_alloca))
     do_pending_stack_adjust ();
 
-  /* Operand 0 is a pointer-to-function; get the type of the function.  */
-  funtype = TREE_TYPE (TREE_OPERAND (exp, 0));
-  if (! POINTER_TYPE_P (funtype))
-    abort ();
-
-  funtype = TREE_TYPE (funtype);
-
   /* Push the temporary stack slot level so that we can free any temporaries
      we make.  */
   push_temp_slots ();
@@ -1244,21 +1928,18 @@ expand_call (exp, target, ignore)
      (If no anonymous args follow, the result of list_length is actually
      one too large.  This is harmless.)
 
-     If SETUP_INCOMING_VARARGS is defined and STRICT_ARGUMENT_NAMING is zero,
-     this machine will be able to place unnamed args that were passed in
+     If PRETEND_OUTGOING_VARARGS_NAMED is set and STRICT_ARGUMENT_NAMING is
+     zero, this machine will be able to place unnamed args that were passed in
      registers into the stack.  So treat all args as named.  This allows the
      insns emitting for a specific argument list to be independent of the
      function declaration.
 
-     If SETUP_INCOMING_VARARGS is not defined, we do not have any reliable
+     If PRETEND_OUTGOING_VARARGS_NAMED is not set, we do not have any reliable
      way to pass unnamed args in registers, so we must force them into
      memory.  */
 
   if ((STRICT_ARGUMENT_NAMING
-#ifndef SETUP_INCOMING_VARARGS
-       || 1
-#endif
-       )
+       || ! PRETEND_OUTGOING_VARARGS_NAMED)
       && TYPE_ARG_TYPES (funtype) != 0)
     n_named_args
       = (list_length (TYPE_ARG_TYPES (funtype))
@@ -1270,252 +1951,23 @@ expand_call (exp, target, ignore)
     /* If we know nothing, treat all args as named.  */
     n_named_args = num_actuals;
 
-  /* Make a vector to hold all the information about each arg.  */
-  args = (struct arg_data *) alloca (num_actuals * sizeof (struct arg_data));
-  bzero ((char *) args, num_actuals * sizeof (struct arg_data));
-
-  args_size.constant = 0;
-  args_size.var = 0;
-
-  /* In this loop, we consider args in the order they are written.
-     We fill up ARGS from the front or from the back if necessary
-     so that in any case the first arg to be pushed ends up at the front.  */
-
-#ifdef PUSH_ARGS_REVERSED
-  i = num_actuals - 1, inc = -1;
-  /* In this case, must reverse order of args
-     so that we compute and push the last arg first.  */
-#else
-  i = 0, inc = 1;
-#endif
-
-  /* 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++)
-    {
-      tree type = TREE_TYPE (TREE_VALUE (p));
-      int unsignedp;
-      enum machine_mode mode;
-
-      args[i].tree_value = TREE_VALUE (p);
-
-      /* Replace erroneous argument with constant zero.  */
-      if (type == error_mark_node || TYPE_SIZE (type) == 0)
-       args[i].tree_value = integer_zero_node, type = integer_type_node;
-
-      /* If TYPE is a transparent union, pass things the way we would
-        pass the first field of the union.  We have already verified that
-        the modes are the same.  */
-      if (TYPE_TRANSPARENT_UNION (type))
-       type = TREE_TYPE (TYPE_FIELDS (type));
-
-      /* Decide where to pass this arg.
-
-        args[i].reg is nonzero if all or part is passed in registers.
-
-        args[i].partial is nonzero if part but not all is passed in registers,
-        and the exact value says how many words are passed in registers.
-
-        args[i].pass_on_stack is nonzero if the argument must at least be
-        computed on the stack.  It may then be loaded back into registers
-        if args[i].reg is nonzero.
-
-        These decisions are driven by the FUNCTION_... macros and must agree
-        with those made by function.c.  */
-
-      /* See if this argument should be passed by invisible reference.  */
-      if ((TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST
-          && contains_placeholder_p (TYPE_SIZE (type)))
-         || TREE_ADDRESSABLE (type)
-#ifdef FUNCTION_ARG_PASS_BY_REFERENCE
-         || FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, TYPE_MODE (type),
-                                            type, argpos < n_named_args)
-#endif
-         )
-       {
-         /* If we're compiling a thunk, pass through invisible
-             references instead of making a copy.  */
-         if (current_function_is_thunk
-#ifdef FUNCTION_ARG_CALLEE_COPIES
-             || (FUNCTION_ARG_CALLEE_COPIES (args_so_far, TYPE_MODE (type),
-                                            type, argpos < n_named_args)
-                 /* If it's in a register, we must make a copy of it too.  */
-                 /* ??? Is this a sufficient test?  Is there a better one? */
-                 && !(TREE_CODE (args[i].tree_value) == VAR_DECL
-                      && REG_P (DECL_RTL (args[i].tree_value)))
-                 && ! TREE_ADDRESSABLE (type))
-#endif
-             )
-           {
-             /* C++ uses a TARGET_EXPR to indicate that we want to make a
-                new object from the argument.  If we are passing by
-                invisible reference, the callee will do that for us, so we
-                can strip off the TARGET_EXPR.  This is not always safe,
-                but it is safe in the only case where this is a useful
-                optimization; namely, when the argument is a plain object.
-                In that case, the frontend is just asking the backend to
-                make a bitwise copy of the argument. */
-                
-             if (TREE_CODE (args[i].tree_value) == TARGET_EXPR
-                 && (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND
-                                                 (args[i].tree_value, 1)))
-                     == 'd')
-                 && ! REG_P (DECL_RTL (TREE_OPERAND (args[i].tree_value, 1))))
-               args[i].tree_value = TREE_OPERAND (args[i].tree_value, 1);
-
-             args[i].tree_value = build1 (ADDR_EXPR,
-                                          build_pointer_type (type),
-                                          args[i].tree_value);
-             type = build_pointer_type (type);
-           }
-         else
-           {
-             /* We make a copy of the object and pass the address to the
-                function being called.  */
-             rtx copy;
-
-             if (TYPE_SIZE (type) == 0
-                 || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST
-                 || (flag_stack_check && ! STACK_CHECK_BUILTIN
-                     && (TREE_INT_CST_HIGH (TYPE_SIZE (type)) != 0
-                         || (TREE_INT_CST_LOW (TYPE_SIZE (type))
-                             > STACK_CHECK_MAX_VAR_SIZE * BITS_PER_UNIT))))
-               {
-                 /* This is a variable-sized object.  Make space on the stack
-                    for it.  */
-                 rtx size_rtx = expr_size (TREE_VALUE (p));
-
-                 if (old_stack_level == 0)
-                   {
-                     emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
-                     old_pending_adj = pending_stack_adjust;
-                     pending_stack_adjust = 0;
-                   }
-
-                 copy = gen_rtx_MEM (BLKmode,
-                                     allocate_dynamic_stack_space (size_rtx,
-                                                                   NULL_RTX,
-                                                                   TYPE_ALIGN (type)));
-               }
-             else
-               {
-                 int size = int_size_in_bytes (type);
-                 copy = assign_stack_temp (TYPE_MODE (type), size, 0);
-               }
-
-             MEM_SET_IN_STRUCT_P (copy, AGGREGATE_TYPE_P (type));
-
-             store_expr (args[i].tree_value, copy, 0);
-             is_const = 0;
-
-             args[i].tree_value = build1 (ADDR_EXPR,
-                                          build_pointer_type (type),
-                                          make_tree (type, copy));
-             type = build_pointer_type (type);
-           }
-       }
-
-      mode = TYPE_MODE (type);
-      unsignedp = TREE_UNSIGNED (type);
-
-#ifdef PROMOTE_FUNCTION_ARGS
-      mode = promote_mode (type, mode, &unsignedp, 1);
-#endif
-
-      args[i].unsignedp = unsignedp;
-      args[i].mode = mode;
-      args[i].reg = FUNCTION_ARG (args_so_far, mode, type,
-                                 argpos < n_named_args);
-#ifdef FUNCTION_ARG_PARTIAL_NREGS
-      if (args[i].reg)
-       args[i].partial
-         = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode, type,
-                                       argpos < n_named_args);
-#endif
-
-      args[i].pass_on_stack = MUST_PASS_IN_STACK (mode, type);
-
-      /* If FUNCTION_ARG returned a (parallel [(expr_list (nil) ...) ...]),
-        it means that we are to pass this arg in the register(s) designated
-        by the PARALLEL, but also to pass it in the stack.  */
-      if (args[i].reg && GET_CODE (args[i].reg) == PARALLEL
-         && XEXP (XVECEXP (args[i].reg, 0, 0), 0) == 0)
-       args[i].pass_on_stack = 1;
-
-      /* If this is an addressable type, we must preallocate the stack
-        since we must evaluate the object into its final location.
-
-        If this is to be passed in both registers and the stack, it is simpler
-        to preallocate.  */
-      if (TREE_ADDRESSABLE (type)
-         || (args[i].pass_on_stack && args[i].reg != 0))
-       must_preallocate = 1;
-
-      /* If this is an addressable type, we cannot pre-evaluate it.  Thus,
-        we cannot consider this function call constant.  */
-      if (TREE_ADDRESSABLE (type))
-       is_const = 0;
-
-      /* Compute the stack-size of this argument.  */
-      if (args[i].reg == 0 || args[i].partial != 0
-         || reg_parm_stack_space > 0
-         || args[i].pass_on_stack)
-       locate_and_pad_parm (mode, type,
-#ifdef STACK_PARMS_IN_REG_PARM_AREA
-                            1,
-#else
-                            args[i].reg != 0,
-#endif
-                            fndecl, &args_size, &args[i].offset,
-                            &args[i].size);
-
-#ifndef ARGS_GROW_DOWNWARD
-      args[i].slot_offset = args_size;
-#endif
-
-      /* If a part of the arg was put into registers,
-        don't include that part in the amount pushed.  */
-      if (reg_parm_stack_space == 0 && ! args[i].pass_on_stack)
-       args[i].size.constant -= ((args[i].partial * UNITS_PER_WORD)
-                                 / (PARM_BOUNDARY / BITS_PER_UNIT)
-                                 * (PARM_BOUNDARY / BITS_PER_UNIT));
-      
-      /* Update ARGS_SIZE, the total stack space for args so far.  */
-
-      args_size.constant += args[i].size.constant;
-      if (args[i].size.var)
-       {
-         ADD_PARM_SIZE (args_size, args[i].size.var);
-       }
-
-      /* Since the slot offset points to the bottom of the slot,
-        we must record it after incrementing if the args grow down.  */
-#ifdef ARGS_GROW_DOWNWARD
-      args[i].slot_offset = args_size;
-
-      args[i].slot_offset.constant = -args_size.constant;
-      if (args_size.var)
-       {
-         SUB_PARM_SIZE (args[i].slot_offset, args_size.var);
-       }
-#endif
-
-      /* Increment ARGS_SO_FAR, which has info about which arg-registers
-        have been used, etc.  */
+  /* Make a vector to hold all the information about each arg.  */
+  args = (struct arg_data *) alloca (num_actuals * sizeof (struct arg_data));
+  bzero ((char *) args, num_actuals * sizeof (struct arg_data));
 
-      FUNCTION_ARG_ADVANCE (args_so_far, TYPE_MODE (type), type,
-                           argpos < n_named_args);
-    }
+  /* Build up entries inthe 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, &args_so_far,
+                                  reg_parm_stack_space, &old_stack_level,
+                                  &old_pending_adj, &must_preallocate,
+                                  &is_const);
 
 #ifdef FINAL_REG_PARM_STACK_SPACE
   reg_parm_stack_space = FINAL_REG_PARM_STACK_SPACE (args_size.constant,
                                                     args_size.var);
 #endif
       
-  /* Compute the actual size of the argument block required.  The variable
-     and constant sizes must be combined, the size may have to be rounded,
-     and there may be a minimum required size.  */
-
-  original_args_size = args_size;
   if (args_size.var)
     {
       /* If this function requires a variable-sized argument list, don't try to
@@ -1525,94 +1977,17 @@ expand_call (exp, target, ignore)
 
       is_const = 0;
       must_preallocate = 1;
-
-      args_size.var = ARGS_SIZE_TREE (args_size);
-      args_size.constant = 0;
-
-#ifdef PREFERRED_STACK_BOUNDARY
-      if (PREFERRED_STACK_BOUNDARY != BITS_PER_UNIT)
-       args_size.var = round_up (args_size.var, STACK_BYTES);
-#endif
-
-      if (reg_parm_stack_space > 0)
-       {
-         args_size.var
-           = size_binop (MAX_EXPR, args_size.var,
-                         size_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,
-                         size_int (reg_parm_stack_space));
-#endif
-       }
-    }
-  else
-    {
-#ifdef PREFERRED_STACK_BOUNDARY
-      args_size.constant = (((args_size.constant + (STACK_BYTES - 1))
-                            / STACK_BYTES) * STACK_BYTES);
-#endif
-
-      args_size.constant = MAX (args_size.constant,
-                               reg_parm_stack_space);
-
-#ifdef MAYBE_REG_PARM_STACK_SPACE
-      if (reg_parm_stack_space == 0)
-       args_size.constant = 0;
-#endif
-
-#ifndef OUTGOING_REG_PARM_STACK_SPACE
-      args_size.constant -= reg_parm_stack_space;
-#endif
     }
 
-  /* See if we have or want to preallocate stack space.
-
-     If we would have to push a partially-in-regs parm
-     before other stack parms, preallocate stack space instead.
-
-     If the size of some parm is not a multiple of the required stack
-     alignment, we must preallocate.
-
-     If the total size of arguments that would otherwise create a copy in
-     a temporary (such as a CALL) is more than half the total argument list
-     size, preallocation is faster.
-
-     Another reason to preallocate is if we have a machine (like the m88k)
-     where stack alignment is required to be maintained between every
-     pair of insns, not just when the call is made.  However, we assume here
-     that such machines either do not have push insns (and hence preallocation
-     would occur anyway) or the problem is taken care of with
-     PUSH_ROUNDING.  */
-
-  if (! must_preallocate)
-    {
-      int partial_seen = 0;
-      int copy_to_evaluate_size = 0;
-
-      for (i = 0; i < num_actuals && ! must_preallocate; i++)
-       {
-         if (args[i].partial > 0 && ! args[i].pass_on_stack)
-           partial_seen = 1;
-         else if (partial_seen && args[i].reg == 0)
-           must_preallocate = 1;
-
-         if (TYPE_MODE (TREE_TYPE (args[i].tree_value)) == BLKmode
-             && (TREE_CODE (args[i].tree_value) == CALL_EXPR
-                 || TREE_CODE (args[i].tree_value) == TARGET_EXPR
-                 || TREE_CODE (args[i].tree_value) == COND_EXPR
-                 || TREE_ADDRESSABLE (TREE_TYPE (args[i].tree_value))))
-           copy_to_evaluate_size
-             += int_size_in_bytes (TREE_TYPE (args[i].tree_value));
-       }
+  /* Compute the actual size of the argument block required.  The variable
+     and constant sizes must be combined, the size may have to be rounded,
+     and there may be a minimum required size.  */
+  unadjusted_args_size
+    = compute_argument_block_size (reg_parm_stack_space, &args_size);
 
-      if (copy_to_evaluate_size * 2 >= args_size.constant
-         && args_size.constant > 0)
-       must_preallocate = 1;
-    }
+  /* Now make final decision about preallocating stack space.  */
+  must_preallocate = finalize_must_preallocate (must_preallocate,
+                                               num_actuals, args, &args_size);
 
   /* If the structure value address will reference the stack pointer, we must
      stabilize it.  We don't need to do this if we know that we are not going
@@ -1628,51 +2003,9 @@ expand_call (exp, target, ignore)
          ))
     structure_value_addr = copy_to_reg (structure_value_addr);
 
-  /* If this function call is cse'able, precompute all the parameters.
-     Note that if the parameter is constructed into a temporary, this will
-     cause an additional copy because the parameter will be constructed
-     into a temporary location and then copied into the outgoing arguments.
-     If a parameter contains a call to alloca and this function uses the
-     stack, precompute the parameter.  */
-
-  /* If we preallocated the stack space, and some arguments must be passed
-     on the stack, then we must precompute any parameter which contains a
-     function call which will store arguments on the stack.
-     Otherwise, evaluating the parameter may clobber previous parameters
-     which have already been stored into the stack.  */
-
-  for (i = 0; i < num_actuals; i++)
-    if (is_const
-       || ((args_size.var != 0 || args_size.constant != 0)
-           && calls_function (args[i].tree_value, 1))
-       || (must_preallocate && (args_size.var != 0 || args_size.constant != 0)
-           && calls_function (args[i].tree_value, 0)))
-      {
-       /* If this is an addressable type, we cannot pre-evaluate it.  */
-       if (TREE_ADDRESSABLE (TREE_TYPE (args[i].tree_value)))
-         abort ();
-
-       push_temp_slots ();
-
-       args[i].initial_value = args[i].value
-         = expand_expr (args[i].tree_value, NULL_RTX, VOIDmode, 0);
-
-       preserve_temp_slots (args[i].value);
-       pop_temp_slots ();
-
-       /* ANSI doesn't require a sequence point here,
-          but PCC has one, so this will avoid some problems.  */
-       emit_queue ();
-
-       args[i].initial_value = args[i].value
-         = protect_from_queue (args[i].initial_value, 0);
-
-       if (TYPE_MODE (TREE_TYPE (args[i].tree_value)) != args[i].mode)
-         args[i].value
-           = convert_modes (args[i].mode, 
-                            TYPE_MODE (TREE_TYPE (args[i].tree_value)),
-                            args[i].value, args[i].unsignedp);
-      }
+  /* Precompute any arguments as needed.  */
+  precompute_arguments (is_const, must_preallocate, num_actuals,
+                        args, &args_size);
 
   /* Now we are about to start emitting insns that can be deleted
      if a libcall is deleted.  */
@@ -1835,56 +2168,14 @@ expand_call (exp, target, ignore)
       }
 #endif
 
+  compute_argument_addresses (args, argblock, num_actuals);
 
-  /* If we preallocated stack space, compute the address of each argument.
-     We need not ensure it is a valid memory address here; it will be 
-     validized when it is used.  */
-  if (argblock)
-    {
-      rtx arg_reg = argblock;
-      int arg_offset = 0;
-
-      if (GET_CODE (argblock) == PLUS)
-       arg_reg = XEXP (argblock, 0), arg_offset = INTVAL (XEXP (argblock, 1));
-
-      for (i = 0; i < num_actuals; i++)
-       {
-         rtx offset = ARGS_SIZE_RTX (args[i].offset);
-         rtx slot_offset = ARGS_SIZE_RTX (args[i].slot_offset);
-         rtx addr;
-
-         /* Skip this parm if it will not be passed on the stack.  */
-         if (! args[i].pass_on_stack && args[i].reg != 0)
-           continue;
-
-         if (GET_CODE (offset) == CONST_INT)
-           addr = plus_constant (arg_reg, INTVAL (offset));
-         else
-           addr = gen_rtx_PLUS (Pmode, arg_reg, offset);
-
-         addr = plus_constant (addr, arg_offset);
-         args[i].stack = gen_rtx_MEM (args[i].mode, addr);
-         MEM_SET_IN_STRUCT_P 
-           (args[i].stack,
-            AGGREGATE_TYPE_P (TREE_TYPE (args[i].tree_value)));
-
-         if (GET_CODE (slot_offset) == CONST_INT)
-           addr = plus_constant (arg_reg, INTVAL (slot_offset));
-         else
-           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);
-       }
-    }
-                                              
 #ifdef PUSH_ARGS_REVERSED
 #ifdef PREFERRED_STACK_BOUNDARY
   /* If we push args individually in reverse order, perform stack alignment
      before the first push (the last arg).  */
   if (argblock == 0)
-    anti_adjust_stack (GEN_INT (args_size.constant
-                               - original_args_size.constant));
+    anti_adjust_stack (GEN_INT (args_size.constant - unadjusted_args_size));
 #endif
 #endif
 
@@ -1893,34 +2184,7 @@ expand_call (exp, target, ignore)
   if (argblock)
     NO_DEFER_POP;
 
-  /* Get the function to call, in the form of RTL.  */
-  if (fndecl)
-    {
-      /* If this is the first use of the function, see if we need to
-        make an external definition for it.  */
-      if (! TREE_USED (fndecl))
-       {
-         assemble_external (fndecl);
-         TREE_USED (fndecl) = 1;
-       }
-
-      /* Get a SYMBOL_REF rtx for the function address.  */
-      funexp = XEXP (DECL_RTL (fndecl), 0);
-    }
-  else
-    /* Generate an rtx (probably a pseudo-register) for the address.  */
-    {
-      push_temp_slots ();
-      funexp = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
-      pop_temp_slots ();       /* FUNEXP can't be BLKmode */
-
-      /* Check the function is executable.  */
-      if (current_function_check_memory_usage)
-       emit_library_call (chkr_check_exec_libfunc, 1,
-                          VOIDmode, 1,
-                          funexp, ptr_mode);
-      emit_queue ();
-    }
+  funexp = rtx_for_function_call (fndecl, exp);
 
   /* Figure out the register where the value, if any, will come back.  */
   valreg = 0;
@@ -1978,8 +2242,7 @@ expand_call (exp, target, ignore)
   /* If we pushed args in forward order, perform stack alignment
      after pushing the last arg.  */
   if (argblock == 0)
-    anti_adjust_stack (GEN_INT (args_size.constant
-                               - original_args_size.constant));
+    anti_adjust_stack (GEN_INT (args_size.constant - unadjusted_args_size));
 #endif
 #endif
 
@@ -2003,7 +2266,7 @@ expand_call (exp, target, ignore)
       if (current_function_check_memory_usage)
        emit_library_call (chkr_set_right_libfunc, 1,
                           VOIDmode, 3,
-                          structure_value_addr, ptr_mode, 
+                          structure_value_addr, Pmode, 
                           GEN_INT (struct_value_size), TYPE_MODE (sizetype),
                           GEN_INT (MEMORY_USE_WO),
                           TYPE_MODE (integer_type_node));
@@ -2014,76 +2277,7 @@ expand_call (exp, target, ignore)
 
   funexp = prepare_call_address (funexp, fndecl, &call_fusage, reg_parm_seen);
 
-  /* Now 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. 
-
-     Mark all register-parms as living through the call, putting these USE
-     insns in the CALL_INSN_FUNCTION_USAGE field.  */
-
-#ifdef LOAD_ARGS_REVERSED
-  for (i = num_actuals - 1; i >= 0; i--)
-#else
-  for (i = 0; i < num_actuals; i++)
-#endif
-    {
-      rtx reg = args[i].reg;
-      int partial = args[i].partial;
-      int nregs;
-
-      if (reg)
-       {
-         /* Set to non-negative if must move a word at a time, even if just
-            one word (e.g, partial == 1 && mode == DFmode).  Set to -1 if
-            we just use a normal move insn.  This value can be zero if the
-            argument is a zero size structure with no fields.  */
-         nregs = (partial ? partial
-                  : (TYPE_MODE (TREE_TYPE (args[i].tree_value)) == BLKmode
-                     ? ((int_size_in_bytes (TREE_TYPE (args[i].tree_value))
-                         + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
-                     : -1));
-
-         /* Handle calls that pass values in multiple non-contiguous
-            locations.  The Irix 6 ABI has examples of this.  */
-
-         if (GET_CODE (reg) == PARALLEL)
-           {
-             emit_group_load (reg, args[i].value,
-                              int_size_in_bytes (TREE_TYPE (args[i].tree_value)),
-                              (TYPE_ALIGN (TREE_TYPE (args[i].tree_value))
-                               / BITS_PER_UNIT));
-           }
-
-         /* If simple case, just do move.  If normal partial, store_one_arg
-            has already loaded the register for us.  In all other cases,
-            load the register(s) from memory.  */
-
-         else if (nregs == -1)
-           emit_move_insn (reg, args[i].value);
-
-         /* If we have pre-computed the values to put in the registers in
-            the case of non-aligned structures, copy them in now.  */
-
-         else if (args[i].n_aligned_regs != 0)
-           for (j = 0; j < args[i].n_aligned_regs; j++)
-             emit_move_insn (gen_rtx_REG (word_mode, REGNO (reg) + j),
-                             args[i].aligned_regs[j]);
-
-         else if (partial == 0 || args[i].pass_on_stack)
-           move_block_to_reg (REGNO (reg),
-                              validize_mem (args[i].value), nregs,
-                              args[i].mode);
-
-         /* Handle calls that pass values in multiple non-contiguous
-            locations.  The Irix 6 ABI has examples of this.  */
-         if (GET_CODE (reg) == PARALLEL)
-           use_group_regs (&call_fusage, reg);
-         else if (nregs == -1)
-           use_reg (&call_fusage, reg);
-         else
-           use_regs (&call_fusage, REGNO (reg), nregs == 0 ? 1 : nregs);
-       }
-    }
+  load_register_parameters (args, num_actuals, &call_fusage);
 
   /* Perform postincrements before actually calling the function.  */
   emit_queue ();
@@ -2091,7 +2285,8 @@ expand_call (exp, target, ignore)
   /* All arguments and registers used for the call must be set up by now!  */
 
   /* Generate the actual call instruction.  */
-  emit_call_1 (funexp, fndecl, funtype, args_size.constant, struct_value_size,
+  emit_call_1 (funexp, fndecl, funtype, unadjusted_args_size,
+              args_size.constant, struct_value_size,
               FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
               valreg, old_inhibit_defer_pop, call_fusage, is_const);
 
@@ -2776,7 +2971,7 @@ emit_library_call VPROTO((rtx orgfun, int no_queue, enum machine_mode outmode,
                get_identifier (XSTR (orgfun, 0)), 
               build_function_type (outmode == VOIDmode ? void_type_node
                                    : type_for_mode (outmode, 0), NULL_TREE),
-               args_size.constant, 0,
+              original_args_size.constant, args_size.constant, 0,
               FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
               outmode != VOIDmode ? hard_libcall_value (outmode) : NULL_RTX,
               old_inhibit_defer_pop + 1, call_fusage, no_queue);
@@ -3349,7 +3544,8 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue,
   emit_call_1 (fun, 
                get_identifier (XSTR (orgfun, 0)),
               build_function_type (type_for_mode (outmode, 0), NULL_TREE),
-               args_size.constant, struct_value_size,
+               original_args_size.constant, args_size.constant,
+              struct_value_size,
               FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
               mem_value == 0 ? hard_libcall_value (outmode) : NULL_RTX,
               old_inhibit_defer_pop + 1, call_fusage, is_const);
@@ -3481,7 +3677,7 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size,
      struct arg_data *arg;
      rtx argblock;
      int may_be_alloca;
-     int variable_size;
+     int variable_size ATTRIBUTE_UNUSED;
      int reg_parm_stack_space;
 {
   register tree pval = arg->tree_value;
@@ -3640,7 +3836,7 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size,
       if (current_function_check_memory_usage && GET_CODE (arg->stack) == MEM)
        {
          emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
-                            XEXP (arg->stack, 0), ptr_mode, 
+                            XEXP (arg->stack, 0), Pmode, 
                             ARGS_SIZE_RTX (arg->size),
                             TYPE_MODE (sizetype),
                             GEN_INT (MEMORY_USE_RW),