[PATCH] Handle sub-ranges in frange == and != operators [PR126637]

Aldy Hernandez <[email protected]> Thu, 6 Aug 2026 16:20:34 +0200
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
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.

Pushed.

	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.
---
 gcc/range-op-float.cc                    | 20 +++++-----------
 gcc/testsuite/gcc.dg/tree-ssa/pr126637.c | 29 ++++++++++++++++++++++++
 2 files changed, 35 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr126637.c

diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc
index 628c1d365b1..ba6af5851c2 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 00000000000..68b4f4c0c39
--- /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;
+}
-- 
2.47.3