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
This commit is contained in:
Ben Elliston 2007-09-12 10:48:49 +10:00
parent c592621442
commit 9943eb0be3
4 changed files with 86 additions and 10 deletions

View file

@ -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,

View file

@ -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)

View file

@ -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.

View file

@ -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);
}