calls.c (struct arg_data): Move offset, slot_offset, size and alignment_pad to struct...
authorAlan Modra <amodra@bigpond.net.au>
Fri, 2 May 2003 14:22:09 +0000 (14:22 +0000)
committerAlan Modra <amodra@gcc.gnu.org>
Fri, 2 May 2003 14:22:09 +0000 (23:52 +0930)
* calls.c (struct arg_data): Move offset, slot_offset, size and
alignment_pad to struct locate_and_pad_arg_data.  Update all refs.
(initialize_argument_information): Adjust call to locate_and_pad_parm.
Delete alignment_pad var.  Don't calculate slot_offset here.
(emit_library_call_value_1): Delete alignment_pad, offset and size
vars.  Use struct locate_and_pad_arg_data instead.  Adjust refs.
Adjust call to locate_and_pad_parm.  Don't tweak arg size for
partial in-regs here.  Formatting fixes.
* expr.h (struct locate_and_pad_arg_data): New struct.
(locate_and_pad_parm): Adjust declaration.
* function.c (assign_parms): Localize vars.  Use "locate" instead of
other arg location vars.  Don't invoke FUNCTION_ARG or
FUNCTION_INCOMING_ARG unless pretend_named is different from
named_arg.  Heed MUST_PASS_IN_STACK and set up "partial" before
calling locate_and_pad_parm.  Adjust locate_and_pad_parm call.
Use slot_offset for stack home of reg parms.  Correct test for
parm passed in memory.  Formatting fixes.
(locate_and_pad_parm): Add "partial" to params.  Replace offset_ptr
arg_size_ptr and alignment pad with "locate".  Set slot_offset here.
Correct initial_offset_ptr handling.  Localize vars.  Always pad
locate->offset even when in_regs.

From-SVN: r66383

gcc/ChangeLog
gcc/calls.c
gcc/expr.h
gcc/function.c

index 1509141d34f61fb1da1f7c9935befa7439eeb0cc..c2b1e8da47f70fe427cd8092692d034f8a452aa5 100644 (file)
@@ -1,3 +1,27 @@
+2003-05-02  Alan Modra  <amodra@bigpond.net.au>
+
+       * calls.c (struct arg_data): Move offset, slot_offset, size and
+       alignment_pad to struct locate_and_pad_arg_data.  Update all refs.
+       (initialize_argument_information): Adjust call to locate_and_pad_parm.
+       Delete alignment_pad var.  Don't calculate slot_offset here.
+       (emit_library_call_value_1): Delete alignment_pad, offset and size
+       vars.  Use struct locate_and_pad_arg_data instead.  Adjust refs.
+       Adjust call to locate_and_pad_parm.  Don't tweak arg size for
+       partial in-regs here.  Formatting fixes.
+       * expr.h (struct locate_and_pad_arg_data): New struct.
+       (locate_and_pad_parm): Adjust declaration.
+       * function.c (assign_parms): Localize vars.  Use "locate" instead of
+       other arg location vars.  Don't invoke FUNCTION_ARG or
+       FUNCTION_INCOMING_ARG unless pretend_named is different from
+       named_arg.  Heed MUST_PASS_IN_STACK and set up "partial" before
+       calling locate_and_pad_parm.  Adjust locate_and_pad_parm call.
+       Use slot_offset for stack home of reg parms.  Correct test for
+       parm passed in memory.  Formatting fixes.
+       (locate_and_pad_parm): Add "partial" to params.  Replace offset_ptr
+       arg_size_ptr and alignment pad with "locate".  Set slot_offset here.
+       Correct initial_offset_ptr handling.  Localize vars.  Always pad
+       locate->offset even when in_regs.
+
 2003-05-02  Nathan Sidwell  <nathan@codesourcery.com>
 
        * Makefile.in (TREE_H): Replace location.h with input.h.
index 135f949028c4d9d0d27ce2c74768c5b7e99aac3f..8fb84e9b906f3b461cd4089d7b27da58a5d0dcee 100644 (file)
@@ -98,16 +98,8 @@ struct arg_data
      even though pass_on_stack is zero, just because FUNCTION_ARG says so.
      pass_on_stack identifies arguments that *cannot* go in registers.  */
   int pass_on_stack;
-  /* Offset of this argument from beginning of stack-args.  */
-  struct args_size offset;
-  /* Similar, but offset to the start of the stack slot.  Different from
-     OFFSET if this arg pads downward.  */
-  struct args_size slot_offset;
-  /* Size of this argument on the stack, rounded up for any padding it gets,
-     parts of the argument passed in registers do not count.
-     If REG_PARM_STACK_SPACE is defined, then register parms
-     are counted here as well.  */
-  struct args_size size;
+  /* Some fields packaged up for locate_and_pad_parm.  */
+  struct locate_and_pad_arg_data locate;
   /* Location on the stack at which parameter should be stored.  The store
      has already been done if STACK == VALUE.  */
   rtx stack;
@@ -123,9 +115,6 @@ struct arg_data
      word-sized pseudos we made.  */
   rtx *aligned_regs;
   int n_aligned_regs;
