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]

final version of rs6000 altivec non-ELF varargs ABI patch


This is the patch described in

<http://gcc.gnu.org/ml/gcc-patches/2003-09/msg01757.html>

plus:

- It's been tested on PA, and appears to work.  Good!
- It didn't work on sparc.  Another attempt to fix the problem also
  failed, see <http://gcc.gnu.org/ml/gcc-patches/2003-10/msg00461.html>.
  The underlying problem needs someone who actually has
  a sparc to work on it.  I have put big FIXME comments pointing
  out the problem, and have temporarily suppressed this patch in
  the problematic case, in a really ugly way.
- This patch also adds the appropriate changes to the rs6000 port.
  FSF GCC is now ABI-compatible with the native compiler on Darwin,
  and conforms to the AIX ABI for varargs functions with vector
  arguments.  It's still not right for functions with vector arguments
  that are not varargs under some circumstances (although it might
  be good enough for all the system functions).
- Testcases!

This has been boostrapped & tested on powerpc-darwin, and I checked
that the testcases both fail without this patch.

-- 
- Geoffrey Keating <geoffk@apple.com>

===File ~/patches/gcc-functionargalign-A-2.patch============
2003-10-07  Geoffrey Keating  <geoffk@apple.com>

	* function.c (pad_to_arg_alignment): Take STACK_POINTER_OFFSET into
	account	when aligning arguments.
	* calls.c (STACK_POINTER_OFFSET): Move default from here ...
	* defaults.h (STACK_POINTER_OFFSET): ... to here.
	* config/sparc/sparc.h (STACK_BOUNDARY): Add comment about how
	it's wrong when TARGET_ARCH64 && TARGET_STACK_BIAS.
	(SPARC_STACK_BOUNDARY_HACK): Define.
	* config/rs6000/rs6000.c (function_arg): On non-SVR4 systems,
	arrange for vector parameters to varargs functions to be passed
	in both memory and GPRs when appropriate.
	(rs6000_va_arg): Vector arguments passed in memory are 16-byte
	aligned.

Index: testsuite/ChangeLog
2003-10-07  Geoffrey Keating  <geoffk@apple.com>

	* gcc.dg/darwin-abi-2.c: New file.
	* gcc.c-torture/execute/va-arg-24.c: New file.

Index: calls.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/calls.c,v
retrieving revision 1.303
diff -u -p -p -u -r1.303 calls.c
--- calls.c	5 Oct 2003 19:50:54 -0000	1.303
+++ calls.c	7 Oct 2003 19:32:50 -0000
@@ -41,10 +41,6 @@ Software Foundation, 59 Temple Place - S
 #include "cgraph.h"
 #include "except.h"
 
-#ifndef STACK_POINTER_OFFSET
-#define STACK_POINTER_OFFSET    0
-#endif
-
 /* Like PREFERRED_STACK_BOUNDARY but in units of bytes, not bits.  */
 #define STACK_BYTES (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT)
 
Index: defaults.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/defaults.h,v
retrieving revision 1.115
diff -u -p -p -u -r1.115 defaults.h
--- defaults.h	2 Oct 2003 00:44:13 -0000	1.115
+++ defaults.h	7 Oct 2003 19:32:50 -0000
@@ -679,4 +679,8 @@ You Lose!  You must define PREFERRED_DEB
 #define MOVE_MAX_PIECES   MOVE_MAX
 #endif
 
+#ifndef STACK_POINTER_OFFSET
+#define STACK_POINTER_OFFSET    0
+#endif
+
 #endif  /* ! GCC_DEFAULTS_H */
