Hi Andrea and Richard,

I changed this to be perhaps less ambitious.

Instead of trying to modify the existing poly_int API's and make them
some level of target dependent I instead just added a new API for
target aware poly_int comparisons and upper/lower bounds.

Which I think makes a lot more sense.

As a benefit, it means I didn't have to change loads of uses of maybe_lt and
similar.

I'm not sure about the names I chose though.

Is this any better?

Bootstrapped and regr tested on aarch64-linux-gnu, x86_64-linux-gnu, 
armhf-linux-gnu.

Thanks,
Alfie

-- >8 --

gcc/ChangeLog:

        * Makefile.in: Add target dependency on new
        poly-int-target-bounds.h..
        * target.h: Add include of poly-int-target-bounds.h.
        * value-query.cc (range_query::get_tree_range): Use new
        functions for poly int bounds.
        * poly-int-target-bounds.h: New file.

---
 gcc/Makefile.in              |   2 +-
 gcc/poly-int-target-bounds.h | 264 +++++++++++++++++++++++++++++++++++
 gcc/target.h                 |   2 +
 gcc/value-query.cc           |  85 +++--------
 4 files changed, 283 insertions(+), 70 deletions(-)
 create mode 100644 gcc/poly-int-target-bounds.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index c6059206a95..c2e5a05c770 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -995,7 +995,7 @@ COMMON_TARGET_DEF = common/common-target.def 
target-hooks-macros.h
 D_TARGET_DEF = d/d-target.def target-hooks-macros.h
 RUST_TARGET_DEF = rust/rust-target.def target-hooks-macros.h
 JIT_TARGET_DEF = jit/jit-target.def target-hooks-macros.h
-TARGET_H = $(TM_H) target.h $(TARGET_DEF) insn-modes.h insn-codes.h
+TARGET_H = $(TM_H) target.h $(TARGET_DEF) insn-modes.h insn-codes.h 
poly-int-target-bounds.h
 C_TARGET_H = c-family/c-target.h $(C_TARGET_DEF)
 COMMON_TARGET_H = common/common-target.h $(INPUT_H) $(COMMON_TARGET_DEF)
 D_TARGET_H = d/d-target.h $(D_TARGET_DEF)
