This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

function parms in regs, patch 1 of 3


I've been playing with gcc's function call code over the last week or
so.  The goal was to properly pass structures by value in registers,
according to the PowerPC64 ABI, and avoid the problems illustrated
in PR 10397 and PR 10408.  What started out as a relatively straight-
forward patch using PARALLELs in rs6000.c:function_arg has grown a
little..  So much so that it needs splitting up.

Patch 1 of 3 (this one) mostly mucks about with locate_and_pad_parm.
Patch 2 of 3 moves special case code out of move_block_from_reg.
Patch 3 of 3 is the new code to handle big-endian reg parms, and
rs6000 specific changes.

Patch 1 and 2 can probably be applied in reverse order as they're
independent, although I haven't tested that.  Regression tested
powerpc64-linux after each patch cumulatively applied.  I'll also
bootstrap and regression test i686-linux and powerpc-linux again
(these were tested on earlier versions of the patch).

This patch
a) Packages struct arg_data fields set by locate_and_pad_parm into a
   separate struct, reducing the number of function parms.  The resulting
   change to callers happens to fix a bug in emit_library_call_value_1
   where alignment_pad was being set for each arg in one loop, then used
   in another loop for each arg.  ie. we used the last arg's
   alignment_pad for all args.
b) Calculates slot_offset in locate_and_pad_parm.  This requires an
   extra input parm to specify partial-in-reg parms, which also lets us
   correct the arg size calculation in the function instead of adjusting
   it externally.  Incidentally fixes a bug in calls.c:
   initialize_argument_information ARGS_GROW_DOWNWARD calculation of
   slot_offset for variable size args by deleting the buggy code.
c) Fixes bugs in locate_and_pad_parm handling of initial_offset_ptr.
   I can't see anything that guarantees when initial_offset_ptr->var
   is non-NULL that initial_offset_ptr->constant == 0, but that's what
   the old code assumes.
d) Removes the hacks in locate_and_pad_parm that fudged the stack offset
   for pad-down reg parms.  Instead we choose slot_offset externally.
   Note! For !ARGS_GROW_DOWNWARD, downward padding and non-BLKmode args,
   this changes the stack home for a reg arg, which shouldn't be a
   problem.  I'm raising the point here for full disclosure.  :)
e) Optimizes a few things in assign_parms.

	* 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.

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre

diff -urp gcc.orig/gcc/calls.c gcc1/gcc/calls.c
--- gcc.orig/gcc/calls.c	2003-04-22 18:55:34.000000000 +0930
+++ gcc1/gcc/calls.c	2003-04-24 11:25:45.000000000 +0930
@@ -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_act
   /* 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_act
 #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, argblo
 
       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, ar
   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;
@@ -3358,7 +3321,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);
 	      }
 
@@ -3507,7 +3470,6 @@ emit_library_call_value_1 (retval, orgfu
   rtx fun;
   int inc;
   int count;
-  struct args_size alignment_pad;
   rtx argblock = 0;
   CUMULATIVE_ARGS args_so_far;
   struct arg
@@ -3516,8 +3478,7 @@ emit_library_call_value_1 (retval, orgfu
     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;
@@ -3677,12 +3638,11 @@ emit_library_call_value_1 (retval, orgfu
 #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);
 
@@ -3796,18 +3756,15 @@ emit_library_call_value_1 (retval, orgfu
 #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);
     }
@@ -3945,11 +3902,11 @@ emit_library_call_value_1 (retval, orgfu
 #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].lcoate.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;
@@ -3962,19 +3919,16 @@ emit_library_call_value_1 (retval, orgfu
 
 	      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);
@@ -3983,8 +3937,9 @@ emit_library_call_value_1 (retval, orgfu
 
 	  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)
@@ -4189,12 +4144,10 @@ emit_library_call_value_1 (retval, orgfu
 	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);
 	  }
@@ -4321,14 +4274,14 @@ store_one_arg (arg, argblock, flags, var
 	  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;
@@ -4341,13 +4294,11 @@ store_one_arg (arg, argblock, flags, var
 
 	  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)
 		{
@@ -4475,8 +4426,8 @@ store_one_arg (arg, argblock, flags, var
 	 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.  */
@@ -4498,16 +4449,17 @@ store_one_arg (arg, argblock, flags, var
       /* 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);
@@ -4521,7 +4473,7 @@ store_one_arg (arg, argblock, flags, var
 	 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)
 	    {
@@ -4533,7 +4485,7 @@ store_one_arg (arg, argblock, flags, var
       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;
 
@@ -4547,17 +4499,17 @@ store_one_arg (arg, argblock, flags, var
 		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;
 		}
 	    }
@@ -4565,8 +4517,8 @@ store_one_arg (arg, argblock, flags, var
 
       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.
diff -urp gcc.orig/gcc/expr.h gcc1/gcc/expr.h
--- gcc.orig/gcc/expr.h	2003-04-22 18:55:34.000000000 +0930
+++ gcc1/gcc/expr.h	2003-04-24 11:29:11.000000000 +0930
@@ -63,6 +63,8 @@ enum expand_modifier {EXPAND_NORMAL = 0,
    more information.  */
 #define OK_DEFER_POP (inhibit_defer_pop -= 1)
 
+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							\
@@ -567,11 +585,9 @@ extern rtx expand_shift PARAMS ((enum tr
 				 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.  */
diff -urp gcc.orig/gcc/function.c gcc1/gcc/function.c
--- gcc.orig/gcc/function.c	2003-04-23 11:29:02.000000000 +0930
+++ gcc1/gcc/function.c	2003-04-24 17:50:45.000000000 +0930
@@ -4338,12 +4338,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;
@@ -4357,8 +4352,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
@@ -4405,6 +4400,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
@@ -4417,14 +4420,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.  */
@@ -4488,7 +4496,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
 	  )
 	{
@@ -4558,27 +4566,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);
@@ -4595,12 +4628,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.
@@ -4609,39 +4636,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)
-#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));
+#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
+	    = (((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.  */
@@ -4672,9 +4691,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.  */
@@ -4698,7 +4717,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;
 
@@ -5021,7 +5040,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)))
 	    {
@@ -5107,7 +5126,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);
 		}
 
@@ -5278,8 +5298,11 @@ promoted_input_arg (regno, pmode, punsig
    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.
@@ -5296,45 +5319,39 @@ promoted_input_arg (regno, pmode, punsig
    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)
@@ -5350,54 +5367,56 @@ locate_and_pad_parm (passed_mode, type, 
     }
 #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
@@ -5405,8 +5424,9 @@ locate_and_pad_parm (passed_mode, type, 
       || 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)
@@ -5415,18 +5435,18 @@ locate_and_pad_parm (passed_mode, type, 
 
   /* 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 */
 }
 
@@ -5465,7 +5485,8 @@ pad_to_arg_alignment (offset_ptr, bounda
 #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);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]