When bounds_of_var_in_loop was converted to range _of_var_in_loop, quite a bit of code was refactored.

The final check which is now in range_from_loop_direction, use to return FALSE when the beginning and end bounds were the same... The new code was converted from trees into ranges, and the check was changed to see if the beginning and end bounds were behaving properly, and if not, there was a potential overflow and we abort.

The old code also aborted if the upper and lower bounds were the same, but when refactored, the logic was reversed and the conditions were not changed.  THis allowed bounds that were the same to still generate a range, which would be incorrect.  This testcase demonstrates that where we generate a range of [2,2] for the loop when we should not.

The attached patch fixes this by using wi::ge_p instead of wi::gt_p for the fail condition, and returns us back to the expected behaviour.  As a side bonus, it also now fixes this testcase in the JIT compiler:

> FAIL: test-ggc-bugfix.c.exe iteration 1 of 5: verify_code: result is NULL
> FAIL: test-ggc-bugfix.c.exe killed: SIGABRT SIGABRT

This testcase now passes in the JIT suite.

Bootstraps on build-x86_64-pc-linux-gnu  with no new regressions, and fixes that jit regression as well.   Pushed.

Andrew


From 19347db37f572aa0fc165977741d56005d29c2a7 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <[email protected]>
Date: Tue, 30 Sep 2025 15:59:38 -0400
Subject: [PATCH] Fix off by one in range_from_loop_direction.

When bounds_of_var_in_loop was converted to range_from_loop_direction,
the final check returned FALSE when the beginning and end bounds were
the same...  The new code was using wi::gt_p, when it should have been
wi::ge_p when checking for the fail condition.

	PR tree-optimization/120560
	gcc/
	* vr-values.cc (range_from_loop_direction): Use wi::ge_p rather
	than wi::gt_p.

        testsuite/
	* gcc.dg/pr120560.c: New.
---
 gcc/testsuite/gcc.dg/pr120560.c | 13 +++++++++++++
 gcc/vr-values.cc                |  4 ++--
 2 files changed, 15 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr120560.c

diff --git a/gcc/testsuite/gcc.dg/pr120560.c b/gcc/testsuite/gcc.dg/pr120560.c
new file mode 100644
index 00000000000..deb3c18f0b1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr120560.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fno-tree-ccp -fdump-tree-evrp" } */
+int main() {
+  int a = -1, b = 2, c = 1;
+  if (a >= 0)
+    c = 0;
+  while (1) {
+    if (-b + c - 7 >= 0)
+      return 0;
+    b = b - 1000 - 2147482648;
+  }
+}
+/* { dg-final { scan-tree-dump "return 0"  "evrp" } } */
diff --git a/gcc/vr-values.cc b/gcc/vr-values.cc
index ff11656559b..44dff35bcf2 100644
--- a/gcc/vr-values.cc
+++ b/gcc/vr-values.cc
@@ -278,14 +278,14 @@ range_from_loop_direction (irange &r, tree type,
     r.set_varying (type);
   else if (dir == EV_DIR_GROWS)
     {
-      if (wi::gt_p (begin.lower_bound (), end.upper_bound (), sign))
+      if (wi::ge_p (begin.lower_bound (), end.upper_bound (), sign))
 	r.set_varying (type);
       else
 	r = int_range<1> (type, begin.lower_bound (), end.upper_bound ());
     }
   else
     {
-      if (wi::gt_p (end.lower_bound (), begin.upper_bound (), sign))
+      if (wi::ge_p (end.lower_bound (), begin.upper_bound (), sign))
 	r.set_varying (type);
       else
 	r = int_range<1> (type, end.lower_bound (), begin.upper_bound ());
-- 
2.45.0

Reply via email to