-  /* The amount that the stack pointer needs to be adjusted to
-     force alignment for the next argument.  */
-  struct args_size alignment_pad;
 };
 
 /* A vector of one char per byte of stack space.  A byte if nonzero if
@@ -1120,7 +1109,6 @@ initialize_argument_information (num_actuals, args, args_size, n_named_args,
   /* Count arg position in order args appear.  */
   int argpos;
 
-  struct args_size alignment_pad;
   int i;
   tree p;
 
@@ -1331,39 +1319,14 @@ initialize_argument_information (num_actuals, args, args_size, n_named_args,
 #else
                             args[i].reg != 0,
 #endif
-                            fndecl, args_size, &args[i].offset,
-                            &args[i].size, &alignment_pad);
-
-#ifndef ARGS_GROW_DOWNWARD
-      args[i].slot_offset = *args_size;
-#endif
-
-      args[i].alignment_pad = alignment_pad;
-
-      /* 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));
+                            args[i].pass_on_stack ? 0 : args[i].partial,
+                            fndecl, args_size, &args[i].locate);
 
       /* 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
+      args_size->constant += args[i].locate.size.constant;
+      if (args[i].locate.size.var)
+       ADD_PARM_SIZE (*args_size, args[i].locate.size.var);
 
       /* Increment ARGS_SO_FAR, which has info about which arg-registers
         have been used, etc.  */
@@ -1616,8 +1579,8 @@ compute_argument_addresses (args, argblock, num_actuals)
 
       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 offset = ARGS_SIZE_RTX (args[i].locate.offset);
+         rtx slot_offset = ARGS_SIZE_RTX (args[i].locate.slot_offset);
          rtx addr;
 
          /* Skip this parm if it will not be passed on the stack.  */
@@ -2060,12 +2023,12 @@ check_sibcall_argument_overlap (insn, arg, mark_stored_args_map)
   if (mark_stored_args_map)
     {
 #ifdef ARGS_GROW_DOWNWARD
-      low = -arg->slot_offset.constant - arg->size.constant;
+      low = -arg->locate.slot_offset.constant - arg->locate.size.constant;
 #else
-      low = arg->slot_offset.constant;
+      low = arg->locate.slot_offset.constant;
 #endif
 
-      for (high = low + arg->size.constant; low < high; low++)
+      for (high = low + arg->locate.size.constant; low < high; low++)
        SET_BIT (stored_args_map, low);
     }
   return insn != NULL_RTX;
@@ -3364,7 +3327,7 @@ expand_call (exp, target, ignore)
                  emit_move_insn (stack_area, args[i].save_area);
                else
                  emit_block_move (stack_area, args[i].save_area,
-                                  GEN_INT (args[i].size.constant),
+                                  GEN_INT (args[i].locate.size.constant),
                                   BLOCK_OP_CALL_PARM);
              }
 
@@ -3513,7 +3476,6 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
   rtx fun;
   int inc;
   int count;
-  struct args_size alignment_pad;
   rtx argblock = 0;
   CUMULATIVE_ARGS args_so_far;
   struct arg
@@ -3522,8 +3484,7 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
     enum machine_mode mode;
     rtx reg;
     int partial;
-    struct args_size offset;
-    struct args_size size;
+    struct locate_and_pad_arg_data locate;
     rtx save_area;
   };
   struct arg *argvec;
@@ -3683,12 +3644,11 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
 #else
                           argvec[count].reg != 0,
 #endif
-                          NULL_TREE, &args_size, &argvec[count].offset,
-                          &argvec[count].size, &alignment_pad);
+                          0, NULL_TREE, &args_size, &argvec[count].locate);
 
       if (argvec[count].reg == 0 || argvec[count].partial != 0
          || reg_parm_stack_space > 0)
-       args_size.constant += argvec[count].size.constant;
+       args_size.constant += argvec[count].locate.size.constant;
 
       FUNCTION_ARG_ADVANCE (args_so_far, Pmode, (tree) 0, 1);
 
@@ -3802,18 +3762,15 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
 #else
                           argvec[count].reg != 0,
 #endif
-                          NULL_TREE, &args_size, &argvec[count].offset,
-                          &argvec[count].size, &alignment_pad);
+                          argvec[count].partial,
+                          NULL_TREE, &args_size, &argvec[count].locate);
 
-      if (argvec[count].size.var)
+      if (argvec[count].locate.size.var)
        abort ();
 
-      if (reg_parm_stack_space == 0 && argvec[count].partial)
-       argvec[count].size.constant -= argvec[count].partial * UNITS_PER_WORD;
-
       if (argvec[count].reg == 0 || argvec[count].partial != 0
          || reg_parm_stack_space > 0)
-       args_size.constant += argvec[count].size.constant;
+       args_size.constant += argvec[count].locate.size.constant;
 
       FUNCTION_ARG_ADVANCE (args_so_far, mode, (tree) 0, 1);
     }
@@ -3951,11 +3908,11 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
 #ifdef ARGS_GROW_DOWNWARD
              /* stack_slot is negative, but we want to index stack_usage_map
                 with positive values.  */
-             upper_bound = -argvec[argnum].offset.constant + 1;
-             lower_bound = upper_bound - argvec[argnum].size.constant;
+             upper_bound = -argvec[argnum].locate.offset.constant + 1;
+             lower_bound = upper_bound - argvec[argnum].locate.size.constant;
 #else