Index: function.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/function.c,v
retrieving revision 1.460
diff -u -p -p -u -r1.460 function.c
--- function.c	5 Oct 2003 19:50:54 -0000	1.460
+++ function.c	7 Oct 2003 19:32:51 -0000
@@ -5511,6 +5511,16 @@ pad_to_arg_alignment (struct args_size *
 {
   tree save_var = NULL_TREE;
   HOST_WIDE_INT save_constant = 0;
+  HOST_WIDE_INT sp_offset = STACK_POINTER_OFFSET;
+
+#ifdef SPARC_STACK_BOUNDARY_HACK
+  /* The sparc port has a bug.  It sometimes claims a STACK_BOUNDARY
+     higher than the real alignment of %sp.  However, when it does this,
+     the alignment of %sp+STACK_POINTER_OFFSET will be STACK_BOUNDARY.
+     This is a temporary hack while the sparc port is fixed.  */
+  if (SPARC_STACK_BOUNDARY_HACK)
+    sp_offset = 0;
+#endif
 
   int boundary_in_bytes = boundary / BITS_PER_UNIT;
 
@@ -5527,14 +5537,17 @@ pad_to_arg_alignment (struct args_size *
     {
       if (offset_ptr->var)
 	{
-	  offset_ptr->var =
+	  tree sp_offset_tree = ssize_int (sp_offset);
+	  tree offset = size_binop (PLUS_EXPR,
+				    ARGS_SIZE_TREE (*offset_ptr),
+				    sp_offset_tree);
 #ifdef ARGS_GROW_DOWNWARD
-	    round_down
+	  tree rounded = round_down (offset, boundary / BITS_PER_UNIT);
 #else
-	    round_up
+	  tree rounded = round_up   (offset, boundary / BITS_PER_UNIT);
 #endif
-	      (ARGS_SIZE_TREE (*offset_ptr),
-	       boundary / BITS_PER_UNIT);
+
+	  offset_ptr->var = size_binop (MINUS_EXPR, rounded, sp_offset_tree);
 	  /* ARGS_SIZE_TREE includes constant term.  */
 	  offset_ptr->constant = 0;
 	  if (boundary > PARM_BOUNDARY && boundary > STACK_BOUNDARY)
@@ -5543,11 +5556,11 @@ pad_to_arg_alignment (struct args_size *
 	}
       else
 	{
-	  offset_ptr->constant =
+	  offset_ptr->constant = -sp_offset +
 #ifdef ARGS_GROW_DOWNWARD
-	    FLOOR_ROUND (offset_ptr->constant, boundary_in_bytes);
+	    FLOOR_ROUND (offset_ptr->constant + sp_offset, boundary_in_bytes);
 #else
-	    CEIL_ROUND (offset_ptr->constant, boundary_in_bytes);
+	    CEIL_ROUND (offset_ptr->constant + sp_offset, boundary_in_bytes);
 #endif
 	    if (boundary > PARM_BOUNDARY && boundary > STACK_BOUNDARY)
 	      alignment_pad->constant = offset_ptr->constant - save_constant;
Index: config/rs6000/rs6000.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.527
diff -u -p -p -u -r1.527 rs6000.c
--- config/rs6000/rs6000.c	7 Oct 2003 19:23:07 -0000	1.527
+++ config/rs6000/rs6000.c	7 Oct 2003 19:32:52 -0000
@@ -3732,10 +3747,25 @@ function_arg_advance (CUMULATIVE_ARGS *c
 
   if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
     {
-      if (cum->vregno <= ALTIVEC_ARG_MAX_REG && cum->nargs_prototype >= 0)
+      if (named && cum->vregno <= ALTIVEC_ARG_MAX_REG)
 	cum->vregno++;
       else
-	cum->words += RS6000_ARG_SIZE (mode, type);
+	{
+	  int align;
+	  
+	  /* Vector parameters must be 16-byte aligned.  This places them at
+	     2 mod 4 in terms of words (on both ABIs).  */
+	  align = ((6 - (cum->words & 3)) & 3);
+	  cum->words += align + RS6000_ARG_SIZE (mode, type);
+
+	  if (TARGET_DEBUG_ARG)
+	    {
+	      fprintf (stderr, "function_adv: words = %2d, align=%d, ", 
+		       cum->words, align);
+	      fprintf (stderr, "nargs = %4d, proto = %d, mode = %4s\n",
+		       cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode));
+	    }
+	}
     }
   else if (TARGET_SPE_ABI && TARGET_SPE && SPE_VECTOR_MODE (mode)
 	   && !cum->stdarg
@@ -3913,8 +3943,37 @@ function_arg (CUMULATIVE_ARGS *cum, enum
     {
       if (named && cum->vregno <= ALTIVEC_ARG_MAX_REG)
 	return gen_rtx_REG (mode, cum->vregno);
+      else if (named || abi == ABI_V4)
+	return NULL_RTX;
       else
-	return NULL;
+	{
+	  /* Vector parameters to varargs functions under AIX or Darwin
+	     get passed in memory and possibly also in GPRs.  */
+	  int align, align_words;
+	  rtx reg;
+
+	  /* Vector parameters must be 16-byte aligned.  This places them at
+	     2 mod 4 in terms of words.  */
+	  align = ((6 - (cum->words & 3)) & 3);
+	  align_words = cum->words + align;
+
+	  /* Out of registers?  Memory, then.  */
+	  if (align_words >= GP_ARG_NUM_REG)
+	    return NULL_RTX;
+	  
+	  /* The vector value goes in both memory and GPRs.  Varargs
+	     vector regs will always be saved in R5-R8 or R9-R12.  */
+	  reg = gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
+
+	  return gen_rtx_PARALLEL (mode,
+				   gen_rtvec (2,
+					      gen_rtx_EXPR_LIST (VOIDmode,
+								 NULL_RTX, 
+								 const0_rtx),
+					      gen_rtx_EXPR_LIST (VOIDmode,
+								 reg, 
+								 const0_rtx)));
+	}
     }
   else if (TARGET_SPE_ABI && TARGET_SPE && SPE_VECTOR_MODE (mode))
     return rs6000_spe_function_arg (cum, mode, type);
@@ -4302,7 +4361,29 @@ rs6000_va_arg (tree valist, tree type)
 	  return expand_expr (t, NULL_RTX, VOIDmode, EXPAND_NORMAL);
 	}
       else
-	return std_expand_builtin_va_arg (valist, type);
+	{
+	  /* Altivec arguments must be aligned to a 128-bit boundary.  */
+	  if (ALTIVEC_VECTOR_MODE (TYPE_MODE (type)))
+	    {
+	      tree vtype = TREE_TYPE (valist);
+	      tree new_valist, modify;
+	      
+	      /* Round address up to multiple of 16.  Computes
+		 (addr+15)&~0xf.  */
+	      new_valist = fold (build (BIT_AND_EXPR, vtype,
+					fold (build (PLUS_EXPR, vtype, valist,
+						     build_int_2 (15, 0))),
+					build_int_2 (~15, -1)));
+
+	      /* Update valist.  */
+	      modify = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
+			      new_valist);
+	      TREE_SIDE_EFFECTS (modify) = 1;
+	      expand_expr (modify, const0_rtx, VOIDmode, EXPAND_NORMAL);
+	    }
+	  
+	  return std_expand_builtin_va_arg (valist, type);
+	}
     }
 
   f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
Index: config/sparc/sparc.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/sparc/sparc.h,v
retrieving revision 1.234
diff -u -p -p -u -r1.234 sparc.h
--- config/sparc/sparc.h	2 Oct 2003 00:44:28 -0000	1.234
+++ config/sparc/sparc.h	7 Oct 2003 19:32:52 -0000
@@ -780,7 +780,13 @@ if (TARGET_ARCH64				\
 #define PARM_BOUNDARY (TARGET_ARCH64 ? 64 : 32)
 
 /* Boundary (in *bits*) on which stack pointer should be aligned.  */
+/* FIXME, this is wrong when TARGET_ARCH64 and TARGET_STACK_BIAS, because
+   then sp+2047 is 128-bit aligned so sp is really only byte-aligned.  */
 #define STACK_BOUNDARY (TARGET_ARCH64 ? 128 : 64)
+/* Temporary hack until the FIXME above is fixed.  This macro is used
+   only in pad_to_arg_alignment in function.c; see the comment there
+   for details about what it does.  */
+#define SPARC_STACK_BOUNDARY_HACK (TARGET_ARCH64 && TARGET_STACK_BIAS)
 
 /* ALIGN FRAMES on double word boundaries */
 
Index: testsuite/gcc.c-torture/execute/va-arg-24.c
===================================================================
RCS file: testsuite/gcc.c-torture/execute/va-arg-24.c
diff -N testsuite/gcc.c-torture/execute/va-arg-24.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.c-torture/execute/va-arg-24.c	7 Oct 2003 19:32:55 -0000
@@ -0,0 +1,34 @@
+/* Varargs and vectors!  */
+
+#include <stdarg.h>
+
+#define vector __attribute__((vector_size(16)))
+
+const vector unsigned int v1 = {10,11,12,13};
+const vector unsigned int v2 = {20,21,22,23};
+
+void foo(int a, ...)
+{
+  va_list args;
+  vector unsigned int v;
+
+  va_start (args, a);
+  v = va_arg (args, vector unsigned int);
+  if (a != 1 || memcmp (&v, &v1, sizeof (v)) != 0)
+    abort ();
+  a = va_arg (args, int);
+  if (a != 2)
+    abort ();
+  v = va_arg (args, vector unsigned int);
+  if (memcmp (&v, &v2, sizeof (v) != 0))
+    abort ();
+  va_end (args);
+}
+
+int main(void)
+{
+  foo (1, (vector unsigned int){10,11,12,13}, 2,
+       (vector unsigned int){14,15,16,17});
+  return 0;
+}
+
Index: testsuite/gcc.dg/darwin-abi-2.c
===================================================================
RCS file: testsuite/gcc.dg/darwin-abi-2.c
diff -N testsuite/gcc.dg/darwin-abi-2.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.dg/darwin-abi-2.c	7 Oct 2003 19:32:55 -0000
@@ -0,0 +1,23 @@
+/* { dg-do run { target powerpc*-*-darwin* } } */
+
+/* You might think you'd need -maltivec for this, but actually you
+   don't; GCC will happily do everything in GPRs, and it still
+   tests that the ABI is correct.  */
+
+#include <stdio.h>
+
+#define vector __attribute__((vector_size(16)))
+
+int main(void)
+{
+  vector unsigned int v = { 100, 200, 300, 400 };
+  vector unsigned int w = { 4, 5, 6, 7 };
+  char x[64];
+  sprintf (x, "%lvu,%d,%lvu", v, 1, w);
+  if (strcmp (x, "100 200 300 400,1,4 5 6 7") != 0)
+    {
+      puts (x);
+      abort ();
+    }
+  return 0;
+}
============================================================


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