Blob Blame History Raw
2010-07-16  Jakub Jelinek  <jakub@redhat.com>

	PR target/44942
	* config/i386/i386-protos.h (ix86_function_arg_boundary): Change second
	argument to const_tree.
	* config/i386/i386.c (function_arg_advance): If padding needs to be
	inserted before argument, increment cum->words by number of padding
	words as well.
	(contains_aligned_value_p): Change argument to const_tree.
	(ix86_function_arg_boundary): Change second argument to const_tree.

	* gcc.c-torture/execute/pr44942.c: New test.
	* gcc.target/i386/pr44942.c: New test.

--- gcc/config/i386/i386-protos.h.jj	2010-07-13 15:56:31.000000000 +0200
+++ gcc/config/i386/i386-protos.h	2010-07-15 12:45:01.000000000 +0200
@@ -137,8 +137,8 @@ extern enum machine_mode ix86_fp_compare
 extern rtx ix86_libcall_value (enum machine_mode);
 extern bool ix86_function_value_regno_p (int);
 extern bool ix86_function_arg_regno_p (int);
-extern int ix86_function_arg_boundary (enum machine_mode, tree);
-extern bool ix86_solaris_return_in_memory (const_tree,const_tree);
+extern int ix86_function_arg_boundary (enum machine_mode, const_tree);
+extern bool ix86_solaris_return_in_memory (const_tree, const_tree);
 extern rtx ix86_force_to_memory (enum machine_mode, rtx);
 extern void ix86_free_from_memory (enum machine_mode);
 extern enum calling_abi ix86_cfun_abi (void);
--- gcc/config/i386/i386.c.jj	2010-07-13 15:56:31.000000000 +0200
+++ gcc/config/i386/i386.c	2010-07-15 12:44:31.000000000 +0200
@@ -6157,9 +6157,8 @@ function_arg_advance_64 (CUMULATIVE_ARGS
   if (!named && VALID_AVX256_REG_MODE (mode))
     return;
 
-  if (!examine_argument (mode, type, 0, &int_nregs, &sse_nregs))
-    cum->words += words;
-  else if (sse_nregs <= cum->sse_nregs && int_nregs <= cum->nregs)
+  if (examine_argument (mode, type, 0, &int_nregs, &sse_nregs)
+      && sse_nregs <= cum->sse_nregs && int_nregs <= cum->nregs)
     {
       cum->nregs -= int_nregs;
       cum->sse_nregs -= sse_nregs;
@@ -6167,7 +6166,11 @@ function_arg_advance_64 (CUMULATIVE_ARGS
       cum->sse_regno += sse_nregs;
     }
   else
-    cum->words += words;
+    {
+      int align = ix86_function_arg_boundary (mode, type) / BITS_PER_WORD;
+      cum->words = (cum->words + align - 1) & ~(align - 1);
+      cum->words += words;
+    }
 }
 
 static void
@@ -6508,7 +6511,7 @@ ix86_pass_by_reference (CUMULATIVE_ARGS 
 /* Return true when TYPE should be 128bit aligned for 32bit argument passing
    ABI.  */
 static bool
-contains_aligned_value_p (tree type)
+contains_aligned_value_p (const_tree type)
 {
   enum machine_mode mode = TYPE_MODE (type);
   if (((TARGET_SSE && SSE_REG_MODE_P (mode))
@@ -6558,7 +6561,7 @@ contains_aligned_value_p (tree type)
    specified mode and type.  */
 
 int
-ix86_function_arg_boundary (enum machine_mode mode, tree type)
+ix86_function_arg_boundary (enum machine_mode mode, const_tree type)
 {
   int align;
   if (type)
--- gcc/testsuite/gcc.c-torture/execute/pr44942.c.jj	2010-07-15 13:41:28.000000000 +0200
+++ gcc/testsuite/gcc.c-torture/execute/pr44942.c	2010-07-15 13:46:40.000000000 +0200
@@ -0,0 +1,70 @@
+/* PR target/44942 */
+
+#include <stdarg.h>
+
+void
+test1 (int a, int b, int c, int d, int e, int f, int g, long double h, ...)
+{
+  int i;
+  va_list ap;
+
+  va_start (ap, h);
+  i = va_arg (ap, int);
+  if (i != 1234)
+    __builtin_abort ();
+  va_end (ap);
+}
+
+void
+test2 (int a, int b, int c, int d, int e, int f, int g, long double h, int i,
+       long double j, int k, long double l, int m, long double n, ...)
+{
+  int o;
+  va_list ap;
+
+  va_start (ap, n);
+  o = va_arg (ap, int);
+  if (o != 1234)
+    __builtin_abort ();
+  va_end (ap);
+}
+
+void
+test3 (double a, double b, double c, double d, double e, double f,
+       double g, long double h, ...)
+{
+  double i;
+  va_list ap;
+
+  va_start (ap, h);
+  i = va_arg (ap, double);
+  if (i != 1234.0)
+    __builtin_abort ();
+  va_end (ap);
+}
+
+void
+test4 (double a, double b, double c, double d, double e, double f, double g,
+       long double h, double i, long double j, double k, long double l,
+       double m, long double n, ...)
+{
+  double o;
+  va_list ap;
+
+  va_start (ap, n);
+  o = va_arg (ap, double);
+  if (o != 1234.0)
+    __builtin_abort ();
+  va_end (ap);
+}
+
+int
+main ()
+{
+  test1 (0, 0, 0, 0, 0, 0, 0, 0.0L, 1234);
+  test2 (0, 0, 0, 0, 0, 0, 0, 0.0L, 0, 0.0L, 0, 0.0L, 0, 0.0L, 1234);
+  test3 (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0L, 1234.0);
+  test4 (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0L, 0.0, 0.0L,
+	 0.0, 0.0L, 0.0, 0.0L, 1234.0);
+  return 0;
+}
--- gcc/testsuite/gcc.target/i386/pr44942.c.jj	2010-07-15 13:52:37.000000000 +0200
+++ gcc/testsuite/gcc.target/i386/pr44942.c	2010-07-15 13:53:24.000000000 +0200
@@ -0,0 +1,44 @@
+/* PR target/44942 */
+/* { dg-do run { target lp64 } } */
+
+#include <stdarg.h>
+#include <emmintrin.h>
+
+void
+test1 (double a, double b, double c, double d, double e, double f,
+       double g, __m128d h, ...)
+{
+  double i;
+  va_list ap;
+
+  va_start (ap, h);
+  i = va_arg (ap, double);
+  if (i != 1234.0)
+    __builtin_abort ();
+  va_end (ap);
+}
+
+void
+test2 (double a, double b, double c, double d, double e, double f, double g,
+       __m128d h, double i, __m128d j, double k, __m128d l,
+       double m, __m128d n, ...)
+{
+  double o;
+  va_list ap;
+
+  va_start (ap, n);
+  o = va_arg (ap, double);
+  if (o != 1234.0)
+    __builtin_abort ();
+  va_end (ap);
+}
+
+int
+main ()
+{
+  __m128d m = _mm_set1_pd (7.0);
+  test1 (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, m, 1234.0);
+  test2 (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, m, 0.0, m,
+	 0.0, m, 0.0, m, 1234.0);
+  return 0;
+}