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]

fix vector varargs parameter passing on darwin


On 32-bit Darwin and AIX, if you have a named vector parameter, it
gets passed in vector registers but space is reserved (for no good
reason, as far as I can see) for it in GPRs or memory.

So far as I know, this testcase (or semantically equivalent
variations) has never passed on any version of GCC, not even Apple
ones, before this patch.

The ABI is still not compatible with the Darwin/AIX ABI for
non-varargs functions, but only because the ABI specifies that vector
parameters are treated as if they are placed after all other
parameters in the argument list.  (Suggestions as how to implement
this cleanly are welcome.)

Bootstrapped & tested on powerpc-darwin.

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

===File ~/patches/rs6000-darwin-altivarargs.patch===========
2003-11-06  Geoffrey Keating  <geoffk@apple.com>

	* config/rs6000/rs6000.h (USE_FP_FOR_ARG_P): Move to rs6000.c.
	(USE_ALTIVEC_FOR_ARG_P): Likewise.
	* config/rs6000/rs6000.c (USE_FP_FOR_ARG_P): Move from rs6000.h.
	Take a pointer as the CUM parameter.  Update callers.
	(USE_ALTIVEC_FOR_ARG_P): Likewise.  Also correct for Darwin/AIX
	32-bit ABIs.
	(function_arg_advance): Use USE_ALTIVEC_FOR_ARG_P.  Correct case
	of vector parameters as named arguments of stdarg function.
	(function_arg): Likewise.

	* config/rs6000/darwin.h (ASM_SPEC): Use -force_cpusubtype_ALL when
	-maltivec is specified, not the non-existent -faltivec.

Index: gcc/config/rs6000/darwin.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/darwin.h,v
retrieving revision 1.43
diff -u -p -u -p -r1.43 darwin.h
--- gcc/config/rs6000/darwin.h	5 Nov 2003 18:06:22 -0000	1.43
+++ gcc/config/rs6000/darwin.h	6 Nov 2003 21:40:47 -0000
@@ -100,7 +100,7 @@ do {									\
 
 #define ASM_SPEC "-arch ppc \
   %{Zforce_cpusubtype_ALL:-force_cpusubtype_ALL} \
-  %{!Zforce_cpusubtype_ALL:%{faltivec:-force_cpusubtype_ALL}}"
+  %{!Zforce_cpusubtype_ALL:%{maltivec:-force_cpusubtype_ALL}}"
 
 #undef SUBTARGET_EXTRA_SPECS
 #define SUBTARGET_EXTRA_SPECS			\
Index: gcc/config/rs6000/rs6000.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.544
diff -u -p -u -p -r1.544 rs6000.c
--- gcc/config/rs6000/rs6000.c	5 Nov 2003 18:24:53 -0000	1.544
+++ gcc/config/rs6000/rs6000.c	6 Nov 2003 21:40:48 -0000
@@ -3618,6 +3618,19 @@ rs6000_emit_move (rtx dest, rtx source, 
   emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
 }
 
+/* Nonzero if we can use a floating-point register to pass this arg.  */
+#define USE_FP_FOR_ARG_P(CUM,MODE,TYPE)		\
+  (GET_MODE_CLASS (MODE) == MODE_FLOAT		\
+   && (CUM)->fregno <= FP_ARG_MAX_REG		\
+   && TARGET_HARD_FLOAT && TARGET_FPRS)
+
+/* Nonzero if we can use an AltiVec register to pass this arg.  */
+#define USE_ALTIVEC_FOR_ARG_P(CUM,MODE,TYPE,NAMED)	\
+  (ALTIVEC_VECTOR_MODE (MODE)				\
+   && (CUM)->vregno <= ALTIVEC_ARG_MAX_REG		\
+   && TARGET_ALTIVEC_ABI				\
+   && (DEFAULT_ABI == ABI_V4 || (NAMED)))
+
 /* Return a nonzero value to say to return the function value in
    memory, just as large structures are always returned.  TYPE will be
    the data type of the value, and FNTYPE will be the type of the
@@ -3802,23 +3815,35 @@ function_arg_advance (CUMULATIVE_ARGS *c
 
   if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
     {
-      if (named && cum->vregno <= ALTIVEC_ARG_MAX_REG)
+      if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named))
 	cum->vregno++;
-      else
+      
+      /* In variable-argument functions, vector arguments get GPRs allocated
+	 even if they are going to be passed in a vector register.  */
+      if (cum->stdarg && DEFAULT_ABI != ABI_V4)
 	{
 	  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);
+	  /* Vector parameters must be 16-byte aligned.  This places
+	     them at 2 mod 4 in terms of words in 32-bit mode, since
+	     the parameter save area starts at offset 24 from the
+	     stack.  In 64-bit mode, they just have to start on an
+	     even word, since the parameter save area is 16-byte
+	     aligned.  Space for GPRs is reserved even if the argument
+	     will be passed in memory.  */
+	  if (TARGET_32BIT)
+	    align = ((6 - (cum->words & 3)) & 3);
+	  else
+	    align = cum->words & 1;
 	  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));
