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" } } */
