Fix Sparc64 float libcalls

David S. Miller davem@redhat.com
Mon May 6 01:11:00 GMT 2002


For long double library calls on sparc64 it is done like
so:

	_Qp_${OPERATION}(long double *ret,
			 long double *arg1,
			 long double *arg2 ...);

Unfortunately, as we currently implement these libcalls
it is possible to use the same memory location for the return
value as we do for the one of the arguments.

Linux's library implementation never would clobber the output value
before the inputs were consumed, Solaris's implementation
unfortunately does :(

The simplest testcase (as discovered by Kaveh, thanks bunches):

int main()
{
  long double x = 88;
  x -= 6;
  if (x != 82)
    abort();
  exit(0);
}

Compile this with -m64 -O0 and you'll hit the problem.
The libcall for subtraction is output as:

	_Qp_sub(& x, & x, & 88);

This is actually just a simplified form of bits inside of
gcc.c-torture/execute/regstack-1.c

The fix is pretty simple, if the return value is already a
MEM, check if it matches of the arguments.  If it does, pop
the return value onto the stack.

Applied on the mainline.

Mark, not a regression, but a really stupid bug... and I don't have a
note from my mother either.  So I guess this is 3.1.1

Note that putting this in 3.1 would allow us to close Kaveh's PR
target/6103 finally, we've been beating on the failures contained in
that PR one by one for the past month and a half.

2002-05-06  David S. Miller  <davem@redhat.com>

	* config/sparc/sparc.c (emit_soft_tfmode_libcall): Do not
	allow result to overlap input operands in memory.

--- config/sparc/sparc.c.~1~	Tue Apr 30 19:17:33 2002
+++ config/sparc/sparc.c	Mon May  6 00:08:04 2002
@@ -2475,7 +2475,7 @@ emit_soft_tfmode_libcall (func_name, nar
      rtx *operands;
 {
   rtx ret_slot = NULL, arg[3], func_sym;
-  int i;
+  int i, j;
 
   /* We only expect to be called for conversions, unary, and binary ops.  */
   if (nargs < 2 || nargs > 3)
@@ -2490,7 +2490,25 @@ emit_soft_tfmode_libcall (func_name, nar
       if (GET_MODE (this_arg) == TFmode)
 	{
 	  if (GET_CODE (this_arg) == MEM)
-	    this_arg = XEXP (this_arg, 0);
+	    {
+	      this_arg = XEXP (this_arg, 0);
+
+	      /* Make sure the output is not in the same place
+		 as one of our inputs.  */
+	      if (i == 0)
+		{
+		  for (j = 1; j < nargs; j++)
+		    if (rtx_equal_p (operands[0], operands[j]))
+		      break;
+
+		  if (j != nargs)
+		    {
+		      ret_slot = assign_stack_temp (TFmode,
+						    GET_MODE_SIZE (TFmode), 0);
+		      this_arg = XEXP (ret_slot, 0);
+		    }
+		}
+	    }
 	  else if (CONSTANT_P (this_arg))
 	    {
 	      this_slot = force_const_mem (TFmode, this_arg);



More information about the Gcc-patches mailing list