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] Fix va_start on x86_64 after any named argument passed on the stack that needed padding (PR target/44942)


Hi!

When say one integer argument is passed on the stack (because all regs are
already used by earlier arguments) and then long double is passed, it is
padded on the stack to 16 byte boundary on x86-64 (similarly for a bunch of
other argument types).  Unfortunately cum->words isn't adjusted for this
padding and thus ap.overflow_arg_area is set to a wrong address.

It seems cum->words is only ever used by ix86_va_start (for -m64 only
and not for MS ABI), so this patch shouldn't affect anything but
__builtin_va_start expansion.

Bootstrapped/regtested on x86_64-linux and i686-linux, tested with
compat.exp and struct-layout-1.exp also against older gcc in
ALT_CC_UNDER_TEST/ALT_CXX_UNDER_TEST.  Ok for trunk?

What about release branches after a while on the trunk? 
While this probably isn't a regression, it is quite bad wrong code bug.

2010-07-15  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
@@ -140,8 +140,8 @@ extern enum machine_mode ix86_fp_compare
 extern rtx ix86_libcall_value (enum machine_mode);
 extern bool ix86_function_arg_regno_p (int);
 extern void ix86_asm_output_function_label (FILE *, const char *, tree);
-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;
+}

	Jakub


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