]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
range-op: Add relation effect for integer mult [PR23471]
authorAndrew Pinski <andrew.pinski@oss.qualcomm.com>
Sat, 30 May 2026 22:54:59 +0000 (15:54 -0700)
committerAndrew Pinski <andrew.pinski@oss.qualcomm.com>
Sun, 31 May 2026 23:04:29 +0000 (16:04 -0700)
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 <andrew.pinski@oss.qualcomm.com>
gcc/range-op-mixed.h
gcc/range-op.cc
gcc/testsuite/gcc.dg/tree-ssa/vrp-mult-nonneg-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/vrp-mult-nonneg-2.c [new file with mode: 0644]

index 854a801afcc5941a2ae2f1105fc72806703850bb..a870a0c12116ec48e0753096d8e8fe8fabbca915 100644 (file)
@@ -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,
index 689665295fa48e1faeaa8ccc8f46e666325b6d0d..5eb3582a235707084d0c7492e4402a44d5e55263 100644 (file)
@@ -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 (file)
index 0000000..308d7e8
--- /dev/null
@@ -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 (file)
index 0000000..ab1a641
--- /dev/null
@@ -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" } } */