https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68120
Bug ID: 68120
Summary: can't easily deal with integer overflow at compile
time
Product: gcc
Version: unknown
Status: UNCONFIRMED
Severity: enhancement
Priority: P3
Component: c
Assignee: unassigned at gcc dot gnu.org
Reporter: eggert at gnu dot org
Target Milestone: ---
This is a followup to Bug#61129, which asked for integer-overflow-detecting
arithmetic intrinsics. We have them now (thanks!) but I'm running into some
problems using them.
The Gnulib intprops module defines macros to check for integer overflow, e.g.,
INT_ADD_OVERFLOW (a, b) returns 1 if the C expression A+B would overflow. These
macros are implemented in portable C. I'm trying to use GCC 5's new
__builtin_add_overflow etc. functions to speed up their runtime execution. This
turns out to be a pain because these macros are used in integer constant
expressions, where __builtin_add_overflow etc. cannot be used.
I am working around the problem with macro definitions like this:
# define INT_ADD_OVERFLOW(a, b) \
(__builtin_constant_p ((a) == (b)) \
? _GL_INT_ADD_OVERFLOW (a, b) \
: __builtin_add_overflow (a, b, &(__typeof__ ((a) + (b))) {0}))
where _GL_INT_ADD_OVERFLOW is a complex macro implemented in Standard C and is
a constant expression when its arguments are constant expressions. Although I
think this will work, it is ugly, and the macro _GL_INT_ADD_OVERFLOW is
complicated.
To simplify use of __builtin_add_overflow etc., I suggest extending these
builtins as follows.
First, allow the 3rd argument to be a null pointer constant of type
pointer-to-integer, meaning that the caller only wants to know if the overflow
occurred and does not want the low-order bits of the result. E.g.,
__builtin_add_overflow (a, b, (int *) 0) returns 1 if the mathematical value of
A + B does not fit in 'int'. This would allow the above macro to be simplified
to:
# define INT_ADD_OVERFLOW(a, b) \
__builtin_add_overflow (a, b, (__typeof__ ((a) + (b)) *) 0)
Second, allow the 3rd argument to be omitted, as a shorthand for a null pointer
to the integer type of A+B. This further simplification would allow the above
macro to be simplified to:
# define INT_ADD_OVERFLOW(a, b) __builtin_add_overflow (a, b)
Third, add a function __builtin_add_wrapv (a, b, c) that acts like
__builtin_add_overflow (a, b, c) except that it returns the value that would be
stored if C were a non-null pointer. The 3rd argument C is optional here too,
with the same semantics as for __builtin_add_overflow. This will let the user
get the bottom-order bits of an overflowed value in a constant expression,
something that can't be done with the current primitives.
The basic idea here is that we need intrinsics that deal with values and that
do not require non-null addresses, so that we can use these intrinsics in
constant expressions.