diff options
author | Ben Elliston <bje@gcc.gnu.org> | 2007-09-12 10:48:49 +1000 |
---|---|---|
committer | Ben Elliston <bje@gcc.gnu.org> | 2007-09-12 10:48:49 +1000 |
commit | 9943eb0be30702b303d91c36718c3a2c8dfced8b (patch) | |
tree | e79af483bb97019f406ce527c11a2427923e9114 /gcc | |
parent | c5926214424159cb5233844bf5c2e72346c4e6c1 (diff) | |
download | gcc-9943eb0be30702b303d91c36718c3a2c8dfced8b.zip gcc-9943eb0be30702b303d91c36718c3a2c8dfced8b.tar.gz gcc-9943eb0be30702b303d91c36718c3a2c8dfced8b.tar.bz2 |
spu.c (spu_emit_branch_or_set): Handle NaN values as operands to DFmode GE or LE compares.
* config/spu/spu.c (spu_emit_branch_or_set): Handle NaN values as
operands to DFmode GE or LE compares.
testsuite/
* gcc.target/spu/dfcgt-nan.c: New test.
From-SVN: r128404
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/config/spu/spu.c | 55 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/spu/dfcgt-nan.c | 31 |
4 files changed, 86 insertions, 10 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 76e343d..4af559e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2007-09-12 Sa Liu <saliu@de.ibm.com> + + * config/spu/spu.c (spu_emit_branch_or_set): Handle NaN values as + operands to DFmode GE or LE compares. + 2007-09-12 Bernd Schmidt <bernd.schmidt@analog.com> * config/bfin/bfin.h (enum reg_class, REG_CLASS_CONTENTS, diff --git a/gcc/config/spu/spu.c b/gcc/config/spu/spu.c index 3423cef..2dd78a0 100644 --- a/gcc/config/spu/spu.c +++ b/gcc/config/spu/spu.c @@ -720,13 +720,14 @@ spu_emit_branch_or_set (int is_set, enum rtx_code code, rtx operands[]) { int reverse_compare = 0; int reverse_test = 0; - rtx compare_result; - rtx comp_rtx; + rtx compare_result, eq_result; + rtx comp_rtx, eq_rtx; rtx target = operands[0]; enum machine_mode comp_mode; enum machine_mode op_mode; - enum spu_comp_code scode; + enum spu_comp_code scode, eq_code, ior_code; int index; + int eq_test = 0; /* When spu_compare_op1 is a CONST_INT change (X >= C) to (X > C-1), and so on, to keep the constant in operand 1. */ @@ -757,17 +758,40 @@ spu_emit_branch_or_set (int is_set, enum rtx_code code, rtx operands[]) } } + comp_mode = SImode; + op_mode = GET_MODE (spu_compare_op0); + switch (code) { case GE: - reverse_compare = 1; - reverse_test = 1; scode = SPU_GT; + if (HONOR_NANS (op_mode) && spu_arch == PROCESSOR_CELLEDP) + { + reverse_compare = 0; + reverse_test = 0; + eq_test = 1; + eq_code = SPU_EQ; + } + else + { + reverse_compare = 1; + reverse_test = 1; + } break; case LE: - reverse_compare = 0; - reverse_test = 1; scode = SPU_GT; + if (HONOR_NANS (op_mode) && spu_arch == PROCESSOR_CELLEDP) + { + reverse_compare = 1; + reverse_test = 0; + eq_test = 1; + eq_code = SPU_EQ; + } + else + { + reverse_compare = 0; + reverse_test = 1; + } break; case LT: reverse_compare = 1; @@ -809,9 +833,6 @@ spu_emit_branch_or_set (int is_set, enum rtx_code code, rtx operands[]) break; } - comp_mode = SImode; - op_mode = GET_MODE (spu_compare_op0); - switch (op_mode) { case QImode: @@ -916,6 +937,20 @@ spu_emit_branch_or_set (int is_set, enum rtx_code code, rtx operands[]) abort (); emit_insn (comp_rtx); + if (eq_test) + { + eq_result = gen_reg_rtx (comp_mode); + eq_rtx = GEN_FCN (spu_comp_icode[index][eq_code]) (eq_result, + spu_compare_op0, + spu_compare_op1); + if (eq_rtx == 0) + abort (); + emit_insn (eq_rtx); + ior_code = ior_optab->handlers[(int)comp_mode].insn_code; + gcc_assert (ior_code != CODE_FOR_nothing); + emit_insn (GEN_FCN (ior_code) + (compare_result, compare_result, eq_result)); + } } if (is_set == 0) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a6ddaa7..a562e62 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2007-09-12 Ben Elliston <bje@au.ibm.com> + Ulrich Weigand <uweigand@de.ibm.com> + + * gcc.target/spu/dfcgt-nan.c: New test. + 2007-09-11 Hans-Peter Nilsson <hp@axis.com> * gcc.dg/cpp/trad/include.c: Don't run for newlib targets. diff --git a/gcc/testsuite/gcc.target/spu/dfcgt-nan.c b/gcc/testsuite/gcc.target/spu/dfcgt-nan.c new file mode 100644 index 0000000..18ce013 --- /dev/null +++ b/gcc/testsuite/gcc.target/spu/dfcgt-nan.c @@ -0,0 +1,31 @@ +/* { dg-do compile } */ +/* { dg-options "-march=celledp -O1" } */ +/* { dg-final { scan-assembler "dfceq" } } */ + +/* GCC previously transformed an "a <= b" test into "! (a > b)" when + compiling with -march=celledp, so that the dfcgt instruction can be + used to implement the comparison. + + However, this transformation violates the IEEE-754 standard in the + presence of NaN values. If either a or b is a NaN, a <= b should + evaluate to false according to IEEE rules. However, after the + transformation, a > b as implemented by dfcgt itself returns false, + so the transformed test returns true. + + Note that the equivalent transformation is valid for single- + precision floating-point values on the Cell SPU, because the format + does not have NaNs. It is invalid for double-precision, even on + Cell, however. */ + +int test (double a, double b) __attribute__ ((noinline)); +int test (double a, double b) +{ + return a <= b; +} + +int main (void) +{ + double x = 0.0; + double y = 0.0/0.0; + return test (x, y); +} |