summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorsayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4>2004-06-19 00:17:33 +0000
committersayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4>2004-06-19 00:17:33 +0000
commit2f64c4305f43bd0d2970af561b59bd3915c1f121 (patch)
tree9819bd8cdb1d4003c3909100c418617db3fb2944 /gcc
parent7b43578784f746ad1f5a7755e51e0ef7b65c9910 (diff)
downloadgcc-2f64c4305f43bd0d2970af561b59bd3915c1f121.tar.gz
* fold-const.c (fold) <UNORDERED_EXPR, ORDERED_EXPR, UNLT_EXPR,
UNLE_EXPR, UNGT_EXPR, UNGE_EXPR, UNEQ_EXPR, LTGT_EXPR>: Add constant folding for unordered comparison tree nodes. If both operands are real constants, call fold_relational_const. If either operand is a NaN, evaluate the other for side-effects and return a constant. Optimize (double)float1 CMP (double)float2 into the equivalent float1 CMP float2. (nondestructive_fold_binary_to_constant) <UNORDERED_EXPR, ORDERED_EXPR, UNLT_EXPR, UNLE_EXPR, UNGT_EXPR, UNGE_EXPR, UNEQ_EXPR, LTGT_EXPR>: Call fold_relational_const for constant operands. (fold_relational_const): Add support for unordered comparison tree nodes. Don't constant fold "ordered" floating point comparisons against NaN if when flag_trapping_math is set. * gcc.dg/unordered-2.c: New test case. * gcc.dg/unordered-3.c: New test case. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@83379 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog16
-rw-r--r--gcc/fold-const.c155
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/unordered-2.c51
-rw-r--r--gcc/testsuite/gcc.dg/unordered-3.c79
5 files changed, 292 insertions, 14 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 069c48e0f9b..7694596d8b5 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,19 @@
+2004-06-18 Roger Sayle <roger@eyesopen.com>
+
+ * fold-const.c (fold) <UNORDERED_EXPR, ORDERED_EXPR, UNLT_EXPR,
+ UNLE_EXPR, UNGT_EXPR, UNGE_EXPR, UNEQ_EXPR, LTGT_EXPR>: Add
+ constant folding for unordered comparison tree nodes. If both
+ operands are real constants, call fold_relational_const. If either
+ operand is a NaN, evaluate the other for side-effects and return a
+ constant. Optimize (double)float1 CMP (double)float2 into the
+ equivalent float1 CMP float2.
+ (nondestructive_fold_binary_to_constant) <UNORDERED_EXPR,
+ ORDERED_EXPR, UNLT_EXPR, UNLE_EXPR, UNGT_EXPR, UNGE_EXPR, UNEQ_EXPR,
+ LTGT_EXPR>: Call fold_relational_const for constant operands.
+ (fold_relational_const): Add support for unordered comparison tree
+ nodes. Don't constant fold "ordered" floating point comparisons
+ against NaN if when flag_trapping_math is set.
+
2004-06-19 Jakub Jelinek <jakub@redhat.com>
* fold-const.c (build_range_check): If !in_p and recursive call
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 00fd1346e2c..5266b000bee 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -8252,6 +8252,59 @@ fold (tree expr)
t1 = fold_relational_const (code, type, arg0, arg1);
return (t1 == NULL_TREE ? t : t1);
+ case UNORDERED_EXPR:
+ case ORDERED_EXPR:
+ case UNLT_EXPR:
+ case UNLE_EXPR:
+ case UNGT_EXPR:
+ case UNGE_EXPR:
+ case UNEQ_EXPR:
+ case LTGT_EXPR:
+ if (TREE_CODE (arg0) == REAL_CST && TREE_CODE (arg1) == REAL_CST)
+ {
+ t1 = fold_relational_const (code, type, arg0, arg1);
+ if (t1 != NULL_TREE)
+ return t1;
+ }
+
+ /* If the first operand is NaN, the result is constant. */
+ if (TREE_CODE (arg0) == REAL_CST
+ && REAL_VALUE_ISNAN (TREE_REAL_CST (arg0))
+ && (code != LTGT_EXPR || ! flag_trapping_math))
+ {
+ t1 = (code == ORDERED_EXPR || code == LTGT_EXPR)
+ ? integer_zero_node
+ : integer_one_node;
+ return omit_one_operand (type, t1, arg1);
+ }
+
+ /* If the second operand is NaN, the result is constant. */
+ if (TREE_CODE (arg1) == REAL_CST
+ && REAL_VALUE_ISNAN (TREE_REAL_CST (arg1))
+ && (code != LTGT_EXPR || ! flag_trapping_math))
+ {
+ t1 = (code == ORDERED_EXPR || code == LTGT_EXPR)
+ ? integer_zero_node
+ : integer_one_node;
+ return omit_one_operand (type, t1, arg0);
+ }
+
+ /* Fold (double)float1 CMP (double)float2 into float1 CMP float2. */
+ {
+ tree targ0 = strip_float_extensions (arg0);
+ tree targ1 = strip_float_extensions (arg1);
+ tree newtype = TREE_TYPE (targ0);
+
+ if (TYPE_PRECISION (TREE_TYPE (targ1)) > TYPE_PRECISION (newtype))
+ newtype = TREE_TYPE (targ1);
+
+ if (TYPE_PRECISION (newtype) < TYPE_PRECISION (TREE_TYPE (arg0)))
+ return fold (build2 (code, type, fold_convert (newtype, targ0),
+ fold_convert (newtype, targ1)));
+ }
+
+ return t;
+
case COND_EXPR:
/* Pedantic ANSI C says that a conditional expression is never an lvalue,
so all simple results must be passed through pedantic_non_lvalue. */
@@ -9770,6 +9823,16 @@ nondestructive_fold_binary_to_constant (enum tree_code code, tree type,
if (tem)
return tem;
+ /* Fall through. */
+
+ case ORDERED_EXPR:
+ case UNORDERED_EXPR:
+ case UNLT_EXPR:
+ case UNLE_EXPR:
+ case UNGT_EXPR:
+ case UNGE_EXPR:
+ case UNEQ_EXPR:
+ case LTGT_EXPR:
if (!wins)
return NULL_TREE;
@@ -10075,7 +10138,82 @@ fold_relational_const (enum tree_code code, tree type, tree op0, tree op1)
int result, invert;
/* From here on, the only cases we handle are when the result is
- known to be a constant.
+ known to be a constant. */
+
+ if (TREE_CODE (op0) == REAL_CST && TREE_CODE (op1) == REAL_CST)
+ {
+ /* Handle the cases where either operand is a NaN. */
+ if (REAL_VALUE_ISNAN (TREE_REAL_CST (op0))
+ || REAL_VALUE_ISNAN (TREE_REAL_CST (op1)))
+ {
+ switch (code)
+ {
+ case EQ_EXPR:
+ case ORDERED_EXPR:
+ result = 0;
+ break;
+
+ case NE_EXPR:
+ case UNORDERED_EXPR:
+ case UNLT_EXPR:
+ case UNLE_EXPR:
+ case UNGT_EXPR:
+ case UNGE_EXPR:
+ case UNEQ_EXPR:
+ result = 1;
+ break;
+
+ case LT_EXPR:
+ case LE_EXPR:
+ case GT_EXPR:
+ case GE_EXPR:
+ case LTGT_EXPR:
+ if (flag_trapping_math)
+ return NULL_TREE;
+ result = 0;
+ break;
+
+ default:
+ abort ();
+ }
+
+ return constant_boolean_node (result, type);
+ }
+
+ /* From here on we're sure there are no NaNs. */
+ switch (code)
+ {
+ case ORDERED_EXPR:
+ return constant_boolean_node (true, type);
+
+ case UNORDERED_EXPR:
+ return constant_boolean_node (false, type);
+
+ case UNLT_EXPR:
+ code = LT_EXPR;
+ break;
+ case UNLE_EXPR:
+ code = LE_EXPR;
+ break;
+ case UNGT_EXPR:
+ code = GT_EXPR;
+ break;
+ case UNGE_EXPR:
+ code = GE_EXPR;
+ break;
+ case UNEQ_EXPR:
+ code = EQ_EXPR;
+ break;
+ case LTGT_EXPR:
+ code = NE_EXPR;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /* From here on we only handle LT, LE, GT, GE, EQ and NE.
To compute GT, swap the arguments and do LT.
To compute GE, do LT and invert the result.
@@ -10093,7 +10231,7 @@ fold_relational_const (enum tree_code code, tree type, tree op0, tree op1)
}
/* Note that it is safe to invert for real values here because we
- will check below in the one case that it matters. */
+ have already handled the one case that it matters. */
invert = 0;
if (code == NE_EXPR || code == GE_EXPR)
@@ -10121,18 +10259,7 @@ fold_relational_const (enum tree_code code, tree type, tree op0, tree op1)
/* Two real constants can be compared explicitly. */
else if (TREE_CODE (op0) == REAL_CST && TREE_CODE (op1) == REAL_CST)
{
- /* If either operand is a NaN, the result is false with two
- exceptions: First, an NE_EXPR is true on NaNs, but that case
- is already handled correctly since we will be inverting the
- result for NE_EXPR. Second, if we had inverted a LE_EXPR
- or a GE_EXPR into a LT_EXPR, we must return true so that it
- will be inverted into false. */
-
- if (REAL_VALUE_ISNAN (TREE_REAL_CST (op0))
- || REAL_VALUE_ISNAN (TREE_REAL_CST (op1)))
- result = invert && code == LT_EXPR;
-
- else if (code == EQ_EXPR)
+ if (code == EQ_EXPR)
result = REAL_VALUES_EQUAL (TREE_REAL_CST (op0),
TREE_REAL_CST (op1));
else
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 856b789fe6c..362d4f92e14 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2004-06-18 Roger Sayle <roger@eyesopen.com>
+
+ * gcc.dg/unordered-2.c: New test case.
+ * gcc.dg/unordered-3.c: New test case.
+
2004-06-19 David Billinghurst (David.Billinghurst@riotinto.com)
PR other/16043
diff --git a/gcc/testsuite/gcc.dg/unordered-2.c b/gcc/testsuite/gcc.dg/unordered-2.c
new file mode 100644
index 00000000000..0696d37cfb4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/unordered-2.c
@@ -0,0 +1,51 @@
+/* { dg-do link } */
+
+void link_error ();
+
+int main()
+{
+ if (__builtin_isgreater(1.0,2.0) != 0)
+ link_error ();
+ if (__builtin_isgreater(3.0,3.0) != 0)
+ link_error ();
+ if (__builtin_isgreater(5.0,4.0) == 0)
+ link_error ();
+
+ if (__builtin_isgreaterequal(1.0,2.0) != 0)
+ link_error ();
+ if (__builtin_isgreaterequal(3.0,3.0) == 0)
+ link_error ();
+ if (__builtin_isgreaterequal(5.0,4.0) == 0)
+ link_error ();
+
+ if (__builtin_isless(1.0,2.0) == 0)
+ link_error ();
+ if (__builtin_isless(3.0,3.0) != 0)
+ link_error ();
+ if (__builtin_isless(5.0,4.0) != 0)
+ link_error ();
+
+ if (__builtin_islessequal(1.0,2.0) == 0)
+ link_error ();
+ if (__builtin_islessequal(3.0,3.0) == 0)
+ link_error ();
+ if (__builtin_islessequal(5.0,4.0) != 0)
+ link_error ();
+
+ if (__builtin_islessgreater(1.0,2.0) == 0)
+ link_error ();
+ if (__builtin_islessgreater(3.0,3.0) != 0)
+ link_error ();
+ if (__builtin_islessgreater(5.0,4.0) == 0)
+ link_error ();
+
+ if (__builtin_isunordered(1.0,2.0) != 0)
+ link_error ();
+ if (__builtin_isunordered(3.0,3.0) != 0)
+ link_error ();
+ if (__builtin_isunordered(5.0,4.0) != 0)
+ link_error ();
+
+ return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/unordered-3.c b/gcc/testsuite/gcc.dg/unordered-3.c
new file mode 100644
index 00000000000..4a11a6d48d8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/unordered-3.c
@@ -0,0 +1,79 @@
+/* { dg-do link } */
+
+void link_error ();
+
+void test1()
+{
+ if (__builtin_isgreater(1.0,__builtin_nan("")) != 0)
+ link_error ();
+ if (__builtin_isgreater(__builtin_nan(""),1.0) != 0)
+ link_error ();
+
+ if (__builtin_isgreaterequal(1.0,__builtin_nan("")) != 0)
+ link_error ();
+ if (__builtin_isgreaterequal(__builtin_nan(""),1.0) != 0)
+ link_error ();
+
+ if (__builtin_isless(1.0,__builtin_nan("")) != 0)
+ link_error ();
+ if (__builtin_isless(__builtin_nan(""),1.0) != 0)
+ link_error ();
+
+ if (__builtin_islessequal(1.0,__builtin_nan("")) != 0)
+ link_error ();
+ if (__builtin_islessequal(__builtin_nan(""),1.0) != 0)
+ link_error ();
+
+ if (__builtin_islessgreater(1.0,__builtin_nan("")) != 0)
+ link_error ();
+ if (__builtin_islessgreater(__builtin_nan(""),1.0) != 0)
+ link_error ();
+
+ if (__builtin_isunordered(1.0,__builtin_nan("")) == 0)
+ link_error ();
+ if (__builtin_isunordered(__builtin_nan(""),1.0) == 0)
+ link_error ();
+}
+
+
+void test2(double x)
+{
+ if (__builtin_isgreater(x,__builtin_nan("")) != 0)
+ link_error ();
+ if (__builtin_isgreater(__builtin_nan(""),x) != 0)
+ link_error ();
+
+ if (__builtin_isgreaterequal(x,__builtin_nan("")) != 0)
+ link_error ();
+ if (__builtin_isgreaterequal(__builtin_nan(""),x) != 0)
+ link_error ();
+
+ if (__builtin_isless(x,__builtin_nan("")) != 0)
+ link_error ();
+ if (__builtin_isless(__builtin_nan(""),x) != 0)
+ link_error ();
+
+ if (__builtin_islessequal(x,__builtin_nan("")) != 0)
+ link_error ();
+ if (__builtin_islessequal(__builtin_nan(""),x) != 0)
+ link_error ();
+
+ if (__builtin_islessgreater(x,__builtin_nan("")) != 0)
+ link_error ();
+ if (__builtin_islessgreater(__builtin_nan(""),x) != 0)
+ link_error ();
+
+ if (__builtin_isunordered(x,__builtin_nan("")) == 0)
+ link_error ();
+ if (__builtin_isunordered(__builtin_nan(""),x) == 0)
+ link_error ();
+}
+
+
+int main()
+{
+ test1 ();
+ test2 (1.0);
+ return 0;
+}
+