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]

handle arguments with 16-byte alignment for Xtensa


This patch fixes the handling of function arguments with 16-byte alignment for the Xtensa port. The previous code could only handle a maximum of 8-byte alignment. The fix involves a minor change to the va_list implementation; this will break binary compatibility with previous versions of GCC for things like vfprintf where a va_list is passed as an argument.

Tested with an xtensa-elf target and confirmed that this patch fixes the va-arg-25 test that had previously been failing. Committed on the mainline and 3.4 branch.

I'm now working on a patch to the gcc-3.4/changes.html file to describe this change and the one I made yesterday....


2004-03-05 Bob Wilson <bob.wilson@acm.org>


	* config/xtensa/xtensa.c (function_arg): Handle 16-byte aligned args.
	(xtensa_va_start): Initialize __va_stk to ($arg_ptr - 32).  Adjust
	__va_ndx by 2 words when referencing an argument on the stack.
	(xtensa_va_arg): Handle 16-byte aligned args.  Adjust __va_ndx by 2
	words when an arg on the stack is first seen.

Index: xtensa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/xtensa/xtensa.c,v
retrieving revision 1.52
diff -u -p -r1.52 xtensa.c
--- xtensa.c	5 Mar 2004 01:13:43 -0000	1.52
+++ xtensa.c	5 Mar 2004 21:18:09 -0000
@@ -1805,7 +1805,10 @@ function_arg (CUMULATIVE_ARGS *cum, enum
 	    : int_size_in_bytes (type)) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
 
   if (type && (TYPE_ALIGN (type) > BITS_PER_WORD))
-    *arg_words += (*arg_words & 1);
+    {
+      int align = TYPE_ALIGN (type) / BITS_PER_WORD;
+      *arg_words = (*arg_words + align - 1) & -align;
+    }
 
   if (*arg_words + words > max)
     return (rtx)0;
@@ -2335,17 +2338,20 @@ xtensa_return_addr (int count, rtx frame
 
 
 /* Create the va_list data type.
-   This structure is set up by __builtin_saveregs.  The __va_reg
-   field points to a stack-allocated region holding the contents of the
-   incoming argument registers.  The __va_ndx field is an index initialized
-   to the position of the first unnamed (variable) argument.  This same index
-   is also used to address the arguments passed in memory.  Thus, the
-   __va_stk field is initialized to point to the position of the first
-   argument in memory offset to account for the arguments passed in
-   registers.  E.G., if there are 6 argument registers, and each register is
-   4 bytes, then __va_stk is set to $sp - (6 * 4); then __va_reg[N*4]
-   references argument word N for 0 <= N < 6, and __va_stk[N*4] references
-   argument word N for N >= 6.  */
+
+   This structure is set up by __builtin_saveregs.  The __va_reg field
+   points to a stack-allocated region holding the contents of the
+   incoming argument registers.  The __va_ndx field is an index
+   initialized to the position of the first unnamed (variable)
+   argument.  This same index is also used to address the arguments
+   passed in memory.  Thus, the __va_stk field is initialized to point
+   to the position of the first argument in memory offset to account
+   for the arguments passed in registers and to account for the size
+   of the argument registers not being 16-byte aligned.  E.G., there
+   are 6 argument registers of 4 bytes each, but we want the __va_ndx
+   for the first stack argument to have the maximal alignment of 16
+   bytes, so we offset the __va_stk address by 32 bytes so that
+   __va_stk[32] references the first argument on the stack.  */
 
 static tree
 xtensa_build_builtin_va_list (void)
@@ -2436,15 +2442,18 @@ xtensa_va_start (tree valist, rtx nextar
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
 
-  /* Set the __va_stk member to $arg_ptr - (size of __va_reg area) */
+  /* Set the __va_stk member to ($arg_ptr - 32).  */
   u = make_tree (ptr_type_node, virtual_incoming_args_rtx);
-  u = fold (build (PLUS_EXPR, ptr_type_node, u,
-		   build_int_2 (-MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD, -1)));
+  u = fold (build (PLUS_EXPR, ptr_type_node, u, build_int_2 (-32, -1)));
   t = build (MODIFY_EXPR, ptr_type_node, stk, u);
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
 
-  /* Set the __va_ndx member.  */
+  /* Set the __va_ndx member.  If the first variable argument is on
+     the stack, adjust __va_ndx by 2 words to account for the extra
+     alignment offset for __va_stk.  */
+  if (arg_words >= MAX_ARGS_IN_REGISTERS)
+    arg_words += 2;
   u = build_int_2 (arg_words * UNITS_PER_WORD, 0);
   t = build (MODIFY_EXPR, integer_type_node, ndx, u);
   TREE_SIDE_EFFECTS (t) = 1;
@@ -2506,17 +2515,19 @@ xtensa_va_arg (tree valist, tree type)
     emit_move_insn (va_size, r);
 
 
-  /* First align __va_ndx to a double word boundary if necessary for this arg:
+  /* First align __va_ndx if necessary for this arg:
 
-     if (__alignof__ (TYPE) > 4)
-       (AP).__va_ndx = (((AP).__va_ndx + 7) & -8); */
+     if (__alignof__ (TYPE) > 4 )
+       (AP).__va_ndx = (((AP).__va_ndx + __alignof__ (TYPE) - 1)
+			& -__alignof__ (TYPE)); */
 
   if (TYPE_ALIGN (type) > BITS_PER_WORD)
     {
+      int align = TYPE_ALIGN (type) / BITS_PER_UNIT;
       tmp = build (PLUS_EXPR, integer_type_node, ndx,
-		   build_int_2 ((2 * UNITS_PER_WORD) - 1, 0));
+		   build_int_2 (align - 1, 0));
       tmp = build (BIT_AND_EXPR, integer_type_node, tmp,
-		   build_int_2 (-2 * UNITS_PER_WORD, -1));
+		   build_int_2 (-align, -1));
       tmp = build (MODIFY_EXPR, integer_type_node, ndx, tmp);
       TREE_SIDE_EFFECTS (tmp) = 1;
       expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -2574,18 +2585,18 @@ xtensa_va_arg (tree valist, tree type)
 
      else
        {
-	 if (orig_ndx < __MAX_ARGS_IN_REGISTERS * 4)
-	     (AP).__va_ndx = __MAX_ARGS_IN_REGISTERS * 4 + __va_size (TYPE);
+	 if (orig_ndx <= __MAX_ARGS_IN_REGISTERS * 4)
+	     (AP).__va_ndx = 32 + __va_size (TYPE);
 	 __array = (AP).__va_stk;
        } */
 
   lab_false2 = gen_label_rtx ();
   emit_cmp_and_jump_insns (orig_ndx,
 			   GEN_INT (MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD),
-			   GE, const1_rtx, SImode, 0, lab_false2);
+			   GT, const1_rtx, SImode, 0, lab_false2);
 
   tmp = build (PLUS_EXPR, sizetype, make_tree (intSI_type_node, va_size),
-	       build_int_2 (MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD, 0));
+	       build_int_2 (32, 0));
   tmp = build (MODIFY_EXPR, integer_type_node, ndx, tmp);
   TREE_SIDE_EFFECTS (tmp) = 1;
   expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL);

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