aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Elliston <bje@gcc.gnu.org>2007-09-12 10:48:49 +1000
committerBen Elliston <bje@gcc.gnu.org>2007-09-12 10:48:49 +1000
commit9943eb0be30702b303d91c36718c3a2c8dfced8b (patch)
treee79af483bb97019f406ce527c11a2427923e9114
parentc5926214424159cb5233844bf5c2e72346c4e6c1 (diff)
downloadgcc-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
-rw-r--r--gcc/ChangeLog5
-rw-r--r--gcc/config/spu/spu.c55
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.target/spu/dfcgt-nan.c31
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);
+}