Hi,

On 2019-07-17 17:29:58 +0900, Michael Paquier wrote:
> Actually, one thing which may be a problem is that we lack currently
> the equivalents of pg_mul_s16_overflow and such for unsigned
> integers.

It's much simpler to implement them for unsigned than for signed,
because unsigned overflow is well-defined. So I'd not be particularly
worried about just adding them.  E.g. comparing the "slow" version of
pg_mul_s64_overflow() with an untested implementation of
pg_mul_u64_overflow():

pg_mul_s64_overflow:
        /*
         * Overflow can only happen if at least one value is outside the range
         * sqrt(min)..sqrt(max) so check that first as the division can be 
quite a
         * bit more expensive than the multiplication.
         *
         * Multiplying by 0 or 1 can't overflow of course and checking for 0
         * separately avoids any risk of dividing by 0.  Be careful about 
dividing
         * INT_MIN by -1 also, note reversing the a and b to ensure we're always
         * dividing it by a positive value.
         *
         */
        if ((a > PG_INT32_MAX || a < PG_INT32_MIN ||
                 b > PG_INT32_MAX || b < PG_INT32_MIN) &&
                a != 0 && a != 1 && b != 0 && b != 1 &&
                ((a > 0 && b > 0 && a > PG_INT64_MAX / b) ||
                 (a > 0 && b < 0 && b < PG_INT64_MIN / a) ||
                 (a < 0 && b > 0 && a < PG_INT64_MIN / b) ||
                 (a < 0 && b < 0 && a < PG_INT64_MAX / b)))
        {
                *result = 0x5EED;               /* to avoid spurious warnings */
                return true;
        }
        *result = a * b;
        return false;

pg_mul_s64_overflow:

        /*
         * Checking for unsigned overflow is simple, just check
         * if reversing the multiplication indicates that the
         * multiplication overflowed.
         */
        int64 res = a * b;
        if (a != 0 && b != res / a)
        {
                *result = 0x5EED;               /* to avoid spurious warnings */
                return true;
        }
        *result = res;
        return false;


The cases for addition/subtraction are even easier:
addition:
res = a + b;
if (res < a)
   /* overflow */

subtraction:
if (a < b)
   /* underflow */
res  = a - b;

Greetings,

Andres Freund


Reply via email to