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]

PATCH: Allow downward padding of arguments on systems that define ARGS_GROW_DOWNWARD


This patch modifies calls.c and function.c to allow downward padding
of arguments on systems that define ARGS_GROW_DOWNWARD.  This affects
c4x, dsp16xx, stormy16 and the 32-bit pa ports.  It is needed as part
of a fix for a long standing ABI problem on the PA.

The 32-bit PA-RISC runtime specifies that arguments smaller than 64
bits are to be left extended (i.e., right-justified).  For BLKmode
arguments larger than one word, this differs from the standard big-endian
treatment where blocks are left justified.  This patch provides a
means to obtain downward padding of blocks larger than one word.

There was also a problem with blocks consisting of a single
character or short.  These were also being left justified contrary
to the runtime specification.  This could have been fixed by
defining MEMBER_TYPE_FORCES_BLOCK in the backend but I didn't
like the interaction with the transparent_union attribute.  So,
I decided to pad everything below that wasn't in a register.
Register padding downward is done in different code.

It's possible this patch might break c4x, dsp16xx, or stormy16.
If this should occur, this can easily be corrected by not returning
downward padding in situations where it is not needed.

The patch is not perfect in that the padding obtained is garbage
whereas the HP compiler pads with zeros.  As far as I can tell,
the HP compiler doesn't reference or make any assumptions about
the nature of the padding, so I don't think that this presents
a major compatibility issue.

Previously compiled code that passes small structures, will be
incompatible with new code.  However, the old code was incompatible
with the HP compiler and our va_arg implementation.  So, something
needed fixing.

I have tested the patch with bootstraps and checks with the companion
back-end patch on hppa-unknown-linux-gnu, hppa2.0w-hp-hpux11.00
and hppa64-hp-hpux11.00.  There were no regressions and it fixes
a number of va_arg fails in strct-stdarg-1.c.  As far as I can tell,
there are no remaining problems related to the passing of aggregates.

I have also manually compared the parmeter values passed for a variety
of small structures with those passed by the HP compiler to ensure that
the patch is correct.

OK for main?

Dave
-- 
J. David Anglin                                  dave.anglin@nrc.ca
National Research Council of Canada              (613) 990-0752 (FAX: 952-6605)

2002-09-16  John David Anglin  <dave@hiauly1.hia.nrc.ca>

	* calls.c (store_one_arg): Set default alignment for BLKmode arguments
	to BITS_PER_UNIT when ARGS_GROW_DOWNWARD and the padding direction is
	downward.
	* function.c (pad_below):  Always compile.
	(locate_and_pad_parm): If defined ARGS_GROW_DOWNWARD, pad argument to
	alignment when it is not in a register or REG_PARM_STACK_SPACE is true.
	Pad below when the argument is not in a register and the padding
	direction is downward.