-             lower_bound = argvec[argnum].offset.constant;
-             upper_bound = lower_bound + argvec[argnum].size.constant;
+             lower_bound = argvec[argnum].locate.offset.constant;
+             upper_bound = lower_bound + argvec[argnum].locate.size.constant;
 #endif
 
              i = lower_bound;
@@ -3968,19 +3925,16 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
 
              if (i < upper_bound)
                {
-                 /* We need to make a save area.  See what mode we can make
-                    it.  */
+                 /* We need to make a save area.  */
+                 unsigned int size
+                   = argvec[argnum].locate.size.constant * BITS_PER_UNIT;
                  enum machine_mode save_mode
-                   = mode_for_size (argvec[argnum].size.constant
-                                    * BITS_PER_UNIT,
-                                    MODE_INT, 1);
+                   = mode_for_size (size, MODE_INT, 1);
+                 rtx adr
+                   = plus_constant (argblock,
+                                    argvec[argnum].locate.offset.constant);
                  rtx stack_area
-                   = gen_rtx_MEM
-                     (save_mode,
-                      memory_address
-                      (save_mode,
-                       plus_constant (argblock,
-                                      argvec[argnum].offset.constant)));
+                   = gen_rtx_MEM (save_mode, memory_address (save_mode, adr));
                  argvec[argnum].save_area = gen_reg_rtx (save_mode);
 
                  emit_move_insn (argvec[argnum].save_area, stack_area);
@@ -3989,8 +3943,9 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
 
          emit_push_insn (val, mode, NULL_TREE, NULL_RTX, PARM_BOUNDARY,
                          partial, reg, 0, argblock,
-                         GEN_INT (argvec[argnum].offset.constant),
-                         reg_parm_stack_space, ARGS_SIZE_RTX (alignment_pad));
+                         GEN_INT (argvec[argnum].locate.offset.constant),
+                         reg_parm_stack_space,
+                         ARGS_SIZE_RTX (argvec[argnum].locate.alignment_pad));
 
          /* Now mark the segment we just used.  */
          if (ACCUMULATE_OUTGOING_ARGS)
@@ -4195,12 +4150,10 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
        if (argvec[count].save_area)
          {
            enum machine_mode save_mode = GET_MODE (argvec[count].save_area);
-           rtx stack_area
-             = gen_rtx_MEM (save_mode,
-                            memory_address
-                            (save_mode,
-                             plus_constant (argblock,
-                                            argvec[count].offset.constant)));
+           rtx adr = plus_constant (argblock,
+                                    argvec[count].locate.offset.constant);
+           rtx stack_area = gen_rtx_MEM (save_mode,
+                                         memory_address (save_mode, adr));
 
            emit_move_insn (stack_area, argvec[count].save_area);
          }
@@ -4327,14 +4280,14 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
          else
            upper_bound = 0;
 
-         lower_bound = upper_bound - arg->size.constant;
+         lower_bound = upper_bound - arg->locate.size.constant;
 #else
          if (GET_CODE (XEXP (arg->stack_slot, 0)) == PLUS)
            lower_bound = INTVAL (XEXP (XEXP (arg->stack_slot, 0), 1));
          else
            lower_bound = 0;
 
-         upper_bound = lower_bound + arg->size.constant;
+         upper_bound = lower_bound + arg->locate.size.constant;
 #endif
 
          i = lower_bound;
@@ -4347,13 +4300,11 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
 
          if (i < upper_bound)
            {
-             /* We need to make a save area.  See what mode we can make it.  */
-             enum machine_mode save_mode
-               = mode_for_size (arg->size.constant * BITS_PER_UNIT, MODE_INT, 1);
-             rtx stack_area
-               = gen_rtx_MEM (save_mode,
-                              memory_address (save_mode,
-                                              XEXP (arg->stack_slot, 0)));
+             /* We need to make a save area.  */
+             unsigned int size = arg->locate.size.constant * BITS_PER_UNIT;
+             enum machine_mode save_mode = mode_for_size (size, MODE_INT, 1);
+             rtx adr = memory_address (save_mode, XEXP (arg->stack_slot, 0));
+             rtx stack_area = gen_rtx_MEM (save_mode, adr);
 
              if (save_mode == BLKmode)
                {
@@ -4481,8 +4432,8 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
         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,
-                     ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space,
-                     ARGS_SIZE_RTX (arg->alignment_pad));
+                     ARGS_SIZE_RTX (arg->locate.offset), reg_parm_stack_space,
+                     ARGS_SIZE_RTX (arg->locate.alignment_pad));
 
       /* Unless this is a partially-in-register argument, the argument is now
         in the stack.  */
@@ -4504,16 +4455,17 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
       /* Round its size up to a multiple
         of the allocation unit for arguments.  */
 
