Skip to content

Commit

Permalink
[PR tree-optimization/98028] Use relationship between operands to sim…
Browse files Browse the repository at this point in the history
…plify SUB_OVERFLOW

So this is a fairly old regression, but with all the ranger work that's been
done, it's become easy to resolve.

The basic idea here is to use known relationships between two operands of a
SUB_OVERFLOW IFN to statically compute the overflow state and ultimately allow
turning the IFN into simple arithmetic (or for the tests in this BZ elide the
arithmetic entirely).

The regression example is when the two inputs are known equal.  In that case
the subtraction will never overflow.    But there's a few other cases we can
handle as well.

a == b -> never overflows
a > b  -> never overflows when A and B are unsigned
a >= b -> never overflows when A and B are unsigned
a < b  -> always overflows when A and B are unsigned

Bootstrapped and regression tested on x86, and regression tested on the usual
cross platforms.

This is Jakub's version of the vr-values.cc fix rather than Jeff's.

	PR tree-optimization/98028
gcc/
	* vr-values.cc (check_for_binary_op_overflow): Try to use a known
	relationship betwen op0/op1 to statically determine overflow state.

gcc/testsuite
	* gcc.dg/tree-ssa/pr98028.c: New test.
  • Loading branch information
jakubjelinek authored and JeffreyALaw committed Feb 15, 2025
1 parent 8859dce commit 42a22b8
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 0 deletions.
26 changes: 26 additions & 0 deletions gcc/testsuite/gcc.dg/tree-ssa/pr98028.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* { dg-options "-O2 -fdump-tree-optimized" } */

unsigned f1(unsigned i, unsigned j) {
if (j != i) __builtin_unreachable();
return __builtin_sub_overflow_p(i, j, (unsigned)0);
}

unsigned f2(unsigned i, unsigned j) {
if (j > i) __builtin_unreachable();
return __builtin_sub_overflow_p(i, j, (unsigned)0);
}

unsigned f3(unsigned i, unsigned j) {
if (j >= i) __builtin_unreachable();
return __builtin_sub_overflow_p(i, j, (unsigned)0);
}

unsigned f4(unsigned i, unsigned j) {
if (j <= i) __builtin_unreachable();
return __builtin_sub_overflow_p(i, j, (unsigned)0);
}

/* { dg-final { scan-tree-dump-times "return 0" 3 optimized } } */
/* { dg-final { scan-tree-dump-times "return 1" 1 optimized } } */
/* { dg-final { scan-tree-dump-not "SUB_OVERFLOW" optimized } } */
/* { dg-final { scan-tree-dump-not "IMAGPART_EXPR" optimized } } */
33 changes: 33 additions & 0 deletions gcc/vr-values.cc
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,20 @@ check_for_binary_op_overflow (range_query *query,
enum tree_code subcode, tree type,
tree op0, tree op1, bool *ovf, gimple *s = NULL)
{
relation_kind rel = VREL_VARYING;
/* For subtraction see if relations could simplify it. */
if (s
&& subcode == MINUS_EXPR
&& types_compatible_p (TREE_TYPE (op0), TREE_TYPE (op1)))
{
rel = query->relation().query (s, op0, op1);
/* The result of the infinite precision subtraction of
the same values will be always 0. That will fit into any result
type. */
if (rel == VREL_EQ)
return true;
}

int_range_max vr0, vr1;
if (!query->range_of_expr (vr0, op0, s) || vr0.undefined_p ())
vr0.set_varying (TREE_TYPE (op0));
Expand All @@ -96,6 +110,25 @@ check_for_binary_op_overflow (range_query *query,
tree vr1min = wide_int_to_tree (TREE_TYPE (op1), vr1.lower_bound ());
tree vr1max = wide_int_to_tree (TREE_TYPE (op1), vr1.upper_bound ());

/* If op1 is not negative, op0 - op1 in infinite precision for op0 >= op1
will be always in [0, op0] and so if vr0max - vr1min fits into type,
there won't be any overflow. */
if ((rel == VREL_GT || rel == VREL_GE)
&& tree_int_cst_sgn (vr1min) >= 0
&& !arith_overflowed_p (MINUS_EXPR, type, vr0max, vr1min))
return true;

/* If op1 is not negative, op0 - op1 in infinite precision for op0 < op1
will be always in [-inf, -1] and so will always overflow if type is
unsigned. */
if (rel == VREL_LT
&& tree_int_cst_sgn (vr1min) >= 0
&& TYPE_UNSIGNED (type))
{
*ovf = true;
return true;
}

*ovf = arith_overflowed_p (subcode, type, vr0min,
subcode == MINUS_EXPR ? vr1max : vr1min);
if (arith_overflowed_p (subcode, type, vr0max,
Expand Down

0 comments on commit 42a22b8

Please sign in to comment.