Index: calls.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/calls.c,v
retrieving revision 1.233
diff -u -3 -p -r1.233 calls.c
--- calls.c	12 Sep 2002 14:00:21 -0000	1.233
+++ calls.c	16 Sep 2002 17:50:49 -0000
@@ -4491,6 +4491,7 @@ store_one_arg (arg, argblock, flags, var
     {
       /* BLKmode, at least partly to be pushed.  */
 
+      unsigned int default_align = PARM_BOUNDARY;
       int excess;
       rtx size_rtx;
 
@@ -4498,6 +4499,13 @@ store_one_arg (arg, argblock, flags, var
 	 If part is passed in registers, PARTIAL says how much
 	 and emit_push_insn will take care of putting it there.  */
 
+#ifdef ARGS_GROW_DOWNWARD
+      /* When an argument is padded down, the block is not aligned to
+	 PARM_BOUNDARY.  */
+      if (FUNCTION_ARG_PADDING (arg->mode, TREE_TYPE (pval)) == downward)
+	default_align = BITS_PER_UNIT;
+#endif
+
       /* Round its size up to a multiple
 	 of the allocation unit for arguments.  */
 
@@ -4573,7 +4581,7 @@ store_one_arg (arg, argblock, flags, var
           {
 	    rtx size_rtx1 = GEN_INT (reg_parm_stack_space - arg->offset.constant);
 	    emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx1,
-		            MAX (PARM_BOUNDARY, TYPE_ALIGN (TREE_TYPE (pval))),
+		            MAX (default_align, TYPE_ALIGN (TREE_TYPE (pval))),
 			    partial, reg, excess, argblock,
 			    ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space,
 		            ARGS_SIZE_RTX (arg->alignment_pad));
@@ -4582,7 +4590,7 @@ store_one_arg (arg, argblock, flags, var
 	
 
       emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx,
-		      MAX (PARM_BOUNDARY, TYPE_ALIGN (TREE_TYPE (pval))),
+		      MAX (default_align, TYPE_ALIGN (TREE_TYPE (pval))),
 		      partial, reg, excess, argblock,
 		      ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space,
 		      ARGS_SIZE_RTX (arg->alignment_pad));
Index: function.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/function.c,v
retrieving revision 1.382
diff -u -3 -p -r1.382 function.c
--- function.c	16 Sep 2002 11:41:59 -0000	1.382
+++ function.c	16 Sep 2002 17:50:56 -0000
@@ -255,10 +255,8 @@ static int instantiate_virtual_regs_1 PA
 static void delete_handlers	PARAMS ((void));
 static void pad_to_arg_alignment PARAMS ((struct args_size *, int,
 					  struct args_size *));
-#ifndef ARGS_GROW_DOWNWARD
 static void pad_below		PARAMS ((struct args_size *, enum machine_mode,
 					 tree));
-#endif
 static rtx round_trampoline_addr PARAMS ((rtx));
 static rtx adjust_trampoline_addr PARAMS ((rtx));
 static tree *identify_blocks_1	PARAMS ((rtx, tree *, tree *, tree *));
@@ -5244,6 +5242,9 @@ locate_and_pad_parm (passed_mode, type, 
     = 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
 
 #ifdef REG_PARM_STACK_SPACE
   /* If we have found a stack parm before we reach the end of the
@@ -5289,13 +5290,20 @@ locate_and_pad_parm (passed_mode, type, 
       offset_ptr->constant = -initial_offset_ptr->constant;
       offset_ptr->var = 0;
     }
+
   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);
-  SUB_PARM_SIZE (*offset_ptr, sizetree);
-  if (where_pad != downward)
+    s2 = round_up (s2, PARM_BOUNDARY / BITS_PER_UNIT);
+  SUB_PARM_SIZE (*offset_ptr, s2);
+
+  if (!in_regs
+#ifdef REG_PARM_STACK_SPACE
+      || REG_PARM_STACK_SPACE (fndecl) > 0
+#endif
+     )
     pad_to_arg_alignment (offset_ptr, boundary, alignment_pad);
+
   if (initial_offset_ptr->var)
     arg_size_ptr->var = size_binop (MINUS_EXPR,
 				    size_binop (MINUS_EXPR,
@@ -5307,6 +5315,13 @@ locate_and_pad_parm (passed_mode, type, 
     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);
+
 #else /* !ARGS_GROW_DOWNWARD */
   if (!in_regs
 #ifdef REG_PARM_STACK_SPACE
@@ -5392,7 +5407,6 @@ pad_to_arg_alignment (offset_ptr, bounda
     }
 }
 
-#ifndef ARGS_GROW_DOWNWARD
 static void
 pad_below (offset_ptr, passed_mode, sizetree)
      struct args_size *offset_ptr;
@@ -5420,7 +5434,6 @@ pad_below (offset_ptr, passed_mode, size
 	}
     }
 }
-#endif
 
 /* Walk the tree of blocks describing the binding levels within a function
    and warn about uninitialized variables.


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