+		       cum->nargs_prototype, cum->prototype, 
+		       GET_MODE_NAME (mode));
 	    }
 	}
     }
@@ -4099,40 +4124,43 @@ function_arg (CUMULATIVE_ARGS *cum, enum
       return GEN_INT (cum->call_cookie);
     }
 
-  if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
+  if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named))
+    return gen_rtx_REG (mode, cum->vregno);
+  else if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
     {
-      if (named && cum->vregno <= ALTIVEC_ARG_MAX_REG)
-	return gen_rtx_REG (mode, cum->vregno);
-      else if (named || abi == ABI_V4)
+      if (named || abi == ABI_V4)
 	return NULL_RTX;
       else
 	{
 	  /* Vector parameters to varargs functions under AIX or Darwin
 	     get passed in memory and possibly also in GPRs.  */
 	  int align, align_words;
-	  rtx reg;
+	  enum machine_mode part_mode = mode;
 
 	  /* Vector parameters must be 16-byte aligned.  This places them at
-	     2 mod 4 in terms of words.  */
-	  align = ((6 - (cum->words & 3)) & 3);
+	     2 mod 4 in terms of words in 32-bit mode, since the parameter
+	     save area starts at offset 24 from the stack.  In 64-bit mode,
+	     they just have to start on an even word, since the parameter
+	     save area is 16-byte aligned.  */
+	  if (TARGET_32BIT)
+	    align = ((6 - (cum->words & 3)) & 3);
+	  else
+	    align = cum->words & 1;
 	  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)));
+	  /* The vector value goes in GPRs.  Only the part of the
+	     value in GPRs is reported here.  */
+	  if (align_words + CLASS_MAX_NREGS (mode, GENERAL_REGS)
+	      > GP_ARG_NUM_REG)
+	    /* Fortunately, there are only two possibilites, the value
+	       is either wholly in GPRs or half in GPRs and half not.  */
+	    part_mode = DImode;
+	  
+	  return gen_rtx_REG (part_mode, GP_ARG_MIN_REG + align_words);
 	}
     }
   else if (TARGET_SPE_ABI && TARGET_SPE && SPE_VECTOR_MODE (mode))
@@ -4183,7 +4211,7 @@ function_arg (CUMULATIVE_ARGS *cum, enum
 	  && (mode == DFmode || mode == DImode || mode == BLKmode))
 	return rs6000_mixed_function_arg (cum, mode, type, align_words);
 
