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]

[SPARC] Fix bug in small unions argument handling


In 64-bit mode, when a union is larger than a word but smaller than two words, 
and passed in the 6th slot, we correctly compute that it must be passed 
partially in register and partially on the stack.  But we build a 2-element 
PARALLEL, which means that %o6 (aka %sp) is clobbered at runtime.

Fixed by building a PARALLEL with only one element.  Bootstrapped, regtested, 
compat-tested against 3.4.2 on sparc64-sun-solaris2.9. ?It fixes:

FAIL: tmpdir-gcc.dg-struct-layout-1/t001 c_compat_x_tst.o-c_compat_y_tst.o 
execute 
FAIL: tmpdir-gcc.dg-struct-layout-1/t002 c_compat_x_tst.o-c_compat_y_tst.o 
execute 
FAIL: tmpdir-gcc.dg-struct-layout-1/t003 c_compat_x_tst.o-c_compat_y_tst.o 
execute 
FAIL: tmpdir-gcc.dg-struct-layout-1/t004 c_compat_x_tst.o-c_compat_y_tst.o 
execute 
FAIL: tmpdir-gcc.dg-struct-layout-1/t005 c_compat_x_tst.o-c_compat_y_tst.o 
execute 
FAIL: tmpdir-gcc.dg-struct-layout-1/t006 c_compat_x_tst.o-c_compat_y_tst.o 
execute 
FAIL: tmpdir-gcc.dg-struct-layout-1/t007 c_compat_x_tst.o-c_compat_y_tst.o 
execute 
FAIL: tmpdir-gcc.dg-struct-layout-1/t009 c_compat_x_tst.o-c_compat_y_tst.o 
execute 
FAIL: tmpdir-gcc.dg-struct-layout-1/t010 c_compat_x_tst.o-c_compat_y_tst.o 
execute 
FAIL: tmpdir-gcc.dg-struct-layout-1/t011 c_compat_x_tst.o-c_compat_y_tst.o 
execute 
FAIL: tmpdir-gcc.dg-struct-layout-1/t012 c_compat_x_tst.o-c_compat_y_tst.o 
execute 
FAIL: tmpdir-gcc.dg-struct-layout-1/t013 c_compat_x_tst.o-c_compat_y_tst.o 
execute 
FAIL: tmpdir-gcc.dg-struct-layout-1/t015 c_compat_x_tst.o-c_compat_y_tst.o 
execute 
FAIL: tmpdir-gcc.dg-struct-layout-1/t017 c_compat_x_tst.o-c_compat_y_tst.o 
execute 
FAIL: tmpdir-gcc.dg-struct-layout-1/t026 c_compat_x_tst.o-c_compat_y_tst.o 
execute 

on mainline.  The bug is also present on the 3.4 branch and is a regression 
from 3.3.x, so I've commited the fix and the testcase on both branches.


2004-11-10? Eric Botcazou ?<ebotcazou@libertysurf.fr>

	* config/sparc/sparc.c (function_arg_union_value): New 'slotno'
	argument.  When the union is passed in the 6th slot, build a
	PARALLEL with only one element.
	(function_arg): Adjust call to function_arg_union_value.
	(function_value): Likewise.


2004-11-10? Eric Botcazou ?<ebotcazou@libertysurf.fr>

	* gcc.dg/union-2.c: New test.


-- 
Eric Botcazou
Index: config/sparc/sparc.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/sparc/sparc.c,v
retrieving revision 1.342
diff -u -p -r1.342 sparc.c
--- config/sparc/sparc.c	9 Nov 2004 17:06:02 -0000	1.342
+++ config/sparc/sparc.c	10 Nov 2004 11:56:02 -0000
@@ -5241,7 +5241,7 @@ static void function_arg_record_value_2
 static void function_arg_record_value_1
  (tree, HOST_WIDE_INT, struct function_arg_record_value_parms *, bool);
 static rtx function_arg_record_value (tree, enum machine_mode, int, int, int);
-static rtx function_arg_union_value (int, enum machine_mode, int);
+static rtx function_arg_union_value (int, enum machine_mode, int, int);
 
 /* A subroutine of function_arg_record_value.  Traverse the structure
    recursively and determine how many registers will be required.  */
@@ -5608,7 +5608,8 @@ function_arg_record_value (tree type, en
    REGNO is the hard register the union will be passed in.  */
 
 static rtx
-function_arg_union_value (int size, enum machine_mode mode, int regno)
+function_arg_union_value (int size, enum machine_mode mode, int slotno,
+			  int regno)
 {
   int nwords = ROUND_ADVANCE (size), i;
   rtx regs;
@@ -5617,6 +5618,9 @@ function_arg_union_value (int size, enum
   if (nwords == 0)
     return gen_rtx_REG (mode, regno);
 
+  if (slotno == SPARC_INT_ARG_MAX - 1)
+    nwords = 1;
+
   regs = gen_rtx_PARALLEL (mode, rtvec_alloc (nwords));
 
   for (i = 0; i < nwords; i++)
@@ -5717,7 +5721,7 @@ function_arg (const struct sparc_args *c
       if (size > 16)
 	abort (); /* shouldn't get here */
 
-      return function_arg_union_value (size, mode, regno);
+      return function_arg_union_value (size, mode, slotno, regno);
     }
   else if (type && TREE_CODE (type) == VECTOR_TYPE)
     {
@@ -6107,7 +6111,7 @@ function_value (tree type, enum machine_
 	  if (size > 32)
 	    abort (); /* shouldn't get here */
 
-	  return function_arg_union_value (size, mode, regbase);
+	  return function_arg_union_value (size, mode, 0, regbase);
 	}
       else if (AGGREGATE_TYPE_P (type))
 	{
@@ -6130,7 +6134,7 @@ function_value (tree type, enum machine_
 	     try to be unduly clever, and simply follow the ABI
 	     for unions in that case.  */
 	  if (mode == BLKmode)
-	    return function_arg_union_value (bytes, mode, regbase);
+	    return function_arg_union_value (bytes, mode, 0, regbase);
 	  else
 	    mclass = MODE_INT;
 	}
/* This used to segfault on SPARC 64-bit at runtime because
   the stack pointer was clobbered by the function call.   */

/* { dg-do run } */

#include <stdarg.h>

union U
{
  long l1[2];
};

union U u;

void foo (int z, ...)
{
  int i;
  va_list ap;
  va_start(ap,z);
  i = va_arg(ap, int);
  va_end(ap);
}

int main(void)
{
  foo (1, 1, 1, 1, 1, u);
  return 0;
}

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