-      if (arg->size.var != 0)
+      if (arg->locate.size.var != 0)
        {
          excess = 0;
-         size_rtx = ARGS_SIZE_RTX (arg->size);
+         size_rtx = ARGS_SIZE_RTX (arg->locate.size);
        }
       else
        {
          /* PUSH_ROUNDING has no effect on us, because
             emit_push_insn for BLKmode is careful to avoid it.  */
-         excess = (arg->size.constant - int_size_in_bytes (TREE_TYPE (pval))
+         excess = (arg->locate.size.constant
+                   - int_size_in_bytes (TREE_TYPE (pval))
                    + partial * UNITS_PER_WORD);
          size_rtx = expand_expr (size_in_bytes (TREE_TYPE (pval)),
                                  NULL_RTX, TYPE_MODE (sizetype), 0);
@@ -4527,7 +4479,7 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
         PARM_BOUNDARY, but the actual argument isn't.  */
       if (FUNCTION_ARG_PADDING (arg->mode, TREE_TYPE (pval)) == downward)
        {
-         if (arg->size.var)
+         if (arg->locate.size.var)
            parm_align = BITS_PER_UNIT;
          else if (excess)
            {
@@ -4539,7 +4491,7 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
       if ((flags & ECF_SIBCALL) && GET_CODE (arg->value) == MEM)
        {
          /* emit_push_insn might not work properly if arg->value and
-            argblock + arg->offset areas overlap.  */
+            argblock + arg->locate.offset areas overlap.  */
          rtx x = arg->value;
          int i = 0;
 
@@ -4553,17 +4505,17 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
                i = INTVAL (XEXP (XEXP (x, 0), 1));
 
              /* expand_call should ensure this */
-             if (arg->offset.var || GET_CODE (size_rtx) != CONST_INT)
+             if (arg->locate.offset.var || GET_CODE (size_rtx) != CONST_INT)
                abort ();
 
-             if (arg->offset.constant > i)
+             if (arg->locate.offset.constant > i)
                {
-                 if (arg->offset.constant < i + INTVAL (size_rtx))
+                 if (arg->locate.offset.constant < i + INTVAL (size_rtx))
                    sibcall_failure = 1;
                }
-             else if (arg->offset.constant < i)
+             else if (arg->locate.offset.constant < i)
                {
-                 if (i < arg->offset.constant + INTVAL (size_rtx))
+                 if (i < arg->locate.offset.constant + INTVAL (size_rtx))
                    sibcall_failure = 1;
                }
            }
@@ -4571,8 +4523,8 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
 
       emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx,
                      parm_align, partial, reg, excess, argblock,
-                     ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space,
-                     ARGS_SIZE_RTX (arg->alignment_pad));
+                     ARGS_SIZE_RTX (arg->locate.offset), reg_parm_stack_space,
+                     ARGS_SIZE_RTX (arg->locate.alignment_pad));
 
       /* Unless this is a partially-in-register argument, the argument is now
         in the stack.
index 7e157cdf30225449f834a162e6f627e4ea26e017..dfd83d43c230afe49b10a995f49ca34b492ab8df 100644 (file)
@@ -63,6 +63,8 @@ enum expand_modifier {EXPAND_NORMAL = 0, EXPAND_STACK_PARM = 2, EXPAND_SUM,
    more information.  */
 #define OK_DEFER_POP (inhibit_defer_pop -= 1)
 \f
+enum direction {none, upward, downward};
+
 #ifdef TREE_CODE /* Don't lose if tree.h not included.  */
 /* Structure to record the size of a sequence of arguments
    as the sum of a tree-expression and a constant.  This structure is
@@ -74,6 +76,24 @@ struct args_size
   HOST_WIDE_INT constant;
   tree var;
 };
+
+/* Package up various arg related fields of struct args for
+   locate_and_pad_parm.  */
+struct locate_and_pad_arg_data
+{
+  /* Size of this argument on the stack, rounded up for any padding it
+     gets.  If REG_PARM_STACK_SPACE is defined, then register parms are
+     counted here, otherwise they aren't.  */
+  struct args_size size;
+  /* Offset of this argument from beginning of stack-args.  */
+  struct args_size offset;
+  /* Offset to the start of the stack slot.  Different from OFFSET
+     if this arg pads downward.  */
+  struct args_size slot_offset;
+  /* The amount that the stack pointer needs to be adjusted to
+     force alignment for the next argument.  */
+  struct args_size alignment_pad;
+};
 #endif
 
 /* Add the value of the tree INC to the `struct args_size' TO.  */
@@ -119,8 +139,6 @@ do {                                                        \
    usually pad upward, but pad short args downward on
    big-endian machines.  */
 
-enum direction {none, upward, downward};  /* Value has this type.  */
-
 #ifndef FUNCTION_ARG_PADDING
 #define FUNCTION_ARG_PADDING(MODE, TYPE)                               \
   (! BYTES_BIG_ENDIAN                                                  \
@@ -570,11 +588,9 @@ extern rtx expand_shift PARAMS ((enum tree_code, enum machine_mode, rtx, tree,
                                 rtx, int));
 extern rtx expand_divmod PARAMS ((int, enum tree_code, enum machine_mode, rtx,
                                  rtx, rtx, int));
-extern void locate_and_pad_parm PARAMS ((enum machine_mode, tree, int, tree,
-                                        struct args_size *,
-                                        struct args_size *,
-                                        struct args_size *,
-                                        struct args_size *));
+extern void locate_and_pad_parm PARAMS ((enum machine_mode, tree, int, int,
+                                        tree, struct args_size *,
+                                        struct locate_and_pad_arg_data *));
 extern rtx expand_inline_function PARAMS ((tree, tree, rtx, int, tree, rtx));
 
 /* Return the CODE_LABEL rtx for a LABEL_DECL, creating it if necessary.  */
index 6e52d7e1ddb6613a95edfdfa7354c4d84c6033a2..5684392b5e9502a50f4a952a601e4b60c66d1efd 100644 (file)
@@ -4340,12 +4340,7 @@ assign_parms (fndecl)
      tree fndecl;
 {
   tree parm;
-  rtx entry_parm = 0;
-  rtx stack_parm = 0;
   CUMULATIVE_ARGS args_so_far;
-  enum machine_mode promoted_mode, passed_mode;
-  enum machine_mode nominal_mode, promoted_nominal_mode;
-  int unsignedp;
   /* Total space needed so far for args on the stack,
      given as a constant and a tree-expression.  */
   struct args_size stack_args_size;
@@ -4359,8 +4354,8 @@ assign_parms (fndecl)
 #ifdef SETUP_INCOMING_VARARGS
   int varargs_setup = 0;
 #endif
+  int reg_parm_stack_space = 0;
   rtx conversion_insns = 0;
-  struct args_size alignment_pad;
 
   /* Nonzero if function takes extra anonymous args.
      This means the last named arg must be on the stack
@@ -4407,6 +4402,14 @@ assign_parms (fndecl)
   max_parm_reg = LAST_VIRTUAL_REGISTER + 1;
   parm_reg_stack_loc = (rtx *) ggc_alloc_cleared (max_parm_reg * sizeof (rtx));
 
+#ifdef REG_PARM_STACK_SPACE
+#ifdef MAYBE_REG_PARM_STACK_SPACE
+  reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE;
+#else
+  reg_parm_stack_space = REG_PARM_STACK_SPACE (fndecl);
+#endif
+#endif
+
 #ifdef INIT_CUMULATIVE_INCOMING_ARGS
   INIT_CUMULATIVE_INCOMING_ARGS (args_so_far, fntype, NULL_RTX);
 #else
@@ -4419,14 +4422,19 @@ assign_parms (fndecl)
 
   for (parm = fnargs; parm; parm = TREE_CHAIN (parm))
     {
-      struct args_size stack_offset;
-      struct args_size arg_size;
+      rtx entry_parm;
+      rtx stack_parm;
+      enum machine_mode promoted_mode, passed_mode;
+      enum machine_mode nominal_mode, promoted_nominal_mode;
+      int unsignedp;
+      struct locate_and_pad_arg_data locate;
       int passed_pointer = 0;
       int did_conversion = 0;
       tree passed_type = DECL_ARG_TYPE (parm);
       tree nominal_type = TREE_TYPE (parm);
-      int pretend_named;
       int last_named = 0, named_arg;
+      int in_regs;
+      int partial = 0;
 
       /* Set LAST_NAMED if this is last named arg before last
         anonymous args.  */
@@ -4490,7 +4498,7 @@ assign_parms (fndecl)
          || TREE_ADDRESSABLE (passed_type)
 #ifdef FUNCTION_ARG_PASS_BY_REFERENCE
          || FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, passed_mode,
-                                             passed_type, named_arg)
+                                            passed_type, named_arg)
 #endif
          )
        {
@@ -4560,27 +4568,52 @@ assign_parms (fndecl)
         it came in a register so that REG_PARM_STACK_SPACE isn't skipped.
         In this case, we call FUNCTION_ARG with NAMED set to 1 instead of
         0 as it was the previous time.  */
-
-      pretend_named = named_arg || PRETEND_OUTGOING_VARARGS_NAMED;
-      locate_and_pad_parm (promoted_mode, passed_type,
+      in_regs = entry_parm != 0;
 #ifdef STACK_PARMS_IN_REG_PARM_AREA
-                          1,
-#else
+      in_regs = 1;
+#endif
+      if (!in_regs && !named_arg)
+       {
+         int pretend_named = PRETEND_OUTGOING_VARARGS_NAMED;
+         if (pretend_named)
+           {
 #ifdef FUNCTION_INCOMING_ARG
-                          FUNCTION_INCOMING_ARG (args_so_far, promoted_mode,
-                                                 passed_type,
-                                                 pretend_named) != 0,
+             in_regs = FUNCTION_INCOMING_ARG (args_so_far, promoted_mode,
+                                              passed_type,
+                                              pretend_named) != 0;
 #else
-                          FUNCTION_ARG (args_so_far, promoted_mode,
-                                        passed_type,
-                                        pretend_named) != 0,
+             in_regs = FUNCTION_ARG (args_so_far, promoted_mode,
+                                     passed_type,
+                                     pretend_named) != 0;
 #endif
+           }
+       }
+
+      /* If this parameter was passed both in registers and in the stack,
+        use the copy on the stack.  */
+      if (MUST_PASS_IN_STACK (promoted_mode, passed_type))
+       entry_parm = 0;
+
+#ifdef FUNCTION_ARG_PARTIAL_NREGS
+      if (entry_parm)
+       partial = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, promoted_mode,
+                                             passed_type, named_arg);
 #endif
-                          fndecl, &stack_args_size, &stack_offset, &arg_size,
-                          &alignment_pad);
+
+      memset (&locate, 0, sizeof (locate));
+      locate_and_pad_parm (promoted_mode, passed_type, in_regs,
+                          entry_parm ? partial : 0, fndecl,
+                          &stack_args_size, &locate);
 
       {
-       rtx offset_rtx = ARGS_SIZE_RTX (stack_offset);
+       rtx offset_rtx;
+
+       /* If we're passing this arg using a reg, make its stack home
+          the aligned stack slot.  */
+       if (entry_parm)
+         offset_rtx = ARGS_SIZE_RTX (locate.slot_offset);
+       else
+         offset_rtx = ARGS_SIZE_RTX (locate.offset);
 
        if (offset_rtx == const0_rtx)
          stack_parm = gen_rtx_MEM (promoted_mode, internal_arg_pointer);
@@ -4597,12 +4630,6 @@ assign_parms (fndecl)
          set_reg_attrs_for_parm (entry_parm, stack_parm);
       }
 
-      /* If this parameter was passed both in registers and in the stack,
-        use the copy on the stack.  */
-      if (MUST_PASS_IN_STACK (promoted_mode, passed_type))
-       entry_parm = 0;
-
-#ifdef FUNCTION_ARG_PARTIAL_NREGS
       /* If this parm was passed part in regs and part in memory,
         pretend it arrived entirely in memory
         by pushing the register-part onto the stack.
@@ -4611,39 +4638,31 @@ assign_parms (fndecl)
         we could put it together in a pseudoreg directly,
         but for now that's not worth bothering with.  */
 
-      if (entry_parm)
+      if (partial)
        {
-         int nregs = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, promoted_mode,
-                                                 passed_type, named_arg);
-
-         if (nregs > 0)
-           {
-#if defined (REG_PARM_STACK_SPACE) && !defined (MAYBE_REG_PARM_STACK_SPACE)
-             /* When REG_PARM_STACK_SPACE is nonzero, stack space for
-                split parameters was allocated by our caller, so we
-                won't be pushing it in the prolog.  */
-             if (REG_PARM_STACK_SPACE (fndecl) == 0)
+#ifndef MAYBE_REG_PARM_STACK_SPACE
+         /* When REG_PARM_STACK_SPACE is nonzero, stack space for
+            split parameters was allocated by our caller, so we
+            won't be pushing it in the prolog.  */
+         if (reg_parm_stack_space)
 #endif
-             current_function_pretend_args_size
-               = (((nregs * UNITS_PER_WORD) + (PARM_BOUNDARY / BITS_PER_UNIT) - 1)
-                  / (PARM_BOUNDARY / BITS_PER_UNIT)
-                  * (PARM_BOUNDARY / BITS_PER_UNIT));
+         current_function_pretend_args_size
+           = (((partial * UNITS_PER_WORD) + (PARM_BOUNDARY / BITS_PER_UNIT) - 1)
+              / (PARM_BOUNDARY / BITS_PER_UNIT)
+              * (PARM_BOUNDARY / BITS_PER_UNIT));
 
-             /* Handle calls that pass values in multiple non-contiguous
-                locations.  The Irix 6 ABI has examples of this.  */
-             if (GET_CODE (entry_parm) == PARALLEL)
-               emit_group_store (validize_mem (stack_parm), entry_parm,
-                                 int_size_in_bytes (TREE_TYPE (parm)));
+         /* Handle calls that pass values in multiple non-contiguous
+            locations.  The Irix 6 ABI has examples of this.  */
+         if (GET_CODE (entry_parm) == PARALLEL)
+           emit_group_store (validize_mem (stack_parm), entry_parm,
+                             int_size_in_bytes (TREE_TYPE (parm)));
 
-             else
-               move_block_from_reg (REGNO (entry_parm),
-                                    validize_mem (stack_parm), nregs,
-                                    int_size_in_bytes (TREE_TYPE (parm)));
+         else
+           move_block_from_reg (REGNO (entry_parm), validize_mem (stack_parm),
+                                partial, int_size_in_bytes (TREE_TYPE (parm)));
 
-             entry_parm = stack_parm;
-           }
+         entry_parm = stack_parm;
        }
-#endif
 
       /* If we didn't decide this parm came in a register,
         by default it came on the stack.  */
@@ -4674,9 +4693,9 @@ assign_parms (fndecl)
 #endif
          )
        {
-         stack_args_size.constant += arg_size.constant;
-         if (arg_size.var)
-           ADD_PARM_SIZE (stack_args_size, arg_size.var);
+         stack_args_size.constant += locate.size.constant;
+         if (locate.size.var)
+           ADD_PARM_SIZE (stack_args_size, locate.size.var);
        }
       else
        /* No stack slot was pushed for this parm.  */
