[gcc r17-3038] Handle sub-ranges in frange == and != operators [PR126637]

Aldy Hernandez via Gcc-cvs <[email protected]> Thu, 6 Aug 2026 14:23:14 +0000 (GMT)
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
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;
+}