Patchwork [committed] Fix SCmode return values for hard-float MIPS16

login
register
mail settings
Submitter Richard Sandiford
Date July 18, 2010, 12:12 p.m.
Message ID <87bpa5rnsq.fsf@firetop.home>
Download mbox | patch
Permalink /patch/59164/
State New
Headers show

Comments

Richard Sandiford - July 18, 2010, 12:12 p.m.
On o64, an SCmode value is returned in either ($f0, $f2) (for hard float)
or as a 64-bit value packed into $2 (for soft-float).  MIPS16 code needs
stubs for converting the former to the latter, but they were missing a
zero-extension of the low-half of $2.  This meant that a negative
component in the low half would fill out the high half, turning it
into a negative NaN.

The bug occured in both mips.c and mips16.S.  The mips.c one caused
a failure in gcc.c-torture/execute with -mflip-mips16.  I then wrote
the attached test to confirm that the same failure occured with
mips16.S stubs.

Tested on mipsisa64-elfoabi and applied.

Richard


gcc/
	* config/mips/mips.c (mips16_build_call_stub): Zero-extend the
	low half of a single-register SCmode return value before ORing
	it with the high half.
	* config/mips/mips16.S (MERGE_GPRf): Likewise.

gcc/testsuite/
	* gcc.target/mips/mips16-attributes-4.c: New test.

Patch

Index: gcc/config/mips/mips.c
===================================================================
--- gcc/config/mips/mips.c	2010-07-18 13:03:50.000000000 +0100
+++ gcc/config/mips/mips.c	2010-07-18 13:03:52.000000000 +0100
@@ -6318,19 +6318,28 @@  mips16_build_call_stub (rtx retval, rtx
 	  switch (GET_MODE (retval))
 	    {
 	    case SCmode:
-	      mips_output_32bit_xfer ('f', GP_RETURN + 1,
-				      FP_REG_FIRST + MAX_FPRS_PER_FMT);
-	      /* Fall though.  */
-	    case SFmode:
-	      mips_output_32bit_xfer ('f', GP_RETURN, FP_REG_FIRST);
+	      mips_output_32bit_xfer ('f', GP_RETURN + TARGET_BIG_ENDIAN,
+				      TARGET_BIG_ENDIAN
+				      ? FP_REG_FIRST + MAX_FPRS_PER_FMT
+				      : FP_REG_FIRST);
+	      mips_output_32bit_xfer ('f', GP_RETURN + TARGET_LITTLE_ENDIAN,
+				      TARGET_LITTLE_ENDIAN
+				      ? FP_REG_FIRST + MAX_FPRS_PER_FMT
+				      : FP_REG_FIRST);
 	      if (GET_MODE (retval) == SCmode && TARGET_64BIT)
 		{
 		  /* On 64-bit targets, complex floats are returned in
 		     a single GPR, such that "sd" on a suitably-aligned
 		     target would store the value correctly.  */
 		  fprintf (asm_out_file, "\tdsll\t%s,%s,32\n",
+			   reg_names[GP_RETURN + TARGET_BIG_ENDIAN],
+			   reg_names[GP_RETURN + TARGET_BIG_ENDIAN]);
+		  fprintf (asm_out_file, "\tdsll\t%s,%s,32\n",
 			   reg_names[GP_RETURN + TARGET_LITTLE_ENDIAN],
 			   reg_names[GP_RETURN + TARGET_LITTLE_ENDIAN]);
+		  fprintf (asm_out_file, "\tdsrl\t%s,%s,32\n",
+			   reg_names[GP_RETURN + TARGET_BIG_ENDIAN],
+			   reg_names[GP_RETURN + TARGET_BIG_ENDIAN]);
 		  fprintf (asm_out_file, "\tor\t%s,%s,%s\n",
 			   reg_names[GP_RETURN],
 			   reg_names[GP_RETURN],
@@ -6338,6 +6347,10 @@  mips16_build_call_stub (rtx retval, rtx
 		}
 	      break;
 
+	    case SFmode:
+	      mips_output_32bit_xfer ('f', GP_RETURN, FP_REG_FIRST);
+	      break;
+
 	    case DCmode:
 	      mips_output_64bit_xfer ('f', GP_RETURN + (8 / UNITS_PER_WORD),
 				      FP_REG_FIRST + MAX_FPRS_PER_FMT);
Index: gcc/config/mips/mips16.S
===================================================================
--- gcc/config/mips/mips16.S	2010-07-18 13:03:50.000000000 +0100
+++ gcc/config/mips/mips16.S	2010-07-18 13:03:52.000000000 +0100
@@ -61,9 +61,11 @@  see the files COPYING3 and COPYING.RUNTI
    and so that its low 32 bits contain LOW_FPR.  */
 #define MERGE_GPRf(GPR, HIGH_FPR, LOW_FPR)	\
 	.set	noat;				\
-	mfc1	GPR, HIGH_FPR;			\
 	mfc1	$1, LOW_FPR;			\
+	mfc1	GPR, HIGH_FPR;			\
+	dsll	$1, $1, 32;			\
 	dsll	GPR, GPR, 32;			\
+	dsrl	$1, $1, 32;			\
 	or	GPR, GPR, $1;			\
 	.set	at
 
Index: gcc/testsuite/gcc.target/mips/mips16-attributes-4.c
===================================================================
--- /dev/null	2010-07-18 09:23:39.222094797 +0100
+++ gcc/testsuite/gcc.target/mips/mips16-attributes-4.c	2010-07-18 13:03:52.000000000 +0100
@@ -0,0 +1,17 @@ 
+/* { dg-do run } */
+/* { dg-options "(-mips16)" } */
+
+extern void abort (void);
+
+__complex float f = { -1.0 + -1.0i };
+__complex float __attribute__((nomips16)) foo (void) { return f; }
+__complex float (*volatile foop) (void) = foo;
+__complex float __attribute__((mips16, noinline)) bar (void) { return foop (); }
+
+int
+main (void)
+{
+  if (bar () != f)
+    abort ();
+  return 0;
+}