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]>
---
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 149ad5e7747..c3f720a786f 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)
{
--
2.43.0