This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[committed] Fix SCmode return values for hard-float MIPS16
- From: Richard Sandiford <rdsandiford at googlemail dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sun, 18 Jul 2010 13:12:53 +0100
- Subject: [committed] Fix SCmode return values for hard-float MIPS16
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.
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;
+}