@@ -4700,7 +4719,7 @@ assign_parms (fndecl)
 
       /* If parm was passed in memory, and we need to convert it on entry,
         don't store it back in that same slot.  */
-      if (entry_parm != 0
+      if (entry_parm == stack_parm
          && nominal_mode != BLKmode && nominal_mode != passed_mode)
        stack_parm = 0;
 
@@ -5023,7 +5042,7 @@ assign_parms (fndecl)
              && ! did_conversion
              && stack_parm != 0
              && GET_CODE (stack_parm) == MEM
-             && stack_offset.var == 0
+             && locate.offset.var == 0
              && reg_mentioned_p (virtual_incoming_args_rtx,
                                  XEXP (stack_parm, 0)))
            {
@@ -5109,7 +5128,8 @@ assign_parms (fndecl)
                {
                  stack_parm
                    = assign_stack_local (GET_MODE (entry_parm),
-                                         GET_MODE_SIZE (GET_MODE (entry_parm)), 0);
+                                         GET_MODE_SIZE (GET_MODE (entry_parm)),
+                                         0);
                  set_mem_attributes (stack_parm, parm, 1);
                }
 
@@ -5280,8 +5300,11 @@ promoted_input_arg (regno, pmode, punsignedp)
    INITIAL_OFFSET_PTR points to the current offset into the stacked
    arguments.
 
