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

commit r17-992-ga94d2d065efd35473c113cfb38b87234218341a3
Author: Andrew Pinski <[email protected]>
Date:   Wed May 27 21:09:01 2026 -0700

    ranger-fold: Don't call into gimple_stmt_nonnegative_p [PR125475]
    
    When fold_using_range::fold_stmt comes in with a varying range,
    it currently calls gimple_stmt_nonnegative_p to see if the value
    is non-negative. But in the case where it matters (pr33738.C),
    it will return true always because here we have just an unsigned type.
    That sets the range to `[0, type_max]`. So instead we should
    check if the type_min/type_max is not the same as precisionmin/precisionmax
    and set the range to `[type_min, type_max]` in that case.
    
    This fixes a recusion if we change tree_expr_nonnegative_p over to use
    the ranger and I suspect might it help Ada code too.
    
            PR tree-optimization/125475
    
    gcc/ChangeLog:
    
            * gimple-range-fold.cc (fold_using_range::fold_stmt): Don't call
            gimple_stmt_nonnegative_p. Instead set the varying range to
            `[type_min, type_max]` if not the same as the precision.
    
    Signed-off-by: Andrew Pinski <[email protected]>

Diff:
---
 gcc/gimple-range-fold.cc | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index 149ad5e77476..c3f720a786f6 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -684,12 +684,22 @@ fold_using_range::fold_stmt (vrange &r, gimple *s, 
fur_source &src, tree name)
   else if (is_a<gassign *> (s) && gimple_assign_rhs_code (s) == COND_EXPR)
     res = range_of_cond_expr (r, as_a<gassign *> (s), src);
 
-  // If the result is varying, check for basic nonnegativeness.
-  // Specifically this helps for now with strict enum in cases like
-  // g++.dg/warn/pr33738.C.
-  if (res && r.varying_p () && INTEGRAL_TYPE_P (r.type ())
-      && gimple_stmt_nonnegative_p (s))
-    r.set_nonnegative (r.type ());
+  // If the result is varying, use the type's min/max if either is not
+  // the same as the full precision min/max. This helps with strict enum
+  // e.g. `g++.dg/warn/pr33738.C`.
+  if (res && r.varying_p () && INTEGRAL_TYPE_P (r.type ()))
+    {
+      irange &ir = as_a <irange> (r);
+      tree type = r.type ();
+      auto typemax = wi::to_wide (TYPE_MAX_VALUE (type));
+      auto typemin = wi::to_wide (TYPE_MIN_VALUE (type));
+      auto precisionmax = wi::max_value (TYPE_PRECISION (type),
+                                        TYPE_SIGN (type));
+      auto precisionmin = wi::min_value (TYPE_PRECISION (type),
+                                        TYPE_SIGN (type));
+      if (typemax != precisionmax || typemin != precisionmin)
+       ir.set (type, typemin, typemax);
+    }
 
   if (!res)
     {

Reply via email to