diff --git a/gcc/poly-int-target-bounds.h b/gcc/poly-int-target-bounds.h
new file mode 100644
index 00000000000..c6b1e6e1bd5
--- /dev/null
+++ b/gcc/poly-int-target-bounds.h
@@ -0,0 +1,264 @@
+/* Operations with very long integers.
+   Copyright (C) 2026-2026 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3, or (at your option) any
+later version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* Functions for reasoning about poly_int's with information from
+   targetm.indeterminate_bound hook.  */
+
+#ifndef HAVE_POLY_INT_TARGET_BOUNDS_H
+#define HAVE_POLY_INT_TARGET_BOUNDS_H
+
+/* Attempts to find an upper bound for poly-int A, potentially using the target
+   poly_int_indeterminate_bound hook if defined. On success stores the result
+   in RES and returns true.  */
+
+template <typename Ca>
+inline bool
+maybe_upper_bound (const poly_int<NUM_POLY_INT_COEFFS, Ca> &a,
+                         WI_BINARY_RESULT
+                           (Ca, WI_BINARY_RESULT
+                                  (Ca, unsigned HOST_WIDE_INT)) * res,
+                         signop sgn)
+{
+  typedef WI_BINARY_RESULT (Ca, unsigned HOST_WIDE_INT) C1;
+  typedef WI_BINARY_RESULT (Ca, C1) Cr;
+
+  wi::overflow_type ovf = wi::OVF_NONE;
+  if (NUM_POLY_INT_COEFFS < 2 || wi::neg_p (a.coeffs[1], sgn)
+      || wi::eq_p (a.coeffs[1], wi::ints_for<Ca>::zero (a.coeffs[1])))
+    {
+      Cr temp2 = wi::add (a.coeffs[0], wi::ints_for<C1>::zero (a.coeffs[0]),
+                         sgn, &ovf);
+      gcc_assert (ovf == wi::OVF_NONE);
+      *res = temp2;
+      return true;
+    }
+
+  const poly_uint64 indeterminate_bound
+    = targetm.poly_int_indeterminate_bound ();
+
+  if (indeterminate_bound.coeffs[1] == HOST_WIDE_INT_M1U)
+    return false;
+
+  C1 temp1 = wi::mul (a.coeffs[1], indeterminate_bound.coeffs[1], sgn, &ovf);
+  if (ovf != wi::OVF_NONE)
+    return false;
+  Cr temp2 = wi::add (a.coeffs[0], temp1, sgn, &ovf);
+  if (ovf != wi::OVF_NONE)
+    return false;
+
+  *res = temp2;
+  return true;
+}
+
+/* Attempts to find a lower bound for poly-int A, potentially using the target
+   poly_int_indeterminate_bound hook if defined. On success stores the result
+   in RES and returns true.  */
+
+template <typename Ca>
+inline bool
+maybe_lower_bound (const poly_int<NUM_POLY_INT_COEFFS, Ca> &a,
+                  WI_BINARY_RESULT (Ca, WI_BINARY_RESULT (Ca, unsigned 
HOST_WIDE_INT))
+                    * res,
+                  signop sgn)
+{
+  typedef WI_BINARY_RESULT (Ca, unsigned HOST_WIDE_INT) C1;
+  typedef WI_BINARY_RESULT (Ca, C1) Cr;
+
+  wi::overflow_type ovf = wi::OVF_NONE;
+  if (NUM_POLY_INT_COEFFS < 2 || !wi::neg_p (a.coeffs[1], sgn))
+    {
+      Cr temp2 = wi::add (a.coeffs[0], wi::ints_for<C1>::zero (a.coeffs[0]),
+                         sgn, &ovf);
+      gcc_assert (ovf == wi::OVF_NONE);
+      *res = temp2;
+      return true;
+    }
+
+  const poly_uint64 indeterminate_bound
+    = targetm.poly_int_indeterminate_bound ();
+
+  if (indeterminate_bound.coeffs[1] == HOST_WIDE_INT_M1U)
+    return false;
+
+  C1 temp1 = wi::mul (a.coeffs[1], indeterminate_bound.coeffs[1], sgn, &ovf);
+  if (ovf != wi::OVF_NONE)
+    return false;
+  Cr temp2 = wi::add (a.coeffs[0], temp1, sgn, &ovf);
+  if (ovf != wi::OVF_NONE)
+    return false;
+
+  *res = temp2;
+  return true;
+}
+
+/* Similar to maybe_le but also uses information from maybe_upper_bound and
+   maybe_lower_bound.  */
+template <typename Ca, typename Cb>
+inline bool
+target_maybe_le (const poly_int<NUM_POLY_INT_COEFFS, Ca> &a,
+                const poly_int<NUM_POLY_INT_COEFFS, Cb> &b)
+{
+  typedef WI_BINARY_RESULT (Ca, unsigned int) type_a;
+  typedef WI_BINARY_RESULT (Cb, unsigned int) type_b;
+
+  signop sgn = (poly_coeff_traits<type_a>::signedness == 1
+                   || poly_coeff_traits<type_b>::signedness == 1
+                 ? SIGNED
+                 : UNSIGNED);
+
+  type_a a_lower_bound = 0;
+  type_b b_upper_bound = 0;
+  if (maybe_lower_bound (a, &a_lower_bound, sgn)
+      && maybe_upper_bound (b, &b_upper_bound, sgn)
+      && wi::gt_p (a_lower_bound, b_upper_bound, sgn))
+    return false;
+
+  return maybe_le (a, b);
+}
+
+/* Similar to maybe_le but also uses information from maybe_upper_bound and
+   maybe_lower_bound.  */
+template <typename Ca, typename Cb>
+inline typename if_nonpoly<Cb, bool>::type
+target_maybe_le (const poly_int<NUM_POLY_INT_COEFFS, Ca> &a, const Cb &b
+         )
+{
+  typedef WI_BINARY_RESULT (Ca, unsigned int) type_a;
+  signop sgn = (poly_coeff_traits<type_a>::signedness == 1 ? SIGNED : 
UNSIGNED);
+
+  type_a a_lower_bound = 0;
+  if (maybe_lower_bound (a, &a_lower_bound, sgn)
+      && wi::gt_p (a_lower_bound, b, sgn))
+    return false;
+
+  return maybe_le (a, b);
+}
+
+/* Similar to maybe_le but also uses information from maybe_upper_bound and
+   maybe_lower_bound.  */
+template <typename Ca, typename Cb>
+inline typename if_nonpoly<Ca, bool>::type
+target_maybe_le (const Ca &a, const poly_int<NUM_POLY_INT_COEFFS, Cb> &b
+         )
+{
+  typedef WI_BINARY_RESULT (Cb, unsigned int) type_b;
+  signop sgn = (poly_coeff_traits<type_b>::signedness == 1 ? SIGNED : 
UNSIGNED);
+
+  type_b b_upper_bound = 0;
+  if (maybe_upper_bound (b, &b_upper_bound, sgn)
+      && wi::gt_p (a, b_upper_bound, sgn))
+    return false;
+
+  return maybe_le (a, b);
+}
+
+/* Similar to maybe_le but also uses information from maybe_upper_bound and
+   maybe_lower_bound.  */
+template <typename Ca, typename Cb>
+inline typename if_nonpoly2<Ca, Cb, bool>::type
+target_maybe_le (const Ca &a, const Cb &b)
+{
+  return maybe_le (a, b);
+}
+
+/* Similar to maybe_lt but also uses information from maybe_upper_bound and
+   maybe_lower_bound.  */
+template <typename Ca, typename Cb>
+inline bool
+target_maybe_lt (const poly_int<NUM_POLY_INT_COEFFS, Ca> &a, const 
poly_int<NUM_POLY_INT_COEFFS, Cb> &b)
+{
+  typedef WI_BINARY_RESULT (Ca, unsigned int) type_a;
+  typedef WI_BINARY_RESULT (Cb, unsigned int) type_b;
+  signop sgn = (poly_coeff_traits<type_a>::signedness == 1
+                   || poly_coeff_traits<type_b>::signedness == 1
+                 ? SIGNED
+                 : UNSIGNED);
+
+  type_a a_lower_bound = 0;
+  type_b b_upper_bound = 0;
+  if (maybe_lower_bound (a, &a_lower_bound, sgn)
+      && maybe_upper_bound (b, &b_upper_bound, sgn)
+      && wi::ge_p (a_lower_bound, b_upper_bound, sgn))
+    return false;
+
+  return maybe_lt (a, b);
+}
+
+/* Similar to maybe_lt but also uses information from maybe_upper_bound and
+   maybe_lower_bound.  */
+template <typename Ca, typename Cb>
+inline typename if_nonpoly<Cb, bool>::type
+target_maybe_lt (const poly_int<NUM_POLY_INT_COEFFS, Ca> &a, const Cb &b
+         )
+{
+  typedef WI_BINARY_RESULT (Ca, unsigned int) type_a;
+  signop sgn = (poly_coeff_traits<type_a>::signedness == 1 ? SIGNED : 
UNSIGNED);
+
+  type_a a_lower_bound = 0;
+  if (maybe_lower_bound (a, &a_lower_bound, sgn)
+      && wi::ge_p (a_lower_bound, b, sgn))
+    return false;
+
+  return maybe_lt (a, b);
+}
+
+/* Similar to maybe_lt but also uses information from maybe_upper_bound and
+   maybe_lower_bound.  */
+template <typename Ca, typename Cb>
+inline typename if_nonpoly<Ca, bool>::type
+target_maybe_lt (const Ca &a, const poly_int<NUM_POLY_INT_COEFFS, Cb> &b)
+{
+  typedef WI_BINARY_RESULT (Cb, unsigned int) type_b;
+  signop sgn = (poly_coeff_traits<type_b>::signedness == 1 ? SIGNED : 
UNSIGNED);
+
+  type_b b_upper_bound = 0;
+  if (maybe_upper_bound (b, &b_upper_bound, sgn)
+      && wi::ge_p (a, b_upper_bound, sgn))
+    return false;
+
+  return maybe_lt (a, b);
+}
+
+/* Similar to maybe_lt but also uses information from maybe_upper_bound and
+   maybe_lower_bound.  */
+template<typename Ca, typename Cb>
+inline typename if_nonpoly2<Ca, Cb, bool>::type
+target_maybe_lt (const Ca &a, const Cb &b)
+{
+  return maybe_lt (a, b);
+}
+
+/* Return true if A may be greater than or equal to B.  */
+#define target_maybe_ge(A, B) target_maybe_le (B, A)
+
+/* Return true if A may be greater than B.  */
+#define target_maybe_gt(A, B) target_maybe_lt (B, A)
+
+/* Return true if A is known to be less than or equal to B.  */
+#define target_known_le(A, B) (!target_maybe_gt (A, B))
+
+/* Return true if A is known to be less than B.  */
+#define target_known_lt(A, B) (!target_maybe_ge (A, B))
+
+/* Return true if A is known to be greater than B.  */
+#define target_known_gt(A, B) (!target_maybe_le (A, B))
+
+/* Return true if A is known to be greater than or equal to B.  */
+#define target_known_ge(A, B) (!target_maybe_lt (A, B))
+#endif
diff --git a/gcc/target.h b/gcc/target.h
index 67b04f90f45..bc9239bfaa8 100644
--- a/gcc/target.h
+++ b/gcc/target.h
@@ -337,6 +337,8 @@ extern bool verify_type_context (location_t, 
type_context_kind, const_tree,
 
 extern struct gcc_target targetm;
 
+#include "poly-int-target-bounds.h"
+
 /* Return an estimate of the runtime value of X, for use in things
    like cost calculations or profiling frequencies.  Note that this
    function should never be used in situations where the actual
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index 0a6de62d763..8b3d607f0e0 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -442,86 +442,33 @@ range_query::get_tree_range (vrange &r, tree expr, gimple 
*stmt,
        {
          unsigned int precision = TYPE_PRECISION (type);
          signop sign = TYPE_SIGN (type);
-         bool have_poly_bound = targetm.poly_int_indeterminate_bound;
-         poly_uint64 indeterminate_bound;
-
-         if (have_poly_bound)
-           indeterminate_bound = targetm.poly_int_indeterminate_bound ();
 
          auto val = wi::to_poly_wide (expr);
          auto type_min = wi::to_wide (TYPE_MIN_VALUE (type));
          auto type_max = wi::to_wide (TYPE_MAX_VALUE (type));
 
-         /* Start with the invariant part of the poly-int, then account
-            for each coefficient below.
-
-            The target hook gives a per-coefficient upper bound for the
-            indeterminate.  Since those indeterminates are unsigned and
-            nonnegative, a positive coefficient can only increase the upper
-            bound and a negative coefficient can only decrease the lower
-            bound.  The opposite bound is unaffected by that coefficient:
-
-               [A, +C] with C >= 0  => max += C * bound
-               [A, -C] with C >= 0  => min -= C * bound.  */
-         wide_int bounds[2] = { val.coeffs[0], val.coeffs[0] };
-         bool ovf[2] = { false, false };
+         wide_int lower_bound = type_min;
+         wide_int upper_bound = type_max;
 
-         for (unsigned int i = 1; i < NUM_POLY_INT_COEFFS; ++i)
+         if (!maybe_lower_bound (val, &lower_bound, sign)
+             || wi::lt_p (lower_bound, type_min, sign)
+             || wi::gt_p (lower_bound, type_max, sign)
+             || !maybe_upper_bound (val, &upper_bound, sign)
+             || wi::lt_p (upper_bound, type_min, sign)
+             || wi::gt_p (upper_bound, type_max, sign))
            {
-             const auto &coeff = val.coeffs[i];
-             if (wi::eq_p (coeff, 0))
-               continue;
-
-             /* Select the only bound affected by this coefficient.  A
-                negative coefficient contributes to the minimum and a positive
-                coefficient contributes to the maximum.  */
-             bool coeff_neg = wi::neg_p (coeff, sign);
-             wide_int &bound = bounds[coeff_neg ? 0 : 1];
-             bool &bound_ovf = ovf[coeff_neg ? 0 : 1];
-
-             if (bound_ovf)
-               continue;
-
-             /* A missing hook, or a -1 bound for this coefficient, means the
-                indeterminate has no finite target-specific limit.  Treat that
-                like an overflow of the affected bound.  */
-             if (!have_poly_bound
-                 || indeterminate_bound.coeffs[i] == HOST_WIDE_INT_M1U)
-               bound_ovf = true;
-             else
-               {
-                 auto indeterminate
-                   = wi::uhwi (indeterminate_bound.coeffs[i], precision);
-                 wi::overflow_type mul_ovf = wi::OVF_NONE;
-                 auto term = wi::mul (coeff, indeterminate, sign, &mul_ovf);
-                 wi::overflow_type add_ovf = wi::OVF_NONE;
-                 bound = wi::add (bound, term, sign, &add_ovf);
-                 bound_ovf = (mul_ovf != wi::OVF_NONE
-                              || add_ovf != wi::OVF_NONE);
-               }
-
-             if (TYPE_OVERFLOW_WRAPS (type) && bound_ovf)
-               {
-                 r.set_varying (type);
-                 r.update_bitmask (irange_bitmask (wi::zero (precision),
-                                                   get_nonzero_bits (expr)));
-                 return true;
-               }
-
-             if (bound_ovf)
-               {
-                 if (coeff_neg)
-                   bounds[0] = type_min;
-                 else
-                   bounds[1] = type_max;
-               }
+             /* Overflow risk, so no known bounds.  */
+             r.set_varying (type);
+             r.update_bitmask (
+               irange_bitmask (wi::zero (precision), get_nonzero_bits (expr)));
+             return true;
            }
 
          /* Check that the target filled in sensible bounds information.  */
-         gcc_assert (wi::le_p (bounds[0], bounds[1], sign));
+         gcc_assert (wi::le_p (lower_bound, upper_bound, sign));
 
-         irange &ir = as_a <irange> (r);
-         ir.set (type, bounds[0], bounds[1]);
+         irange &ir = as_a<irange> (r);
+         ir.set (type, lower_bound, upper_bound);
 
          /* Preserve alignment/step information that is not visible in the
             intervals.  For example, a poly-int like [8, 8] can

base-commit: 2104f1a937eb8c7a701fb7338bee9bfb5f72f902
prerequisite-patch-id: 0d9051391951dc1e79747ae3ca9e35d24c465cc6
prerequisite-patch-id: 0362494f3f88c5e41836a90c542d548d3b78e533
prerequisite-patch-id: 49de9244e7cccce43164831c61f4bbf4801f1d20
prerequisite-patch-id: 160fc126a7452ec2506c145b0496d18fb2f413db
prerequisite-patch-id: 4786144a4f5cd1f711825d8d88a0d7c96b05edbf
prerequisite-patch-id: 0db128616ab469fc37c23d9eba4c557d6ddc8a5e
prerequisite-patch-id: dccb6d3c6e66f276b6e9891adead1f6103220ad6
prerequisite-patch-id: dc007013711d7a8f07cf2a12d3cef57717573406
prerequisite-patch-id: 1ebad3462102e470ccb73f636a9c213ffd22b7ea
prerequisite-patch-id: 17413a65c07f74f24e1dc902e810a6b58d97ae1e
prerequisite-patch-id: 6c8ef12a9cba1c1fc763d96cfa9c59cd6f864b9c
prerequisite-patch-id: 1963ce31969e639922d78f0fffaaa25df43089c3
prerequisite-patch-id: 6753e8252d37568f704c6913f10568bb9691814c
prerequisite-patch-id: 3bcf8be107c5ddfc035eb1def9e2ac42d7da0e16
prerequisite-patch-id: 053fee9945ce94e1c1045dbfa2608c0fed21c9cf
prerequisite-patch-id: f367f9bdd72b059b3c6970fcd0df573814c0915b
prerequisite-patch-id: 09ca4106089b2b729305c85ac9c11310a1a3f627
-- 
2.56.0

Reply via email to