https://gcc.gnu.org/g:b9c9f9350ca8cb8d0a59cb99b5e48f6f7328adc6

commit r17-3038-gb9c9f9350ca8cb8d0a59cb99b5e48f6f7328adc6
Author: Aldy Hernandez <[email protected]>
Date:   Thu Aug 6 07:01:38 2026 +0000

    Handle sub-ranges in frange == and != operators [PR126637]
    
    When the operands do not intersect, == and != still allow equality if
    each range holds a zero of opposite sign, hence -0.0 == 0.0.  The
    check for this looked at the hull endpoints, ignoring the inner
    sub-range boundaries.  With sub-ranges the zero can be inner,
    e.g. [-1.0, -0.0][1.0, 1.0] with hull [-1.0, 1.0], so it was missed
    and e.g. "e != 0.0" folded to true.
    
    Tested on ppc64le Linux: regstrap and LAPACK.
    
            PR tree-optimization/126637
    
    gcc/ChangeLog:
    
            * range-op-float.cc (operator_equal::fold_range): Use the
            contains_zero_p method to detect a contained zero instead of
            inspecting the hull endpoints.
            (operator_not_equal::fold_range): Likewise.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.dg/tree-ssa/pr126637.c: New test.

Diff:
---
 gcc/range-op-float.cc                    | 20 ++++++--------------
 gcc/testsuite/gcc.dg/tree-ssa/pr126637.c | 29 +++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+), 14 deletions(-)

diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc
index 628c1d365b19..ba6af5851c26 100644
--- a/gcc/range-op-float.cc
+++ b/gcc/range-op-float.cc
@@ -656,13 +656,9 @@ operator_equal::fold_range (irange &r, tree type,
       tmp.intersect (op2);
       if (tmp.undefined_p ())
        {
-         // 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 ())))
+         // If one range contains -0.0 and another +0.0, we don't know
+         // anything either, because -0.0 == 0.0.
+         if (op1.contains_zero_p () && op2.contains_zero_p ())
            r = range_true_and_false (type);
          else
            r = range_false (type);
@@ -797,13 +793,9 @@ operator_not_equal::fold_range (irange &r, tree type,
       tmp.intersect (op2);
       if (tmp.undefined_p ())
        {
-         // 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 ())))
+         // If one range contains -0.0 and another +0.0, we don't know
+         // anything either, because -0.0 == 0.0.
+         if (op1.contains_zero_p () && op2.contains_zero_p ())
            r = range_true_and_false (type);
          else
            r = range_true (type);
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr126637.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr126637.c
new file mode 100644
index 000000000000..68b4f4c0c395
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr126637.c
@@ -0,0 +1,29 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+/* e's range is [-1.0, -0.0][1.0, 1.0], which contains -0.0, so e != 0.0
+   must not fold to true since -0.0 == 0.0.  */
+
+static double *a;
+static void
+b (int c)
+{
+  int d = 1;
+  double e = 1.0;
+  a = &e;
+  while (1)
+    {
+      if (!(e ? e : 4.0 < -c))
+       break;
+      e = d - 1;
+      *a = -e;
+      d = 2;
+    }
+}
+
+int
+main ()
+{
+  b (0);
+  return 0;
+}

Reply via email to