-      if (USE_FP_FOR_ARG_P (*cum, mode, type))
+      if (USE_FP_FOR_ARG_P (cum, mode, type))
 	{
 	  if (! type
 	      || ((cum->nargs_prototype > 0)
@@ -4228,13 +4256,13 @@ function_arg (CUMULATIVE_ARGS *cum, enum
 
 int
 function_arg_partial_nregs (CUMULATIVE_ARGS *cum, enum machine_mode mode, 
-			    tree type, int named ATTRIBUTE_UNUSED)
+			    tree type, int named)
 {
   if (DEFAULT_ABI == ABI_V4)
     return 0;
 
-  if (USE_FP_FOR_ARG_P (*cum, mode, type)
-      || USE_ALTIVEC_FOR_ARG_P (*cum, mode, type))
+  if (USE_FP_FOR_ARG_P (cum, mode, type)
+      || USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named))
     {
       if (cum->nargs_prototype >= 0)
 	return 0;
Index: gcc/config/rs6000/rs6000.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.h,v
retrieving revision 1.297
diff -u -p -u -p -r1.297 rs6000.h
--- gcc/config/rs6000/rs6000.h	3 Nov 2003 21:44:09 -0000	1.297
+++ gcc/config/rs6000/rs6000.h	6 Nov 2003 21:40:48 -0000
@@ -1800,18 +1800,6 @@ typedef struct rs6000_args
 #define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED)	\
   function_arg_advance (&CUM, MODE, TYPE, NAMED)
 
-/* Nonzero if we can use a floating-point register to pass this arg.  */
-#define USE_FP_FOR_ARG_P(CUM,MODE,TYPE) \
-  (GET_MODE_CLASS (MODE) == MODE_FLOAT  \
-   && (CUM).fregno <= FP_ARG_MAX_REG    \
-   && TARGET_HARD_FLOAT && TARGET_FPRS)
-
-/* Nonzero if we can use an AltiVec register to pass this arg.  */
-#define USE_ALTIVEC_FOR_ARG_P(CUM,MODE,TYPE)	\
-  (ALTIVEC_VECTOR_MODE (MODE)			\
-   && (CUM).vregno <= ALTIVEC_ARG_MAX_REG	\
-   && TARGET_ALTIVEC_ABI)
-
 /* Determine where to put an argument to a function.
    Value is zero to push the argument on the stack,
    or a hard register in which to store the argument.
Index: gcc/testsuite/ChangeLog
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/ChangeLog,v
retrieving revision 1.3172
diff -u -p -u -p -r1.3172 ChangeLog
--- gcc/testsuite/ChangeLog	5 Nov 2003 20:14:58 -0000	1.3172
+++ gcc/testsuite/ChangeLog	6 Nov 2003 21:40:49 -0000
@@ -1,3 +1,14 @@
+2003-11-06  Geoffrey Keating  <geoffk@apple.com>
+
+	* gcc.dg/altivec-varargs-1.c: New test.
+
+2003-10-24  Geoffrey Keating  <geoffk@apple.com>
+
+	PR 11654
+	* gcc.dg/pch/include-1.c: New file.
+	* gcc.dg/pch/include-1.hs: New file.
+	* gcc.dg/pch/include-1a.h: New file.
+
 2003-11-05  Eric Botcazou  <ebotcazou@libertysurf.fr>
 
 	* gcc.c-torture/compile/20031023-4.c: XFAIL on SPARC64
Index: gcc/testsuite/gcc.dg/altivec-varargs-1.c
===================================================================
RCS file: gcc/testsuite/gcc.dg/altivec-varargs-1.c
diff -N gcc/testsuite/gcc.dg/altivec-varargs-1.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gcc/testsuite/gcc.dg/altivec-varargs-1.c	6 Nov 2003 21:40:49 -0000
@@ -0,0 +1,74 @@
+/* { dg-do run { target powerpc*-*-darwin* powerpc*-*-*altivec* } } */
+/* { dg-options "-maltivec" } */
+/* This test requires altivec, which means it'll fail on Darwin running
+   on G3. FIXME.  */
+
+#include <stdarg.h>
+
+#define vector __attribute__((mode(V4SI)))
+
+const vector unsigned int v1 = {10,11,12,13};
+const vector unsigned int v2 = {20,21,22,23};
+const vector unsigned int v3 = {30,31,32,33};
+const vector unsigned int v4 = {40,41,42,43};
+
+void foo(vector unsigned int a, ...)
+{
+  va_list args;
+  vector unsigned int v;
+
+  va_start (args, a);
+  if (memcmp (&a, &v1, sizeof (v)) != 0)
+    abort ();
+  v = va_arg (args, vector unsigned int);
+  if (memcmp (&v, &v2, sizeof (v)) != 0)
+    abort ();
+  v = va_arg (args, vector unsigned int);
+  if (memcmp (&v, &v3, sizeof (v)) != 0)
+    abort ();
+  v = va_arg (args, vector unsigned int);
+  if (memcmp (&v, &v4, sizeof (v)) != 0)
+    abort ();
+  va_end (args);
+}
+
+void bar(vector unsigned int a, ...)
+{
+  va_list args;
+  vector unsigned int v;
+  int b;
+
+  va_start (args, a);
+  if (memcmp (&a, &v1, sizeof (v)) != 0)
+    abort ();
+  b = va_arg (args, int);
+  if (b != 2)
+    abort ();
+  v = va_arg (args, vector unsigned int);
+  if (memcmp (&v, &v2, sizeof (v)) != 0)
+    abort ();
+  v = va_arg (args, vector unsigned int);
+  if (memcmp (&v, &v3, sizeof (v)) != 0)
+    abort ();
+  va_end (args);
+}
+
+
+int main(void)
+{
+  /* In this call, in the Darwin ABI, the first argument goes into v2
+     the second one into r9-r10 and memory,
+     and the next two in memory.  */
+  foo ((vector unsigned int){10,11,12,13},
+       (vector unsigned int){20,21,22,23},
+       (vector unsigned int){30,31,32,33},
+       (vector unsigned int){40,41,42,43});
+  /* In this call, in the Darwin ABI, the first argument goes into v2
+     the second one into r9, then r10 is reserved and
+     there are two words of padding in memory, and the next two arguments
+     go after the padding.  */
+  bar ((vector unsigned int){10,11,12,13}, 2,
+       (vector unsigned int){20,21,22,23},
+       (vector unsigned int){30,31,32,33});
+  return 0;
+}
============================================================


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