https://gcc.gnu.org/g:61e2300bc9364a9060aca12ba189d5bbca950aff

commit r17-1061-g61e2300bc9364a9060aca12ba189d5bbca950aff
Author: Andrew Pinski <[email protected]>
Date:   Sat May 30 15:54:59 2026 -0700

    range-op: Add relation effect for integer mult [PR23471]
    
    tree_expr_nonnegative_p has code to say `a*a` is nonnegative
    (for signed integers). But when I removed the call to
    gimple_stmt_nonnegative_p, ranger could not figure out that
    that `a*a` is nonnegative. This shows up as a regression
    on riscv with `gcc.target/riscv/rvv/vsetvl/avl_single-65.c`.
    But you can also reproduce the same issue if we disable forwprop
    and look at the result of EVRP and look at the exported range
    for that statement.
    
    The fix is to teach the range multiply operator that when
    dealing with `a*a`, the lhs will be non-negative.
    That is add a op1_op2_relation_effect method to operator_mult
    that handles the case where the relationship is equal.
    
    vrp-mult-nonneg-1.c is now a testcase which GCC can optimize
    which was not handled before.
    vrp-mult-nonneg-2.c is the reduced testcase for PR125513 and the regression.
    
    Bootstrapped and tested on x86_64-linux-gnu.
    
            PR tree-optimization/23471
            PR tree-optimization/125513
    
    gcc/ChangeLog:
    
            * range-op-mixed.h (operator_mult): Add op1_op2_relation_effect
            for 2xirange.
            * range-op.cc (operator_mult::op1_op2_relation_effect): New 
function.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.dg/tree-ssa/vrp-mult-nonneg-1.c: New test.
            * gcc.dg/tree-ssa/vrp-mult-nonneg-2.c: New test.
    
    Signed-off-by: Andrew Pinski <[email protected]>

Diff:
---
 gcc/range-op-mixed.h                              |  5 +++++
 gcc/range-op.cc                                   | 19 +++++++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/vrp-mult-nonneg-1.c | 17 +++++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/vrp-mult-nonneg-2.c | 14 ++++++++++++++
 4 files changed, 55 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 854a801afcc5..a870a0c12116 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -734,6 +734,7 @@ public:
   using range_operator::op1_range;
   using range_operator::op2_range;
   using range_operator::update_bitmask;
+  using range_operator::op1_op2_relation_effect;
   bool op1_range (irange &r, tree type,
                  const irange &lhs, const irange &op2,
                  relation_trio) const final override;
@@ -756,6 +757,10 @@ public:
                const wide_int &rh_ub) const final override;
   bool wi_op_overflows (wide_int &res, tree type, const wide_int &w0,
                        const wide_int &w1) const final override;
+  bool op1_op2_relation_effect (irange &lhs_range, tree type,
+                               const irange &op1_range,
+                               const irange &op2_range,
+                               relation_kind rel) const final override;
 
   void rv_fold (frange &r, tree type,
                const REAL_VALUE_TYPE &lh_lb, const REAL_VALUE_TYPE &lh_ub,
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 689665295fa4..5eb3582a2357 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -2387,6 +2387,25 @@ operator_mult::wi_fold (irange &r, tree type,
     }
 }
 
+bool
+operator_mult::op1_op2_relation_effect (irange &lhs_range, tree type,
+                                       const irange &,
+                                       const irange &,
+                                       relation_kind rel) const
+{
+  // a*a is nonnegative without overflow.
+  // tree_binary_nonnegative_p handles this in a similar way.
+  if (rel == VREL_EQ
+      && TYPE_OVERFLOW_UNDEFINED (type))
+    {
+      int_range<2> nonnegative;
+      nonnegative.set_nonnegative (type);
+      lhs_range.intersect (nonnegative);
+      return true;
+    }
+  return false;
+}
+
 class operator_widen_mult_signed : public range_operator
 {
 public:
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-mult-nonneg-1.c 
b/gcc/testsuite/gcc.dg/tree-ssa/vrp-mult-nonneg-1.c
new file mode 100644
index 000000000000..308d7e84b6cd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-mult-nonneg-1.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized -fdump-tree-evrp-details" } */
+/* PR tree-optimization/23471 */
+
+int f(int a, int b)
+{
+  if (a == b)
+  {
+    int t = a*b;
+    return t < 0; /* Should be optimized to 0. */
+  }
+  return 0;
+}
+
+
+/* { dg-final { scan-tree-dump-not "if " "optimized" } } */
+/* { dg-final { scan-tree-dump "Global Exported: t_" "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-mult-nonneg-2.c 
b/gcc/testsuite/gcc.dg/tree-ssa/vrp-mult-nonneg-2.c
new file mode 100644
index 000000000000..ab1a641c0b76
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-mult-nonneg-2.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-tree-forwprop -fdump-tree-optimized 
-fdump-tree-evrp-details" } */
+/* PR tree-optimization/125513 */
+
+
+int f(int a)
+{
+  int t = a*a;
+  return t < 0; /* Should be optimized to 0. */
+}
+
+
+/* { dg-final { scan-tree-dump "return 0" "optimized" } } */
+/* { dg-final { scan-tree-dump "Global Exported: t_" "evrp" } } */

Reply via email to