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]

Reserving stack space on a per-argument basis


FUNCTION_ARG may return a PARALLEL containing a NULL_RTX, indicating
that a copy of an argument must be passed on the stack.  I'm working
on a port whose ABI requires stack space to be reserved for certain
types of arguments passed in registers.  In order to not waste the CPU
and memory cycles of creating a useless copy of such registers in
memory, I've come up with this patch.  Behavior is unchanged in ports
that don't use this new feature.  Ok to install?

Index: gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* tm.texi (FUNCTION_ARG): Document use of NULL_RTX in the last
	entry of a PARALLEL.
	* expr.c (emit_group_load, emit_group_store): Disregard such
	uses.
	* function.c (assign_parms): Take them into account when
	computing stack usage.
	* calls.c (initialize_argument_information): Likewise.

Index: gcc/calls.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/calls.c,v
retrieving revision 1.168
diff -u -p -r1.168 calls.c
--- gcc/calls.c 2000/11/30 20:15:10 1.168
+++ gcc/calls.c 2000/12/18 06:17:55
@@ -1125,6 +1125,7 @@ initialize_argument_information (num_act
       tree type = TREE_TYPE (TREE_VALUE (p));
       int unsignedp;
       enum machine_mode mode;
+      int reserve_stack_space = 0;
 
       args[i].tree_value = TREE_VALUE (p);
 
@@ -1270,9 +1271,16 @@ initialize_argument_information (num_act
       /* 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 (args[i].reg && GET_CODE (args[i].reg) == PARALLEL)
+	{
+	  if (XEXP (XVECEXP (args[i].reg, 0, 0), 0) == NULL_RTX)
+	    args[i].pass_on_stack = 1;
+	  else if (XVECLEN (args[i].reg, 0) > 1
+		   && (XEXP (XVECEXP (args[i].reg, 0,
+				      XVECLEN (args[i].reg, 0) - 1), 0)
+		       == NULL_RTX))
+	    reserve_stack_space = 1;
+	}
 
       /* If this is an addressable type, we must preallocate the stack
 	 since we must evaluate the object into its final location.
@@ -1291,7 +1299,8 @@ initialize_argument_information (num_act
       /* 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)
+	  || args[i].pass_on_stack
+	  || reserve_stack_space)
 	locate_and_pad_parm (mode, type,
 #ifdef STACK_PARMS_IN_REG_PARM_AREA
 			     1,
Index: gcc/function.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/function.c,v
retrieving revision 1.235
diff -u -p -r1.235 function.c
--- gcc/function.c 2000/12/15 09:09:41 1.235
+++ gcc/function.c 2000/12/18 06:17:55
@@ -4505,7 +4505,11 @@ assign_parms (fndecl)
 
       if (entry_parm == stack_parm
           || (GET_CODE (entry_parm) == PARALLEL
-              && XEXP (XVECEXP (entry_parm, 0, 0), 0) == NULL_RTX)
+              && (XEXP (XVECEXP (entry_parm, 0, 0), 0) == NULL_RTX
+		  || (XVECLEN (entry_parm, 0) > 1
+		      && (XEXP (XVECEXP (entry_parm, 0,
+					 XVECLEN (entry_parm, 0) - 1), 0)
+			  == NULL_RTX))))
 #if defined (REG_PARM_STACK_SPACE) && ! defined (MAYBE_REG_PARM_STACK_SPACE)
 	  /* On some machines, even if a parm value arrives in a register
 	     there is still an (uninitialized) stack slot allocated for it.
Index: gcc/expr.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/expr.c,v
retrieving revision 1.282
diff -u -p -r1.282 expr.c
--- gcc/expr.c 2000/12/09 03:42:29 1.282
+++ gcc/expr.c 2000/12/18 06:17:57
@@ -1919,7 +1919,7 @@ move_block_from_reg (regno, x, nregs, si
    registers represented by a PARALLEL.  SSIZE represents the total size of
    block SRC in bytes, or -1 if not known.  ALIGN is the known alignment of
    SRC in bits.  */
-/* ??? If SSIZE % UNITS_PER_WORD != 0, we make the blatent assumption that
+/* ??? If SSIZE % UNITS_PER_WORD != 0, we make the blatant assumption that
    the balance will be in what would be the low-order memory addresses, i.e.
    left justified for big endian, right justified for little endian.  This
    happens to be true for the targets currently using this support.  If this
@@ -1933,18 +1933,25 @@ emit_group_load (dst, orig_src, ssize, a
      int ssize;
 {
   rtx *tmps, src;
-  int start, i;
+  int start, i, len;
 
   if (GET_CODE (dst) != PARALLEL)
     abort ();
 
   /* Check for a NULL entry, used to indicate that the parameter goes
      both on the stack and in registers.  */
-  if (XEXP (XVECEXP (dst, 0, 0), 0))
+  if (XEXP (XVECEXP (dst, 0, 0), 0) != NULL_RTX)
     start = 0;
   else
     start = 1;
 
+  len = XVECLEN (dst, 0);
+
+  /* Check for a NULL entry at the end, used to indicate that stack
+     space is reserved, but not used, for this argument.  */
+  if (len > 0 && XEXP (XVECEXP (dst, 0, len - 1), 0) == NULL_RTX)
+    len--;
+
   tmps = (rtx *) alloca (sizeof (rtx) * XVECLEN (dst, 0));
 
   /* If we won't be loading directly from memory, protect the real source
@@ -1960,7 +1967,7 @@ emit_group_load (dst, orig_src, ssize, a
     }
 
   /* Process the pieces.  */
-  for (i = start; i < XVECLEN (dst, 0); i++)
+  for (i = start; i < len; i++)
     {
       enum machine_mode mode = GET_MODE (XEXP (XVECEXP (dst, 0, i), 0));
       HOST_WIDE_INT bytepos = INTVAL (XEXP (XVECEXP (dst, 0, i), 1));
@@ -2016,7 +2023,7 @@ emit_group_load (dst, orig_src, ssize, a
   emit_queue ();
 
   /* Copy the extracted pieces into the proper (probable) hard regs.  */
-  for (i = start; i < XVECLEN (dst, 0); i++)
+  for (i = start; i < len; i++)
     emit_move_insn (XEXP (XVECEXP (dst, 0, i), 0), tmps[i]);
 }
 
@@ -2031,22 +2038,29 @@ emit_group_store (orig_dst, src, ssize, 
      unsigned int align;
 {
   rtx *tmps, dst;
-  int start, i;
+  int start, i, len;
 
   if (GET_CODE (src) != PARALLEL)
     abort ();
 
   /* Check for a NULL entry, used to indicate that the parameter goes
      both on the stack and in registers.  */
-  if (XEXP (XVECEXP (src, 0, 0), 0))
+  if (XEXP (XVECEXP (src, 0, 0), 0) != NULL_RTX)
     start = 0;
   else
     start = 1;
 
+  len = XVECLEN (src, 0);
+
+  /* Check for a NULL entry at the end, used to indicate that stack
+     space is reserved, but not used, for this argument.  */
+  if (len > 1 && XEXP (XVECEXP (src, 0, len - 1), 0) == NULL_RTX)
+    len--;
+
   tmps = (rtx *) alloca (sizeof (rtx) * XVECLEN (src, 0));
 
   /* Copy the (probable) hard regs into pseudos.  */
-  for (i = start; i < XVECLEN (src, 0); i++)
+  for (i = start; i < len; i++)
     {
       rtx reg = XEXP (XVECEXP (src, 0, i), 0);
       tmps[i] = gen_reg_rtx (GET_MODE (reg));
@@ -2084,7 +2098,7 @@ emit_group_store (orig_dst, src, ssize, 
     }
 
   /* Process the pieces.  */
-  for (i = start; i < XVECLEN (src, 0); i++)
+  for (i = start; i < len; i++)
     {
       HOST_WIDE_INT bytepos = INTVAL (XEXP (XVECEXP (src, 0, i), 1));
       enum machine_mode mode = GET_MODE (tmps[i]);
Index: gcc/tm.texi
===================================================================
RCS file: /cvs/gcc/egcs/gcc/tm.texi,v
retrieving revision 1.155
diff -u -p -r1.155 tm.texi
--- gcc/tm.texi 2000/12/15 09:09:41 1.155
+++ gcc/tm.texi 2000/12/18 06:17:59
@@ -2919,9 +2919,12 @@ register in which to pass this part of t
 register RTX indicates how large this part of the argument is.  The
 second operand of the @code{expr_list} is a @code{const_int} which gives
 the offset in bytes into the entire argument of where this part starts.
-As a special exception the first @code{expr_list} in the @code{parallel} 
-RTX may have a first operand of zero.  This indicates that the entire
-argument is also stored on the stack.
+As a special exception the first and the last @code{expr_list} in the
+@code{parallel} RTX may have a first operand of @code{NULL_RTX}.  When
+the @code{NULL_RTX} appears in the first @code{expr_list}, it indicates
+that the entire argument is also stored on the stack.  When it appears
+in the last @code{expr_list}, stack space is reserved for the whole
+argument, but this stack space is not used at all.
 
 @cindex @file{stdarg.h} and register arguments
 The usual way to make the ANSI library @file{stdarg.h} work on a machine

-- 
Alexandre Oliva   Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer                  aoliva@{cygnus.com, redhat.com}
CS PhD student at IC-Unicamp        oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist    *Please* write to mailing lists, not to me

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