From patchwork Sun Jul 18 12:12:53 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [committed] Fix SCmode return values for hard-float MIPS16 Date: Sun, 18 Jul 2010 02:12:53 -0000 From: Richard Sandiford X-Patchwork-Id: 59164 Message-Id: <87bpa5rnsq.fsf@firetop.home> To: gcc-patches@gcc.gnu.org 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; +}