aboutsummaryrefslogtreecommitdiff
path: root/gcc/range-op-float.cc
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2023-01-26 17:21:22 +0100
committerJakub Jelinek <jakub@redhat.com>2023-01-26 17:28:17 +0100
commit09176201ec6a21c25b1edb07f19f83be22a123f9 (patch)
tree5095ca59b6ff2a1cf939627442f91a3bdd0cee36 /gcc/range-op-float.cc
parent0cdb609f43eb6131053fb88e32fdc5490f4ef293 (diff)
downloadgcc-09176201ec6a21c25b1edb07f19f83be22a123f9.zip
gcc-09176201ec6a21c25b1edb07f19f83be22a123f9.tar.gz
gcc-09176201ec6a21c25b1edb07f19f83be22a123f9.tar.bz2
frange: Fix up foperator_{,not_}equal::fold_range for signed zeros [PR108540]
The following testcases are miscompiled, because threader sees some SSA_NAME would have -0.0 value and when computing range of SSA_NAME == 0.0 foperator_equal::fold_range sees one operand has [-0.0, -0.0] singleton range, the other [0.0, 0.0], they aren't equal (frange operator== uses real_identical etc. rather than real comparisons) and so it thinks they compare unequal. With signed zeros -0.0 == 0.0 is true though, so we need to special case the both ranges singleton code. Similarly, if we see op1 range being say [-42.0, -0.0] and op2 range [0.0, 42.0], we'd check that the intersection of the two ranges is empty (that is correct) and fold the result of == between such operands to [0, 0] which is wrong, because -0.0 == 0.0, it needs to be [0, 1]. Similarly for foperator_not_equal::fold_range. 2023-01-26 Jakub Jelinek <jakub@redhat.com> PR tree-optimization/108540 * range-op-float.cc (foperator_equal::fold_range): If both op1 and op2 are singletons, use range_true even if op1 != op2 when one range is [-0.0, -0.0] and another [0.0, 0.0]. Similarly, even if intersection of the ranges is empty and one has zero low bound and another zero high bound, use range_true_and_false rather than range_false. (foperator_not_equal::fold_range): If both op1 and op2 are singletons, use range_false even if op1 != op2 when one range is [-0.0, -0.0] and another [0.0, 0.0]. Similarly, even if intersection of the ranges is empty and one has zero low bound and another zero high bound, use range_true_and_false rather than range_true. * gcc.c-torture/execute/ieee/pr108540-1.c: New test. * gcc.c-torture/execute/ieee/pr108540-2.c: New test.
Diffstat (limited to 'gcc/range-op-float.cc')
-rw-r--r--gcc/range-op-float.cc40
1 files changed, 35 insertions, 5 deletions
diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc
index 74ac465..2db83ae 100644
--- a/gcc/range-op-float.cc
+++ b/gcc/range-op-float.cc
@@ -607,6 +607,10 @@ foperator_equal::fold_range (irange &r, tree type,
{
if (op1 == op2)
r = range_true (type);
+ // If one operand is -0.0 and other 0.0, they are still equal.
+ else if (real_iszero (&op1.lower_bound ())
+ && real_iszero (&op2.lower_bound ()))
+ r = range_true (type);
else
r = range_false (type);
}
@@ -617,7 +621,18 @@ foperator_equal::fold_range (irange &r, tree type,
frange tmp = op1;
tmp.intersect (op2);
if (tmp.undefined_p ())
- r = range_false (type);
+ {
+ // If one range is [whatever, -0.0] and another
+ // [0.0, whatever2], we don't know anything either,
+ // because -0.0 == 0.0.
+ if ((real_iszero (&op1.upper_bound ())
+ && real_iszero (&op2.lower_bound ()))
+ || (real_iszero (&op1.lower_bound ())
+ && real_iszero (&op2.upper_bound ())))
+ r = range_true_and_false (type);
+ else
+ r = range_false (type);
+ }
else
r = range_true_and_false (type);
}
@@ -708,10 +723,14 @@ foperator_not_equal::fold_range (irange &r, tree type,
// consist of a single value, and then compare them.
else if (op1.singleton_p () && op2.singleton_p ())
{
- if (op1 != op2)
- r = range_true (type);
- else
+ if (op1 == op2)
r = range_false (type);
+ // If one operand is -0.0 and other 0.0, they are still equal.
+ else if (real_iszero (&op1.lower_bound ())
+ && real_iszero (&op2.lower_bound ()))
+ r = range_false (type);
+ else
+ r = range_true (type);
}
else if (!maybe_isnan (op1, op2))
{
@@ -720,7 +739,18 @@ foperator_not_equal::fold_range (irange &r, tree type,
frange tmp = op1;
tmp.intersect (op2);
if (tmp.undefined_p ())
- r = range_true (type);
+ {
+ // If one range is [whatever, -0.0] and another
+ // [0.0, whatever2], we don't know anything either,
+ // because -0.0 == 0.0.
+ if ((real_iszero (&op1.upper_bound ())
+ && real_iszero (&op2.lower_bound ()))
+ || (real_iszero (&op1.lower_bound ())
+ && real_iszero (&op2.upper_bound ())))
+ r = range_true_and_false (type);
+ else
+ r = range_true (type);
+ }
else
r = range_true_and_false (type);
}