On Tue, Feb 11, 2025 at 05:20:49PM -0700, Jeff Law wrote:
> 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

Is that really the case?
I mean, .SUB_OVERFLOW etc. can have 3 arbitrary types, the type into which
we are trying to write the result and the 2 types of arguments.
Consider:

int
foo (unsigned x, unsigned y)
{
  return __builtin_sub_overflow_p (x, y, (signed char) 0);
}

int
bar (unsigned int x, unsigned long long y)
{
  return __builtin_sub_overflow_p (x, y, (_BitInt(33)) 0);
}

int
main ()
{
  __builtin_printf ("%d\n", foo (16, 16));
  __builtin_printf ("%d\n", foo (65536, 65536));
  __builtin_printf ("%d\n", foo (65536, 16));
  __builtin_printf ("%d\n", bar (0, ~0U));
  __builtin_printf ("%d\n", bar (0, ~0ULL));
}

The a == b case is probably ok, although unsure if the relation query
won't be upset if op0 and op1 have different types (say signed long long vs.
unsigned int), given that result in infinite precision should be 0 and
that will fit into any type.
But the a > b and a >= b cases clearly can overflow if the result type
(element type of the COMPLEX_TYPE result of the ifn) can't represent all the
values of op0's type, so if say __builtin_add_overflow_p with second
argument 0 would also overflow.
And the a < b case can also overflow or not overflow depending on the types
as shown in the test.

So, I think you want to:
a) see with Andrew or check yourself whether relation query can deal with
   operands with different types; if not, restrict just to the case
   where they are compatible
b) either restrict the a > b, a >= b and a < b new optimizations to
   cases where the result and operand types are the same, or add further
   checks; for the a > b and a >= b case there won't be overflow if
   result type can fit all the values in a's type, or as we are in the
   ranger we can just check if the range maximum of op0
   fits into the result type (or even use ranges of both op0 and op1
   for that, we know that the result will be always non-negative given the
   a > b or a >= b relations, so check if maximum of op0 minus minimum of
   op1 will fit into the result type); if yes, it never overflows, otherwise
   we don't know.  Also, unsure why this is about TYPE_UNSIGNED only;
   even for signed operands, if a > b or a >= b, the infinite precision
   result is still non-negative.
   What the a > b and a >= b relations bring into the picture for MINUS_EXPR
   is simply that we don't need to check 2 arith_overflowed_p cases
   but just one; the vr0max vs. vr1min, as for the vr0min vs. vr1max case
   we know it doesn't overflow unless the first one overflows.
   For the a < b case again similarly.

        Jakub

Reply via email to