-   The starting offset and size for this parm are returned in *OFFSET_PTR
-   and *ARG_SIZE_PTR, respectively.
+   The starting offset and size for this parm are returned in
+   LOCATE->OFFSET and LOCATE->SIZE, respectively.  When IN_REGS is
+   nonzero, the offset is that of stack slot, which is returned in
+   LOCATE->SLOT_OFFSET.  LOCATE->ALIGNMENT_PAD is the amount of
+   padding required from the initial offset ptr to the stack slot.
 
    IN_REGS is nonzero if the argument will be passed in registers.  It will
    never be set if REG_PARM_STACK_SPACE is not defined.
@@ -5298,45 +5321,39 @@ promoted_input_arg (regno, pmode, punsignedp)
    initial offset is not affected by this rounding, while the size always
    is and the starting offset may be.  */
 
-/*  offset_ptr will be negative for ARGS_GROW_DOWNWARD case;
-    initial_offset_ptr is positive because locate_and_pad_parm's
+/*  LOCATE->OFFSET will be negative for ARGS_GROW_DOWNWARD case;
+    INITIAL_OFFSET_PTR is positive because locate_and_pad_parm's
     callers pass in the total size of args so far as
-    initial_offset_ptr. arg_size_ptr is always positive.  */
+    INITIAL_OFFSET_PTR.  LOCATE->SIZE is always positive.  */
 
 void
-locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
-                    initial_offset_ptr, offset_ptr, arg_size_ptr,
-                    alignment_pad)
+locate_and_pad_parm (passed_mode, type, in_regs, partial, fndecl,
+                    initial_offset_ptr, locate)
      enum machine_mode passed_mode;
      tree type;
-     int in_regs ATTRIBUTE_UNUSED;
+     int in_regs;
+     int partial;
      tree fndecl ATTRIBUTE_UNUSED;
      struct args_size *initial_offset_ptr;
-     struct args_size *offset_ptr;
-     struct args_size *arg_size_ptr;
-     struct args_size *alignment_pad;
-
+     struct locate_and_pad_arg_data *locate;
 {
-  tree sizetree
-    = type ? size_in_bytes (type) : size_int (GET_MODE_SIZE (passed_mode));
-  enum direction where_pad = FUNCTION_ARG_PADDING (passed_mode, type);
-  int boundary = FUNCTION_ARG_BOUNDARY (passed_mode, type);
-#ifdef ARGS_GROW_DOWNWARD
-  tree s2 = sizetree;
-#endif
+  tree sizetree;
+  enum direction where_pad;
+  int boundary;
+  int reg_parm_stack_space = 0;
+  int part_size_in_regs;
 
 #ifdef REG_PARM_STACK_SPACE
+#ifdef MAYBE_REG_PARM_STACK_SPACE
+  reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE;
+#else
+  reg_parm_stack_space = REG_PARM_STACK_SPACE (fndecl);
+#endif
+
   /* If we have found a stack parm before we reach the end of the
      area reserved for registers, skip that area.  */
   if (! in_regs)
     {
-      int reg_parm_stack_space = 0;
-
-#ifdef MAYBE_REG_PARM_STACK_SPACE
-      reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE;
-#else
-      reg_parm_stack_space = REG_PARM_STACK_SPACE (fndecl);
-#endif
       if (reg_parm_stack_space > 0)
        {
          if (initial_offset_ptr->var)
@@ -5352,54 +5369,56 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
     }
 #endif /* REG_PARM_STACK_SPACE */
 
-  arg_size_ptr->var = 0;
-  arg_size_ptr->constant = 0;
-  alignment_pad->var = 0;
-  alignment_pad->constant = 0;
+  part_size_in_regs = 0;
+  if (reg_parm_stack_space == 0)
+    part_size_in_regs = ((partial * UNITS_PER_WORD)
+                        / (PARM_BOUNDARY / BITS_PER_UNIT)
+                        * (PARM_BOUNDARY / BITS_PER_UNIT));
+
+  sizetree
+    = type ? size_in_bytes (type) : size_int (GET_MODE_SIZE (passed_mode));
+  where_pad = FUNCTION_ARG_PADDING (passed_mode, type);
+  boundary = FUNCTION_ARG_BOUNDARY (passed_mode, type);
 
 #ifdef ARGS_GROW_DOWNWARD
+  locate->slot_offset.constant = -initial_offset_ptr->constant;
   if (initial_offset_ptr->var)
-    {
-      offset_ptr->constant = 0;
-      offset_ptr->var = size_binop (MINUS_EXPR, ssize_int (0),
-                                   initial_offset_ptr->var);
-    }
-  else
-    {
-      offset_ptr->constant = -initial_offset_ptr->constant;
-      offset_ptr->var = 0;
-    }
+    locate->slot_offset.var = size_binop (MINUS_EXPR, ssize_int (0),
+                                         initial_offset_ptr->var);
 
-  if (where_pad != none
-      && (!host_integerp (sizetree, 1)
-         || (tree_low_cst (sizetree, 1) * BITS_PER_UNIT) % PARM_BOUNDARY))
-    s2 = round_up (s2, PARM_BOUNDARY / BITS_PER_UNIT);
-  SUB_PARM_SIZE (*offset_ptr, s2);
+  {
+    tree s2 = sizetree;
+    if (where_pad != none
+       && (!host_integerp (sizetree, 1)
+           || (tree_low_cst (sizetree, 1) * BITS_PER_UNIT) % PARM_BOUNDARY))
+      s2 = round_up (s2, PARM_BOUNDARY / BITS_PER_UNIT);
+    SUB_PARM_SIZE (locate->slot_offset, s2);
+  }
+
+  locate->slot_offset.constant += part_size_in_regs;
 
   if (!in_regs
 #ifdef REG_PARM_STACK_SPACE
       || REG_PARM_STACK_SPACE (fndecl) > 0
 #endif
      )
-    pad_to_arg_alignment (offset_ptr, boundary, alignment_pad);
+    pad_to_arg_alignment (&locate->slot_offset, boundary,
+                         &locate->alignment_pad);
 
+  locate->size.constant = (-initial_offset_ptr->constant
+                          - locate->slot_offset.constant);
   if (initial_offset_ptr->var)
-    arg_size_ptr->var = size_binop (MINUS_EXPR,
-                                   size_binop (MINUS_EXPR,
-                                               ssize_int (0),
-                                               initial_offset_ptr->var),
-                                   offset_ptr->var);
-
-  else
-    arg_size_ptr->constant = (-initial_offset_ptr->constant
-                             - offset_ptr->constant);
-
-  /* Pad_below needs the pre-rounded size to know how much to pad below.
-     We only pad parameters which are not in registers as they have their
-     padding done elsewhere.  */
-  if (where_pad == downward
-      && !in_regs)
-    pad_below (offset_ptr, passed_mode, sizetree);
+    locate->size.var = size_binop (MINUS_EXPR,
+                                  size_binop (MINUS_EXPR,
+                                              ssize_int (0),
+                                              initial_offset_ptr->var),
+                                  locate->slot_offset.var);
+
+  /* Pad_below needs the pre-rounded size to know how much to pad
+     below.  */
+  locate->offset = locate->slot_offset;
+  if (where_pad == downward)
+    pad_below (&locate->offset, passed_mode, sizetree);
 
 #else /* !ARGS_GROW_DOWNWARD */
   if (!in_regs
@@ -5407,8 +5426,9 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
       || REG_PARM_STACK_SPACE (fndecl) > 0
 #endif
       )
-    pad_to_arg_alignment (initial_offset_ptr, boundary, alignment_pad);
-  *offset_ptr = *initial_offset_ptr;
+    pad_to_arg_alignment (initial_offset_ptr, boundary,
+                         &locate->alignment_pad);
+  locate->slot_offset = *initial_offset_ptr;
 
 #ifdef PUSH_ROUNDING
   if (passed_mode != BLKmode)
@@ -5417,18 +5437,18 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
 
   /* Pad_below needs the pre-rounded size to know how much to pad below
      so this must be done before rounding up.  */
-  if (where_pad == downward
-    /* However, BLKmode args passed in regs have their padding done elsewhere.
-       The stack slot must be able to hold the entire register.  */
-      && !(in_regs && passed_mode == BLKmode))
-    pad_below (offset_ptr, passed_mode, sizetree);
+  locate->offset = locate->slot_offset;
+  if (where_pad == downward)
+    pad_below (&locate->offset, passed_mode, sizetree);
 
   if (where_pad != none
       && (!host_integerp (sizetree, 1)
          || (tree_low_cst (sizetree, 1) * BITS_PER_UNIT) % PARM_BOUNDARY))
     sizetree = round_up (sizetree, PARM_BOUNDARY / BITS_PER_UNIT);
 
-  ADD_PARM_SIZE (*arg_size_ptr, sizetree);
+  ADD_PARM_SIZE (locate->size, sizetree);
+
+  locate->size.constant -= part_size_in_regs;
 #endif /* ARGS_GROW_DOWNWARD */
 }
 
@@ -5467,7 +5487,8 @@ pad_to_arg_alignment (offset_ptr, boundary, alignment_pad)
 #endif
              (ARGS_SIZE_TREE (*offset_ptr),
               boundary / BITS_PER_UNIT);
-         offset_ptr->constant = 0; /*?*/
+         /* ARGS_SIZE_TREE includes constant term.  */
+         offset_ptr->constant = 0;
          if (boundary > PARM_BOUNDARY && boundary > STACK_BOUNDARY)
            alignment_pad->var = size_binop (MINUS_EXPR, offset_ptr->var,
                                             save_var);