If available, use GCC 5's builtin functions for efficient integer overflow checking. Also, add macros like INT_ADD_WRAPV that efficently and safely compute the low-order bits of the correct answer. A downside of these efficient functions is that they cannot be used in constant expressions, so add macros like INT_CONST_ADD_OVERFLOW and INT_CONST_ADD_WRAPV that can be used even in constant expressions. * NEWS: Document the incompatible changes to INT_ADD_OVERFLOW etc. * doc/intprops.texi (Integer Properties, Integer Type Overflow): Document the changes. (Wraparound Arithmetic): New section. (Integer Range Overflow): Put this subsection last, since it's least useful. * lib/intprops.h (INT_CONST_ADD_OVERFLOW) (INT_CONST_SUBTRACT_OVERFLOW, INT_CONST_MULTIPLY_OVERFLOW): New macros, with the meaning that INT_ADD_OVERFLOW etc. used to have. (INT_CONST_ADD_WRAPV, INT_CONST_SUBTRACT_WRAPV) (INT_NEGATE_WRAPV, INT_CONST_MULTIPLY_WRAPV, INT_DIVIDE_WRAPV) (INT_REMAINDER_WRAPV, _GL_INT_OP_WRAPV, _GL_EXPR_CAST) (_GL_INT_OP_WRAPV_LONGISH, INT_ADD_WRAPV, INT_SUBTRACT_WRAPV) (INT_MULTIPLY_WRAPV, _GL_OP_OVERFLOW, _GL_OP_WRAPV, _GL_OP_WRAPV_GENSYM): New macros. (INT_ADD_OVERFLOW, INT_SUBTRACT_OVERFLOW, INT_MULTIPLY_OVERFLOW): Generate calls to GCC builtins if available, for speed. * tests/test-intprops.c (INT_CONST_DIVIDE_OVERFLOW) (INT_CONST_REMAINDER_OVERFLOW, INT_CONST_LEFT_SHIFT_OVERFLOW) (INT_CONST_DIVIDE_WRAPV, INT_CONST_REMAINDER_WRAPV) (INT_CONST_LEFT_SHIFT_WRAPV): New macros. (main, CHECK_BINOP, CHECK_UNOP, CHECK_SUM, CHECK_PRODUCT) (CHECK_QUOTIENT, CHECK_REMAINDER): Test WRAPV and CONST flavors (when available) too. --- ChangeLog | 34 +++++ NEWS | 8 ++ doc/intprops.texi | 387 +++++++++++++++++++++++++++++++++++--------------- lib/intprops.h | 141 ++++++++++++++++-- tests/test-intprops.c | 333 +++++++++++++++++++++++++------------------ 5 files changed, 636 insertions(+), 267 deletions(-)
diff --git a/ChangeLog b/ChangeLog index 247bc4c..e83b3ce 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,37 @@ +2015-10-30 Paul Eggert <egg...@cs.ucla.edu> + + intprops: add WRAPV and const flavors for GCC 5 + If available, use GCC 5's builtin functions for efficient integer + overflow checking. Also, add macros like INT_ADD_WRAPV efficently + and safely compute the low-order bits of the correct answer. + A downside of these efficient functions is that they cannot be + used in constant expressions, so add macros like INT_CONST_ADD_OVERFLOW + and INT_CONST_ADD_WRAPV that can be used even in constant expressions. + * NEWS: Document the incompatible changes to INT_ADD_OVERFLOW etc. + * doc/intprops.texi (Integer Properties, Integer Type Overflow): + Document the changes. + (Wraparound Arithmetic): New section. + (Integer Range Overflow): + Put this subsection last, since it's least useful. + * lib/intprops.h (INT_CONST_ADD_OVERFLOW) + (INT_CONST_SUBTRACT_OVERFLOW, INT_CONST_MULTIPLY_OVERFLOW): + New macros, with the meaning that INT_ADD_OVERFLOW etc. used to have. + (INT_CONST_ADD_WRAPV, INT_CONST_SUBTRACT_WRAPV) + (INT_NEGATE_WRAPV, INT_CONST_MULTIPLY_WRAPV, INT_DIVIDE_WRAPV) + (INT_REMAINDER_WRAPV, _GL_INT_OP_WRAPV, _GL_EXPR_CAST) + (_GL_INT_OP_WRAPV_LONGISH, INT_ADD_WRAPV, INT_SUBTRACT_WRAPV) + (INT_MULTIPLY_WRAPV, _GL_OP_OVERFLOW, _GL_OP_WRAPV, _GL_OP_WRAPV_GENSYM): + New macros. + (INT_ADD_OVERFLOW, INT_SUBTRACT_OVERFLOW, INT_MULTIPLY_OVERFLOW): + Generate calls to GCC builtins if available, for speed. + * tests/test-intprops.c (INT_CONST_DIVIDE_OVERFLOW) + (INT_CONST_REMAINDER_OVERFLOW, INT_CONST_LEFT_SHIFT_OVERFLOW) + (INT_CONST_DIVIDE_WRAPV, INT_CONST_REMAINDER_WRAPV) + (INT_CONST_LEFT_SHIFT_WRAPV): New macros. + (main, CHECK_BINOP, CHECK_UNOP, CHECK_SUM, CHECK_PRODUCT) + (CHECK_QUOTIENT, CHECK_REMAINDER): + Test WRAPV and CONST flavors (when available) too. + 2015-10-30 Pádraig Brady <p...@draigbrady.com> doc: use extended timezone format in iso-8601 example diff --git a/NEWS b/NEWS index 122abf5..ffc26df 100644 --- a/NEWS +++ b/NEWS @@ -42,6 +42,14 @@ User visible incompatible changes Date Modules Changes +2015-10-30 intprops The macros INT_ADD_OVERFLOW, INT_SUBTRACT_OVERFLOW, + and INT_MULTIPLY_OVERFLOW are no longer constant + expressions even when their arguments are constants. + Use the new macros INT_CONST_ADD_OVERFLOW, + INT_CONST_SUBTRACT_OVERFLOW, and + INT_CONST_MULTIPLY_OVERFLOW if you need + overflow checking in constant expressions. + 2015-09-25 c-ctype The following macros were removed: C_CTYPE_CONSECUTIVE_DIGITS C_CTYPE_CONSECUTIVE_LOWERCASE diff --git a/doc/intprops.texi b/doc/intprops.texi index 8e1f9be..489bcb9 100644 --- a/doc/intprops.texi +++ b/doc/intprops.texi @@ -30,42 +30,39 @@ the resulting behavior is well-defined, but programs may still misbehave badly after overflow occurs. Many techniques have been proposed to attack these problems. These -include precondition testing, GCC's @option{-ftrapv} option, GCC's -no-undefined-overflow branch, the as-if infinitely ranged (AIR) model -implemented in Clang, saturation semantics where overflow reliably -yields an extreme value, the RICH static transformer to an -overflow-checking variant, and special testing methods. For more -information about these techniques, see: Dannenberg R, Dormann W, -Keaton D @emph{et al.}, -@url{http://www.sei.cmu.edu/library/abstracts/reports/10tn008.cfm, -As-if infinitely ranged integer model}, 2nd ed., Software Engineering -Institute Technical Note CMU/SEI-2010-TN-008, April 2010. - -Gnulib supports the precondition testing technique, as this is easy to -support portably. There are two families of precondition tests: the -first, for integer ranges, has a simple and straightforward implementation, -while the second, for integer types, is easier to use. +include precondition testing, wraparound behavior where signed integer +arithmetic is guaranteed to be modular, saturation semantics where +overflow reliably yields an extreme value, undefined behavior +sanitizers where overflow is guaranteed to trap, and various static +analysis techniques. + +Gnulib supports wraparound arithmetic and precondition testing, as +these are relatively easy to support portably and efficiently. There +are two families of precondition tests: the first, for integer types, +is easier to use, while the second, for integer ranges, has a simple +and straightforward portable implementation. @menu * Integer Type Determination:: Whether a type has integer properties. * Integer Bounds:: Bounds on integer values and representations. -* Integer Range Overflow:: Integer overflow checking if bounds are known. +* Wraparound Arithmetic:: Well-defined behavior on signed overflow. * Integer Type Overflow:: General integer overflow checking. +* Integer Range Overflow:: Integer overflow checking if bounds are known. @end menu @node Integer Type Determination @subsection Integer Type Determination @findex TYPE_IS_INTEGER -@code{TYPE_IS_INTEGER (@var{t})} expands to a constant +@code{TYPE_IS_INTEGER (@var{t})} is a constant expression that is 1 if the arithmetic type @var{t} is an integer type. @code{_Bool} counts as an integer type. @findex TYPE_SIGNED -@code{TYPE_SIGNED (@var{t})} expands to a constant expression +@code{TYPE_SIGNED (@var{t})} is a constant expression that is 1 if the arithmetic type @var{t} is a signed integer type or a floating type. If @var{t} is an integer type, @code{TYPE_SIGNED (@var{t})} -expands to an integer constant expression. +is an integer constant expression. Example usage: @@ -85,7 +82,7 @@ enum @cindex integer bounds @findex INT_BUFSIZE_BOUND -@code{INT_BUFSIZE_BOUND (@var{t})} expands to an integer constant +@code{INT_BUFSIZE_BOUND (@var{t})} is an integer constant expression that is a bound on the size of the string representing an integer type or expression @var{t} in decimal notation, including the terminating null character and any leading @code{-} character. For @@ -107,7 +104,7 @@ int_strlen (int i) @end example @findex INT_STRLEN_BOUND -@code{INT_STRLEN_BOUND (@var{t})} expands to an integer constant +@code{INT_STRLEN_BOUND (@var{t})} is an integer constant expression that is a bound on the length of the string representing an integer type or expression @var{t} in decimal notation, including any leading @code{-} character. This is one less than @@ -115,8 +112,8 @@ leading @code{-} character. This is one less than @findex TYPE_MINIMUM @findex TYPE_MAXIMUM -@code{TYPE_MINIMUM (@var{t})} and @code{TYPE_MAXIMUM (@var{t})} expand -to integer constant expressions equal to the minimum and maximum +@code{TYPE_MINIMUM (@var{t})} and @code{TYPE_MAXIMUM (@var{t})} are +integer constant expressions equal to the minimum and maximum values of the integer type @var{t}. These expressions are of the type @var{t} (or more precisely, the type @var{t} after integer promotions). @@ -134,6 +131,254 @@ in_off_t_range (intmax_t a) @} @end example +@node Wraparound Arithmetic +@subsection Wraparound Arithmetic with Signed Integers + +@cindex wraparound integer arithmetic + +Signed integer arithmetic has undefined behavior on overflow in C@. +Although almost all modern computers use two's complement signed +arithmetic that is well-defined to wrap around, C compilers routinely +optimize assuming that signed integer overflow cannot occur, which +means that a C program cannot easily get at the underlying machine +arithmetic. For example, on a typical machine with 32-bit two's +complement @code{int} the expression @code{INT_MAX + 1} does not +necessarily yield @code{INT_MIN}, because the compiler may do +calculations with a 64-bit register, or may generate code that +traps on signed integer overflow. + +The following macros work around this problem by yielding the +wraparound value, i.e., the low-order bits of the correct answer. For +example, @code{INT_ADD_WRAPV (INT_MAX, 1)} reliably yields +@code{INT_MIN} on a two's complement machine. You can also use +overflow-checking macros to check whether wraparound occurred. +@xref{Integer Type Overflow}. + +@noindent +These macros have the following restrictions: + +@itemize @bullet +@item +Their arguments must be integer expressions. + +@item +They may evaluate their arguments zero or multiple times, so the +arguments should not have side effects. + +@item +On non-GCC-compatible compilers that do not support C11, the type of +@code{INT_ADD_WRAPV (@var{a}, @var{b})} might differ from the native +type of @code{@var{a} + @var{b}}, so it is wise to convert the result +to the native type. Such a conversion is safe and cannot trap. This +issue applies to all the @code{_WRAP} macros. +@end itemize + +These macros are tuned for their last argument being a constant. + +@table @code +@item INT_ADD_WRAP (@var{a}, @var{b}) +@findex INT_ADD_WRAP +Return the low-order bits of @code{@var{a} + @var{b}}. See above for +restrictions. + +@item INT_CONST_ADD_WRAP (@var{a}, @var{b}) +@findex INT_CONST_ADD_WRAP +Return the low-order bits of @code{@var{a} + @var{b}}. See above for +restrictions. This macro differs from @code{INT_ADD_WRAP} in that +although its implementation is typically slower, it is an integer +constant expression if its arguments are. + +@item INT_SUBTRACT_WRAP (@var{a}, @var{b}) +@findex INT_SUBTRACT_WRAP +Return the low-order bits of @code{@var{a} - @var{b}}. See above for +restrictions. + +@item INT_CONST_SUBTRACT_WRAP (@var{a}, @var{b}) +@findex INT_CONST_SUBTRACT_WRAP +Return the low-order bits of @code{@var{a} - @var{b}}. See above for +restrictions. This macro differs from @code{INT_SUBTRACT_WRAP} in +that although its implementation is typically slower, it is an integer +constant expression if its arguments are. + +@item INT_NEGATE_WRAP (@var{a}) +@findex INT_NEGATE_WRAP +Return the low-order bits of @code{-@var{a}}. See above for restrictions. +This macro is an integer constant expression if its arguments are. + +@item INT_MULTIPLY_WRAP (@var{a}, @var{b}) +@findex INT_MULTIPLY_WRAP +Return the low-order bits of @code{@var{a} * @var{b}}. See above for +restrictions. + +@item INT_CONST_MULTIPLY_WRAP (@var{a}, @var{b}) +@findex INT_CONST_MULTIPLY_WRAP +Return the low-order bits of @code{@var{a} * @var{b}}. See above for +restrictions. This macro differs from @code{INT_MULTIPLY_WRAP} in +that although its implementation is typically slower, it is an integer +constant expression if its arguments are. + +@item INT_DIVIDE_WRAP (@var{a}, @var{b}) +@findex INT_DIVIDE_WRAP +Return the low-order bits of @code{@var{a} / @var{b}}. See above for +restrictions. This macro does not check for division by zero. This +macro is an integer constant expression if its arguments are. + +@item INT_REMAINDER_WRAP (@var{a}, @var{b}) +@findex INT_REMAINDER_WRAP +Return the low-order bits of @code{@var{a} % @var{b}}. See above for +restrictions. This macro does not check for division by zero. This +macro is an integer constant expression if its arguments are. + +@item INT_LEFT_SHIFT_WRAP (@var{a}, @var{b}) +@findex INT_LEFT_SHIFT_WRAP +Return the low-order bits of @code{@var{a} << @var{b}}. See above for +restrictions. The C standard says that behavior is undefined for +shifts unless 0@leq{}@var{b}<@var{w} where @var{w} is @var{a}'s word +width, and that when @var{a} is negative then @code{@var{a} << +@var{b}} has undefined behavior, but this macro does not check these +other restrictions. This macro is an integer constant expression if +its arguments are. +@end table + +@node Integer Type Overflow +@subsection Integer Type Overflow + +@cindex integer type overflow +@cindex overflow, integer type + +Although unsigned integer arithmetic wraps around modulo a power of +two, signed integer arithmetic has undefined behavior on overflow in +C@. Almost all modern computers use two's complement signed +arithmetic that is well-defined to wrap around, but C compilers +routinely optimize based on the assumption that signed integer +overflow cannot occur, which means that a C program cannot easily get +at the underlying machine behavior. For example, the signed integer +expression @code{(a + b < b) != (a < 0)} is not a reliable test for +whether @code{a + b} overflows, because a compiler can assume that +signed overflow cannot occur and treat the entire expression as if it +were false. + +These macros yield 1 if the corresponding C operators might not yield +numerically correct answers due to arithmetic overflow of an integer +type. They work correctly on all known practical hosts, and do not +rely on undefined behavior due to signed arithmetic overflow. They +are typically easier to use than the integer range overflow macros +(@pxref{Integer Range Overflow}). + +Example usages: + +@example +#include <intprops.h> +#include <limits.h> + +/* Print the low order bits of A * B, + reporting whether overflow occurred. + When optimized this code typically + multiplies A and B only once. */ +void +print_product (long int a, long int b) +@{ + long int result = INT_MULTIPLY_WRAPV (a, b); + printf ("result is %ld (%s)\n", result, + (INT_MULTIPLY_OVERFLOW (a, b) + ? "after overflow" + : "no overflow")); +@} + +/* Does the product of two ints always fit + in a long int? */ +enum @{ + INT_PRODUCTS_FIT_IN_LONG + = ! (INT_CONST_MULTIPLY_OVERFLOW + ((long int) INT_MIN, INT_MIN)) +@}; +@end example + +@noindent +These macros have the following restrictions: + +@itemize @bullet +@item +Their arguments must be integer expressions. + +@item +They may evaluate their arguments zero or multiple times, so the +arguments should not have side effects. +@end itemize + +These macros are tuned for their last argument being a constant. + +@table @code +@item INT_ADD_OVERFLOW (@var{a}, @var{b}) +@findex INT_ADD_OVERFLOW +Yield 1 if @code{@var{a} + @var{b}} would overflow. See above for +restrictions. + +@item INT_CONST_ADD_OVERFLOW (@var{a}, @var{b}) +@findex INT_CONST_ADD_OVERFLOW +Yield 1 if @code{@var{a} + @var{b}} would overflow. See above for +restrictions. This macro differs from @code{INT_ADD_OVERFLOW} in that +although its implementation is typically slower, it is an integer +constant expression if its arguments are. + +@item INT_SUBTRACT_OVERFLOW (@var{a}, @var{b}) +@findex INT_SUBTRACT_OVERFLOW +Yield 1 if @code{@var{a} - @var{b}} would overflow. See above for +restrictions. + +@item INT_CONST_SUBTRACT_OVERFLOW (@var{a}, @var{b}) +@findex INT_CONST_SUBTRACT_OVERFLOW +Yield 1 if @code{@var{a} - @var{b}} would overflow. See above for +restrictions. This macro differs from @code{INT_SUBTRACT_OVERFLOW} in +that although its implementation is typically slower, it is an integer +constant expression if its arguments are. + +@item INT_NEGATE_OVERFLOW (@var{a}) +@findex INT_NEGATE_OVERFLOW +Yields 1 if @code{-@var{a}} would overflow. See above for restrictions. +This macro is an integer constant expression if its arguments are. + +@item INT_MULTIPLY_OVERFLOW (@var{a}, @var{b}) +@findex INT_MULTIPLY_OVERFLOW +Yield 1 if @code{@var{a} * @var{b}} would overflow. See above for +restrictions. + +@item INT_CONST_MULTIPLY_OVERFLOW (@var{a}, @var{b}) +@findex INT_CONST_MULTIPLY_OVERFLOW +Yield 1 if @code{@var{a} * @var{b}} would overflow. See above for +restrictions. This macro differs from @code{INT_SUBTRACT_OVERFLOW} in +that although its implementation is typically slower, it is an integer +constant expression if its arguments are. + +@item INT_DIVIDE_OVERFLOW (@var{a}, @var{b}) +@findex INT_DIVIDE_OVERFLOW +Yields 1 if @code{@var{a} / @var{b}} would overflow. See above for +restrictions. Division overflow can happen on two's complement hosts +when dividing the most negative integer by @minus{}1. This macro does +not check for division by zero. This macro is an integer constant +expression if its arguments are. + +@item INT_REMAINDER_OVERFLOW (@var{a}, @var{b}) +@findex INT_REMAINDER_OVERFLOW +Yield 1 if @code{@var{a} % @var{b}} would overflow. See above for +restrictions. Remainder overflow can happen on two's complement hosts +when dividing the most negative integer by @minus{}1; although the +mathematical result is always 0, in practice some implementations +trap, so this counts as an overflow. This macro does not check for +division by zero. This macro is an integer constant expression if its +arguments are. + +@item INT_LEFT_SHIFT_OVERFLOW (@var{a}, @var{b}) +@findex INT_LEFT_SHIFT_OVERFLOW +Yield 1 if @code{@var{a} << @var{b}} would overflow. See above for +restrictions. The C standard says that behavior is undefined for +shifts unless 0@leq{}@var{b}<@var{w} where @var{w} is @var{a}'s word +width, and that when @var{a} is negative then @code{@var{a} << +@var{b}} has undefined behavior, but this macro does not check these +other restrictions. This macro is an integer constant expression if +its arguments are. +@end table + @node Integer Range Overflow @subsection Integer Range Overflow @@ -142,7 +387,7 @@ in_off_t_range (intmax_t a) These macros yield 1 if the corresponding C operators might not yield numerically correct answers due to arithmetic overflow. They do not -rely on undefined or implementation-defined behavior. They expand to +rely on undefined or implementation-defined behavior. They are integer constant expressions if their arguments are. Their implementations are simple and straightforward, but they are typically harder to use than the integer type overflow macros. @xref{Integer @@ -242,96 +487,6 @@ Here, @var{min} and @var{max} are for @var{a} only, and @var{b} need not be of the same type as the other arguments. The C standard says that behavior is undefined for shifts unless 0@leq{}@var{b}<@var{w} where @var{w} is @var{a}'s word width, and that when @var{a} is negative -then @code{@var{a} << @var{b}} has undefined behavior and -@code{@var{a} >> @var{b}} has implementation-defined behavior, but -this macro does not check these other restrictions. -@end table - -@node Integer Type Overflow -@subsection Integer Type Overflow - -@cindex integer type overflow -@cindex overflow, integer type - -These macros yield 1 if the corresponding C operators might not yield -numerically correct answers due to arithmetic overflow of an integer -type. They work correctly on all known practical hosts, and do not -rely on undefined behavior due to signed arithmetic overflow. They -expand to integer constant expressions if their arguments are. They -are easier to use than the integer range overflow macros -(@pxref{Integer Range Overflow}). - -Example usage: - -@example -#include <intprops.h> -void -print_product (long int a, long int b) -@{ - if (INT_MULTIPLY_OVERFLOW (a, b)) - printf ("multiply would overflow"); - else - printf ("product is %ld", a * b); -@} -@end example - -@noindent -These macros have the following restrictions: - -@itemize @bullet -@item -Their arguments must be integer expressions. - -@item -They may evaluate their arguments zero or multiple times, so the -arguments should not have side effects. -@end itemize - -These macros are tuned for their last argument being a constant. - -@table @code -@item INT_ADD_OVERFLOW (@var{a}, @var{b}) -@findex INT_ADD_OVERFLOW -Yield 1 if @code{@var{a} + @var{b}} would overflow. See above for -restrictions. - -@item INT_SUBTRACT_OVERFLOW (@var{a}, @var{b}) -@findex INT_SUBTRACT_OVERFLOW -Yield 1 if @code{@var{a} - @var{b}} would overflow. See above for -restrictions. - -@item INT_NEGATE_OVERFLOW (@var{a}) -@findex INT_NEGATE_OVERFLOW -Yields 1 if @code{-@var{a}} would overflow. See above for restrictions. - -@item INT_MULTIPLY_OVERFLOW (@var{a}, @var{b}) -@findex INT_MULTIPLY_OVERFLOW -Yield 1 if @code{@var{a} * @var{b}} would overflow. See above for -restrictions. - -@item INT_DIVIDE_OVERFLOW (@var{a}, @var{b}) -@findex INT_DIVIDE_OVERFLOW -Yields 1 if @code{@var{a} / @var{b}} would overflow. See above for -restrictions. Division overflow can happen on two's complement hosts -when dividing the most negative integer by @minus{}1. This macro does -not check for division by zero. - -@item INT_REMAINDER_OVERFLOW (@var{a}, @var{b}) -@findex INT_REMAINDER_OVERFLOW -Yield 1 if @code{@var{a} % @var{b}} would overflow. See above for -restrictions. Remainder overflow can happen on two's complement hosts -when dividing the most negative integer by @minus{}1; although the -mathematical result is always 0, in practice some implementations -trap, so this counts as an overflow. This macro does not check for -division by zero. - -@item INT_LEFT_SHIFT_OVERFLOW (@var{a}, @var{b}) -@findex INT_LEFT_SHIFT_OVERFLOW -Yield 1 if @code{@var{a} << @var{b}} would overflow. See above for -restrictions. The C standard says that behavior is undefined for -shifts unless 0@leq{}@var{b}<@var{w} where @var{w} is @var{a}'s word -width, and that when @var{a} is negative then @code{@var{a} << -@var{b}} has undefined behavior and @code{@var{a} >> @var{b}} has -implementation-defined behavior, but this macro does not check these -other restrictions. +then @code{@var{a} << @var{b}} has undefined behavior, but this macro +does not check these other restrictions. @end table diff --git a/lib/intprops.h b/lib/intprops.h index f85ccad..4441f1c 100644 --- a/lib/intprops.h +++ b/lib/intprops.h @@ -263,22 +263,31 @@ : (a) % - (b)) \ == 0) - -/* Integer overflow checks. +/* Check for integer overflow, and report low order bits of answer. The INT_<op>_OVERFLOW macros return 1 if the corresponding C operators might not yield numerically correct answers due to arithmetic overflow. - They work correctly on all known practical hosts, and do not rely + The INT_<op>_WRAPV macros return the low-order bits of the answer. + For example, INT_ADD_WRAPV (INT_MAX, 1) returns INT_MIN on a two's + complement host, even if INT_MAX + 1 would trap. + + These macros work correctly on all known practical hosts, and do not rely on undefined behavior due to signed arithmetic overflow. Example usage: - long int i = ...; - long int j = ...; - if (INT_MULTIPLY_OVERFLOW (i, j)) - printf ("multiply would overflow"); - else - printf ("product is %ld", i * j); + long int a = ...; + long int b = ...; + long int result = INT_MULTIPLY_WRAPV (a, b); + printf ("result is %ld (%s)\n", result, + INT_MULTIPLY_OVERFLOW (a, b) ? "after overflow" : "no overflow"); + + enum { + INT_PRODUCTS_FIT_IN_LONG + = ! INT_CONST_MULTIPLY_OVERFLOW ((long int) INT_MIN, INT_MIN) + }; + + Restrictions on these macros: These macros do not check for all possible numerical problems or undefined or unspecified behavior: they do not check for division @@ -287,18 +296,35 @@ These macros may evaluate their arguments zero or multiple times, so the arguments should not have side effects. + On non-GCC-compatible compilers that do not support C11, the type + of INT_<op>_WRAPV (A, B) might differ from the native type of (A op + B), so it is wise to convert the result to the native type. Such a + conversion is safe and cannot trap. + + For runtime efficiency GCC 5 and later has builtin functions for +, + -, * when doing integer overflow checking or wraparound arithmetic. + Unfortunately, these builtins require nonnull pointer arguments and + so cannot be used in constant expressions; see GCC bug 68120 + <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68120>. In constant + expressions, use the macros INT_CONST_ADD_OVERFLOW and + INT_CONST_ADD_WRAPV instead, and similarly for SUBTRACT and + MULTIPLY; these macros avoid the builtins and are slower in + non-constant expressions. Perhaps someday GCC's API for overflow + checking will be improved and we can remove the need for the + INT_CONST_ variants. + These macros are tuned for their last argument being a constant. Return 1 if the integer expressions A * B, A - B, -A, A * B, A / B, A % B, and A << B would overflow, respectively. */ -#define INT_ADD_OVERFLOW(a, b) \ +#define INT_CONST_ADD_OVERFLOW(a, b) \ _GL_BINARY_OP_OVERFLOW (a, b, _GL_ADD_OVERFLOW) -#define INT_SUBTRACT_OVERFLOW(a, b) \ +#define INT_CONST_SUBTRACT_OVERFLOW(a, b) \ _GL_BINARY_OP_OVERFLOW (a, b, _GL_SUBTRACT_OVERFLOW) #define INT_NEGATE_OVERFLOW(a) \ INT_NEGATE_RANGE_OVERFLOW (a, _GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a)) -#define INT_MULTIPLY_OVERFLOW(a, b) \ +#define INT_CONST_MULTIPLY_OVERFLOW(a, b) \ _GL_BINARY_OP_OVERFLOW (a, b, _GL_MULTIPLY_OVERFLOW) #define INT_DIVIDE_OVERFLOW(a, b) \ _GL_BINARY_OP_OVERFLOW (a, b, _GL_DIVIDE_OVERFLOW) @@ -317,4 +343,95 @@ _GL_INT_MINIMUM (0 * (b) + (a)), \ _GL_INT_MAXIMUM (0 * (b) + (a))) +/* Return the low order bits of the integer expressions + A * B, A - B, -A, A * B, A / B, A % B, and A << B, respectively. + See above for restrictions. */ +#define INT_CONST_ADD_WRAPV(a, b) _GL_INT_OP_WRAPV (a, b, +) +#define INT_CONST_SUBTRACT_WRAPV(a, b) _GL_INT_OP_WRAPV (a, b, -) +#define INT_NEGATE_WRAPV(a) INT_CONST_SUBTRACT_WRAPV (0, a) +#define INT_CONST_MULTIPLY_WRAPV(a, b) _GL_INT_OP_WRAPV (a, b, *) +#define INT_DIVIDE_WRAPV(a, b) \ + (INT_DIVIDE_OVERFLOW(a, b) ? INT_NEGATE_WRAPV (a) : (a) / (b)) +#define INT_REMAINDER_WRAPV(a, b) \ + (INT_REMAINDER_OVERFLOW(a, b) ? 0 : (a) % (b)) +#define INT_LEFT_SHIFT_WRAPV(a, b) _GL_INT_OP_WRAPV (a, b, <<) + +/* Return the low order bits of A <op> B, where OP specifies the operation. + See above for restrictions. */ +#if !_GL_HAVE___TYPEOF__ && 201112 <= __STDC_VERSION__ +# define _GL_INT_OP_WRAPV(a, b, op) \ + _Generic ((a) op (b), \ + int: _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, int), \ + long int: _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, long int), \ + long long int: _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, \ + long long int), \ + default: (a) op (b)) +#else +# define _GL_INT_OP_WRAPV(a, b, op) \ + (! _GL_INT_SIGNED ((0 * (a)) op (0 * (b))) \ + ? ((a) op (b)) \ + : _GL_EXPR_CAST ((a) op (b), \ + (sizeof ((a) op (b)) <= sizeof (int) \ + ? _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, int) \ + : _GL_INT_OP_WRAPV_LONGISH (a, b, op)))) + +/* Cast to E's type the value of V if possible. Yield V as-is otherwise. */ +# if _GL_HAVE___TYPEOF__ +# define _GL_EXPR_CAST(e, v) ((__typeof__ (e)) (v)) +# else +# define _GL_EXPR_CAST(e, v) (v) +# endif + +# ifdef LLONG_MAX +# define _GL_INT_OP_WRAPV_LONGISH(a, b, op) \ + (sizeof ((a) op (b)) <= sizeof (long int) \ + ? _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, long int) \ + : _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, long long int)) +# else +# define _GL_INT_OP_WRAPV_LONGISH(a, b, op) \ + _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, long int) +# endif +#endif + +/* Return A <op> B, where the operation is given by OP and the result + type is T. T is a signed integer type that is at least as wide as int. + Do arithmetic using 'unsigned T' to avoid signed integer overflow. + Subtract TYPE_MINIMUM (T) before converting back to T, and add it + back afterwards, to avoid signed overflow during conversion. */ +#define _GL_INT_OP_WRAPV_VIA_UNSIGNED(a, b, op, t) \ + ((unsigned t) (a) op (unsigned t) (b) <= TYPE_MAXIMUM (t) \ + ? (t) ((unsigned t) (a) op (unsigned t) (b)) \ + : ((t) ((unsigned t) (a) op (unsigned t) (b) - TYPE_MINIMUM (t)) \ + + TYPE_MINIMUM (t))) + +/* Calls to the INT_<op>_<result> macros are like their INT_CONST_<op>_<result> + counterparts, except they are faster with GCC 5 or later, and they + are not constant expressions due to limitations in the GNU C API. */ + +#define INT_ADD_OVERFLOW(a, b) \ + _GL_OP_OVERFLOW (a, b, INT_CONST_ADD_OVERFLOW, __builtin_add_overflow) +#define INT_SUBTRACT_OVERFLOW(a, b) \ + _GL_OP_OVERFLOW (a, b, INT_CONST_SUBTRACT_OVERFLOW, __builtin_sub_overflow) +#define INT_MULTIPLY_OVERFLOW(a, b) \ + _GL_OP_OVERFLOW (a, b, INT_CONST_MULTIPLY_OVERFLOW, __builtin_mul_overflow) + +#define INT_ADD_WRAPV(a, b) \ + _GL_OP_WRAPV (a, b, INT_CONST_ADD_WRAPV, __builtin_add_overflow) +#define INT_SUBTRACT_WRAPV(a, b) \ + _GL_OP_WRAPV (a, b, INT_CONST_SUBTRACT_WRAPV, __builtin_sub_overflow) +#define INT_MULTIPLY_WRAPV(a, b) \ + _GL_OP_WRAPV (a, b, INT_CONST_MULTIPLY_WRAPV, __builtin_mul_overflow) + +#if __GNUC__ < 5 +# define _GL_OP_OVERFLOW(a, b, portable, builtin) portable (a, b) +# define _GL_OP_WRAPV(a, b, portable, builtin) portable (a, b) +#else +# define _GL_OP_OVERFLOW(a, b, portable, builtin) \ + builtin (a, b, &(__typeof__ ((a) + (b))) {0}) +# define _GL_OP_WRAPV(a, b, portable, builtin) \ + _GL_OP_WRAPV_GENSYM(a, b, builtin, __gl_wrapv##__COUNTER__) +# define _GL_OP_WRAPV_GENSYM(a, b, builtin, r) \ + ({__typeof__ ((a) + (b)) r; builtin (a, b, &r); r; }) +#endif + #endif /* _GL_INTPROPS_H */ diff --git a/tests/test-intprops.c b/tests/test-intprops.c index 06df5a7..25b9126 100644 --- a/tests/test-intprops.c +++ b/tests/test-intprops.c @@ -32,6 +32,16 @@ #include "macros.h" +/* Create these CONST macros as alias for the standard ones, as some + of the generic code below assumes each binary operator has a CONST + alternative. */ +#define INT_CONST_DIVIDE_OVERFLOW(a, b) INT_DIVIDE_OVERFLOW (a, b) +#define INT_CONST_REMAINDER_OVERFLOW(a, b) INT_REMAINDER_OVERFLOW (a, b) +#define INT_CONST_LEFT_SHIFT_OVERFLOW(a, b) INT_LEFT_SHIFT_OVERFLOW (a, b) +#define INT_CONST_DIVIDE_WRAPV(a, b) INT_DIVIDE_WRAPV (a, b) +#define INT_CONST_REMAINDER_WRAPV(a, b) INT_REMAINDER_WRAPV (a, b) +#define INT_CONST_LEFT_SHIFT_WRAPV(a, b) INT_LEFT_SHIFT_WRAPV (a, b) + /* VERIFY (X) uses a static assertion for compilers that are known to work, and falls back on a dynamic assertion for other compilers. These tests should be checkable via 'verify' rather than 'ASSERT', but @@ -43,6 +53,8 @@ # define VERIFY(x) ASSERT (x) #endif +#define DONTCARE __LINE__ + int main (void) { @@ -128,148 +140,191 @@ main (void) #endif /* All the INT_<op>_RANGE_OVERFLOW tests are equally valid as - INT_<op>_OVERFLOW tests, so define a single macro to do both. */ - #define CHECK_BINOP(op, a, b, min, max, overflow) \ - (INT_##op##_RANGE_OVERFLOW (a, b, min, max) == (overflow) \ - && INT_##op##_OVERFLOW (a, b) == (overflow)) - #define CHECK_UNOP(op, a, min, max, overflow) \ - (INT_##op##_RANGE_OVERFLOW (a, min, max) == (overflow) \ - && INT_##op##_OVERFLOW (a) == (overflow)) + INT_<op>_OVERFLOW tests, so define a single macro to do both. + OP is the operation, A and B its operands, T the result type, + V the overflow flag, and VRES the result if V. If overflow + occurs, assumes two's complement; that's good enough for + tests. */ + #define CHECK_BINOP(op, opname, a, b, t, v, vres) \ + VERIFY (INT_##opname##_RANGE_OVERFLOW (a, b, TYPE_MINIMUM (t), \ + TYPE_MAXIMUM (t)) \ + == (v)); \ + ASSERT (INT_##opname##_OVERFLOW (a, b) == (v)); \ + VERIFY (INT_CONST_##opname##_OVERFLOW (a, b) == (v)); \ + VERIFY (((t) INT_CONST_##opname##_WRAPV (a, b) \ + == ((v) ? (vres) : ((a) op (b)))) \ + || ((v) && TYPE_SIGNED (t) && !TYPE_TWOS_COMPLEMENT (t))); \ + ASSERT (INT_##opname##_WRAPV (a, b) == INT_CONST_##opname##_WRAPV (a, b)) + #define CHECK_UNOP(op, opname, a, t, v, vres) \ + VERIFY (INT_##opname##_RANGE_OVERFLOW (a, TYPE_MINIMUM (t), \ + TYPE_MAXIMUM (t)) \ + == (v)); \ + VERIFY (INT_##opname##_OVERFLOW (a) == (v)); \ + VERIFY ((t) INT_##opname##_WRAPV (a) == ((v) ? (vres) : (op (a))) \ + || ((v) && TYPE_SIGNED (t) && !TYPE_TWOS_COMPLEMENT (t))) /* INT_<op>_RANGE_OVERFLOW, INT_<op>_OVERFLOW. */ VERIFY (INT_ADD_RANGE_OVERFLOW (INT_MAX, 1, INT_MIN, INT_MAX)); - VERIFY (INT_ADD_OVERFLOW (INT_MAX, 1)); - VERIFY (CHECK_BINOP (ADD, INT_MAX, 1, INT_MIN, INT_MAX, true)); - VERIFY (CHECK_BINOP (ADD, INT_MAX, -1, INT_MIN, INT_MAX, false)); - VERIFY (CHECK_BINOP (ADD, INT_MIN, 1, INT_MIN, INT_MAX, false)); - VERIFY (CHECK_BINOP (ADD, INT_MIN, -1, INT_MIN, INT_MAX, true)); - VERIFY (CHECK_BINOP (ADD, UINT_MAX, 1u, 0u, UINT_MAX, true)); - VERIFY (CHECK_BINOP (ADD, 0u, 1u, 0u, UINT_MAX, false)); - - VERIFY (CHECK_BINOP (SUBTRACT, INT_MAX, 1, INT_MIN, INT_MAX, false)); - VERIFY (CHECK_BINOP (SUBTRACT, INT_MAX, -1, INT_MIN, INT_MAX, true)); - VERIFY (CHECK_BINOP (SUBTRACT, INT_MIN, 1, INT_MIN, INT_MAX, true)); - VERIFY (CHECK_BINOP (SUBTRACT, INT_MIN, -1, INT_MIN, INT_MAX, false)); - VERIFY (CHECK_BINOP (SUBTRACT, UINT_MAX, 1u, 0u, UINT_MAX, false)); - VERIFY (CHECK_BINOP (SUBTRACT, 0u, 1u, 0u, UINT_MAX, true)); - - VERIFY (CHECK_UNOP (NEGATE, INT_MIN, INT_MIN, INT_MAX, - TYPE_TWOS_COMPLEMENT (int))); - VERIFY (CHECK_UNOP (NEGATE, 0, INT_MIN, INT_MAX, false)); - VERIFY (CHECK_UNOP (NEGATE, INT_MAX, INT_MIN, INT_MAX, false)); - VERIFY (CHECK_UNOP (NEGATE, 0u, 0u, UINT_MAX, false)); - VERIFY (CHECK_UNOP (NEGATE, 1u, 0u, UINT_MAX, true)); - VERIFY (CHECK_UNOP (NEGATE, UINT_MAX, 0u, UINT_MAX, true)); - - VERIFY (CHECK_BINOP (MULTIPLY, INT_MAX, INT_MAX, INT_MIN, INT_MAX, true)); - VERIFY (CHECK_BINOP (MULTIPLY, INT_MAX, INT_MIN, INT_MIN, INT_MAX, true)); - VERIFY (CHECK_BINOP (MULTIPLY, INT_MIN, INT_MAX, INT_MIN, INT_MAX, true)); - VERIFY (CHECK_BINOP (MULTIPLY, INT_MIN, INT_MIN, INT_MIN, INT_MAX, true)); - VERIFY (CHECK_BINOP (MULTIPLY, -1, INT_MIN, INT_MIN, INT_MAX, - INT_NEGATE_OVERFLOW (INT_MIN))); - VERIFY (CHECK_BINOP (MULTIPLY, LONG_MIN / INT_MAX, (long int) INT_MAX, - LONG_MIN, LONG_MIN, false)); - - VERIFY (CHECK_BINOP (DIVIDE, INT_MIN, -1, INT_MIN, INT_MAX, - INT_NEGATE_OVERFLOW (INT_MIN))); - VERIFY (CHECK_BINOP (DIVIDE, INT_MAX, 1, INT_MIN, INT_MAX, false)); - VERIFY (CHECK_BINOP (DIVIDE, (unsigned int) INT_MIN, - -1u, 0u, UINT_MAX, false)); - - VERIFY (CHECK_BINOP (REMAINDER, INT_MIN, -1, INT_MIN, INT_MAX, - INT_NEGATE_OVERFLOW (INT_MIN))); - VERIFY (CHECK_BINOP (REMAINDER, INT_MAX, 1, INT_MIN, INT_MAX, false)); - VERIFY (CHECK_BINOP (REMAINDER, (unsigned int) INT_MIN, - -1u, 0u, UINT_MAX, false)); - - VERIFY (CHECK_BINOP (LEFT_SHIFT, UINT_MAX, 1, 0u, UINT_MAX, true)); - VERIFY (CHECK_BINOP (LEFT_SHIFT, UINT_MAX / 2 + 1, 1, 0u, UINT_MAX, true)); - VERIFY (CHECK_BINOP (LEFT_SHIFT, UINT_MAX / 2, 1, 0u, UINT_MAX, false)); - - /* INT_<op>_OVERFLOW with mixed types. */ - #define CHECK_SUM(a, b, overflow) \ - VERIFY (INT_ADD_OVERFLOW (a, b) == (overflow)); \ - VERIFY (INT_ADD_OVERFLOW (b, a) == (overflow)) - CHECK_SUM (-1, LONG_MIN, true); - CHECK_SUM (-1, UINT_MAX, false); - CHECK_SUM (-1L, INT_MIN, INT_MIN == LONG_MIN); - CHECK_SUM (0u, -1, true); - CHECK_SUM (0u, 0, false); - CHECK_SUM (0u, 1, false); - CHECK_SUM (1, LONG_MAX, true); - CHECK_SUM (1, UINT_MAX, true); - CHECK_SUM (1L, INT_MAX, INT_MAX == LONG_MAX); - CHECK_SUM (1u, INT_MAX, INT_MAX == UINT_MAX); - CHECK_SUM (1u, INT_MIN, true); - - VERIFY (! INT_SUBTRACT_OVERFLOW (INT_MAX, 1u)); - VERIFY (! INT_SUBTRACT_OVERFLOW (UINT_MAX, 1)); - VERIFY (! INT_SUBTRACT_OVERFLOW (0u, -1)); - VERIFY (INT_SUBTRACT_OVERFLOW (UINT_MAX, -1)); - VERIFY (INT_SUBTRACT_OVERFLOW (INT_MIN, 1u)); - VERIFY (INT_SUBTRACT_OVERFLOW (-1, 0u)); - - #define CHECK_PRODUCT(a, b, overflow) \ - VERIFY (INT_MULTIPLY_OVERFLOW (a, b) == (overflow)); \ - VERIFY (INT_MULTIPLY_OVERFLOW (b, a) == (overflow)) - - CHECK_PRODUCT (-1, 1u, true); - CHECK_PRODUCT (-1, INT_MIN, INT_NEGATE_OVERFLOW (INT_MIN)); - CHECK_PRODUCT (-1, UINT_MAX, true); - CHECK_PRODUCT (-12345, LONG_MAX / -12345 - 1, true); - CHECK_PRODUCT (-12345, LONG_MAX / -12345, false); - CHECK_PRODUCT (0, -1, false); - CHECK_PRODUCT (0, 0, false); - CHECK_PRODUCT (0, 0u, false); - CHECK_PRODUCT (0, 1, false); - CHECK_PRODUCT (0, INT_MAX, false); - CHECK_PRODUCT (0, INT_MIN, false); - CHECK_PRODUCT (0, UINT_MAX, false); - CHECK_PRODUCT (0u, -1, false); - CHECK_PRODUCT (0u, 0, false); - CHECK_PRODUCT (0u, 0u, false); - CHECK_PRODUCT (0u, 1, false); - CHECK_PRODUCT (0u, INT_MAX, false); - CHECK_PRODUCT (0u, INT_MIN, false); - CHECK_PRODUCT (0u, UINT_MAX, false); - CHECK_PRODUCT (1, INT_MAX, false); - CHECK_PRODUCT (1, INT_MIN, false); - CHECK_PRODUCT (1, UINT_MAX, false); - CHECK_PRODUCT (1u, INT_MIN, true); - CHECK_PRODUCT (1u, INT_MAX, UINT_MAX < INT_MAX); - CHECK_PRODUCT (INT_MAX, UINT_MAX, true); - CHECK_PRODUCT (INT_MAX, ULONG_MAX, true); - CHECK_PRODUCT (INT_MIN, LONG_MAX / INT_MIN - 1, true); - CHECK_PRODUCT (INT_MIN, LONG_MAX / INT_MIN, false); - CHECK_PRODUCT (INT_MIN, UINT_MAX, true); - CHECK_PRODUCT (INT_MIN, ULONG_MAX, true); - - VERIFY (INT_DIVIDE_OVERFLOW (INT_MIN, -1L) - == (TYPE_TWOS_COMPLEMENT (long int) && INT_MIN == LONG_MIN)); - VERIFY (! INT_DIVIDE_OVERFLOW (INT_MIN, UINT_MAX)); - VERIFY (! INT_DIVIDE_OVERFLOW (INTMAX_MIN, UINTMAX_MAX)); - VERIFY (! INT_DIVIDE_OVERFLOW (INTMAX_MIN, UINT_MAX)); - VERIFY (INT_DIVIDE_OVERFLOW (-11, 10u)); - VERIFY (INT_DIVIDE_OVERFLOW (-10, 10u)); - VERIFY (! INT_DIVIDE_OVERFLOW (-9, 10u)); - VERIFY (INT_DIVIDE_OVERFLOW (11u, -10)); - VERIFY (INT_DIVIDE_OVERFLOW (10u, -10)); - VERIFY (! INT_DIVIDE_OVERFLOW (9u, -10)); - - VERIFY (INT_REMAINDER_OVERFLOW (INT_MIN, -1L) - == (TYPE_TWOS_COMPLEMENT (long int) && INT_MIN == LONG_MIN)); - VERIFY (INT_REMAINDER_OVERFLOW (-1, UINT_MAX)); - VERIFY (INT_REMAINDER_OVERFLOW ((intmax_t) -1, UINTMAX_MAX)); - VERIFY (INT_REMAINDER_OVERFLOW (INTMAX_MIN, UINT_MAX) - == (INTMAX_MAX < UINT_MAX - && - (unsigned int) INTMAX_MIN % UINT_MAX != 0)); - VERIFY (INT_REMAINDER_OVERFLOW (INT_MIN, ULONG_MAX) - == (INT_MIN % ULONG_MAX != 1)); - VERIFY (! INT_REMAINDER_OVERFLOW (1u, -1)); - VERIFY (! INT_REMAINDER_OVERFLOW (37*39u, -39)); - VERIFY (INT_REMAINDER_OVERFLOW (37*39u + 1, -39)); - VERIFY (INT_REMAINDER_OVERFLOW (37*39u - 1, -39)); - VERIFY (! INT_REMAINDER_OVERFLOW (LONG_MAX, -INT_MAX)); + VERIFY (INT_CONST_ADD_OVERFLOW (INT_MAX, 1)); + CHECK_BINOP (+, ADD, INT_MAX, 1, int, true, INT_MIN); + CHECK_BINOP (+, ADD, INT_MAX, -1, int, false, INT_MAX - 1); + CHECK_BINOP (+, ADD, INT_MIN, 1, int, false, INT_MIN + 1); + CHECK_BINOP (+, ADD, INT_MIN, -1, int, true, INT_MAX); + CHECK_BINOP (+, ADD, UINT_MAX, 1u, unsigned int, true, 0u); + CHECK_BINOP (+, ADD, 0u, 1u, unsigned int, false, 1u); + + CHECK_BINOP (-, SUBTRACT, INT_MAX, 1, int, false, INT_MAX - 1); + CHECK_BINOP (-, SUBTRACT, INT_MAX, -1, int, true, INT_MIN); + CHECK_BINOP (-, SUBTRACT, INT_MIN, 1, int, true, INT_MAX); + CHECK_BINOP (-, SUBTRACT, INT_MIN, -1, int, false, INT_MIN - -1); + CHECK_BINOP (-, SUBTRACT, UINT_MAX, 1u, unsigned int, false, UINT_MAX - 1u); + CHECK_BINOP (-, SUBTRACT, 0u, 1u, unsigned int, true, 0u - 1u); + + CHECK_UNOP (-, NEGATE, INT_MIN, int, TYPE_TWOS_COMPLEMENT (int), INT_MIN); + CHECK_UNOP (-, NEGATE, 0, int, false, -0); + CHECK_UNOP (-, NEGATE, INT_MAX, int, false, -INT_MAX); + CHECK_UNOP (-, NEGATE, 0u, unsigned int, false, -0u); + CHECK_UNOP (-, NEGATE, 1u, unsigned int, true, -1u); + CHECK_UNOP (-, NEGATE, UINT_MAX, unsigned int, true, -UINT_MAX); + + CHECK_BINOP (*, MULTIPLY, INT_MAX, INT_MAX, int, true, 1); + CHECK_BINOP (*, MULTIPLY, INT_MAX, INT_MIN, int, true, INT_MIN); + CHECK_BINOP (*, MULTIPLY, INT_MIN, INT_MAX, int, true, INT_MIN); + CHECK_BINOP (*, MULTIPLY, INT_MIN, INT_MIN, int, true, 0); + CHECK_BINOP (*, MULTIPLY, -1, INT_MIN, int, + INT_NEGATE_OVERFLOW (INT_MIN), INT_MIN); + CHECK_BINOP (*, MULTIPLY, LONG_MIN / INT_MAX, (long int) INT_MAX, + long int, false, LONG_MIN - LONG_MIN % INT_MAX); + + CHECK_BINOP (/, DIVIDE, INT_MIN, -1, int, + INT_NEGATE_OVERFLOW (INT_MIN), INT_MIN); + CHECK_BINOP (/, DIVIDE, INT_MAX, 1, int, false, INT_MAX); + CHECK_BINOP (/, DIVIDE, (unsigned int) INT_MIN, -1u, unsigned int, + false, INT_MIN / -1u); + + CHECK_BINOP (%, REMAINDER, INT_MIN, -1, int, INT_NEGATE_OVERFLOW (INT_MIN), 0); + CHECK_BINOP (%, REMAINDER, INT_MAX, 1, int, false, 0); + CHECK_BINOP (%, REMAINDER, (unsigned int) INT_MIN, -1u, unsigned int, + false, INT_MIN % -1u); + + CHECK_BINOP (<<, LEFT_SHIFT, UINT_MAX, 1, unsigned int, true, UINT_MAX << 1); + CHECK_BINOP (<<, LEFT_SHIFT, UINT_MAX / 2 + 1, 1, unsigned int, true, + (UINT_MAX / 2 + 1) << 1); + CHECK_BINOP (<<, LEFT_SHIFT, UINT_MAX / 2, 1, unsigned int, false, + (UINT_MAX / 2) << 1); + + /* INT_<op>_OVERFLOW and INT_<op>_WRAPV with mixed types. */ + #define CHECK_SUM(a, b, t, v, vres) \ + ASSERT (INT_ADD_OVERFLOW (a, b) == (v)); \ + ASSERT (INT_ADD_OVERFLOW (b, a) == (v)); \ + VERIFY (INT_CONST_ADD_OVERFLOW (a, b) == (v)); \ + VERIFY (INT_CONST_ADD_OVERFLOW (b, a) == (v)); \ + VERIFY ((t) INT_CONST_ADD_WRAPV (a, b) == (t) INT_CONST_ADD_WRAPV (b, a)); \ + VERIFY ((t) INT_CONST_ADD_WRAPV (a, b) == ((v) ? (vres) : (a) + (b)) \ + || ((v) && TYPE_SIGNED (t) && !TYPE_TWOS_COMPLEMENT (t))); \ + ASSERT ((t) INT_ADD_WRAPV (a, b) == (t) INT_CONST_ADD_WRAPV (a, b)); \ + ASSERT ((t) INT_ADD_WRAPV (b, a) == (t) INT_CONST_ADD_WRAPV (a, b)) + CHECK_SUM (-1, LONG_MIN, long int, true, LONG_MAX); + CHECK_SUM (-1, UINT_MAX, unsigned int, false, DONTCARE); + CHECK_SUM (-1L, INT_MIN, long int, INT_MIN == LONG_MIN, + INT_MIN == LONG_MIN ? INT_MAX : DONTCARE); + CHECK_SUM (0u, -1, unsigned int, true, 0u + -1); + CHECK_SUM (0u, 0, unsigned int, false, DONTCARE); + CHECK_SUM (0u, 1, unsigned int, false, DONTCARE); + CHECK_SUM (1, LONG_MAX, long int, true, LONG_MIN); + CHECK_SUM (1, UINT_MAX, unsigned int, true, 0u); + CHECK_SUM (1L, INT_MAX, long int, INT_MAX == LONG_MAX, + INT_MAX == LONG_MAX ? INT_MIN : DONTCARE); + CHECK_SUM (1u, INT_MAX, unsigned int, INT_MAX == UINT_MAX, 1u + INT_MAX); + CHECK_SUM (1u, INT_MIN, unsigned int, true, 1u + INT_MIN); + + VERIFY (! INT_CONST_SUBTRACT_OVERFLOW (INT_MAX, 1u)); + VERIFY (! INT_CONST_SUBTRACT_OVERFLOW (UINT_MAX, 1)); + VERIFY (! INT_CONST_SUBTRACT_OVERFLOW (0u, -1)); + VERIFY (INT_CONST_SUBTRACT_OVERFLOW (UINT_MAX, -1)); + VERIFY (INT_CONST_SUBTRACT_OVERFLOW (INT_MIN, 1u)); + VERIFY (INT_CONST_SUBTRACT_OVERFLOW (-1, 0u)); + + #define CHECK_PRODUCT(a, b, t, v, vres) \ + ASSERT (INT_MULTIPLY_OVERFLOW (a, b) == (v)); \ + ASSERT (INT_MULTIPLY_OVERFLOW (b, a) == (v)); \ + VERIFY (INT_CONST_MULTIPLY_OVERFLOW (a, b) == (v)); \ + VERIFY (INT_CONST_MULTIPLY_OVERFLOW (b, a) == (v)); \ + VERIFY ((t) INT_CONST_MULTIPLY_WRAPV (a, b) \ + == (t) INT_CONST_MULTIPLY_WRAPV (b, a)); \ + VERIFY ((t) INT_CONST_MULTIPLY_WRAPV (a, b) == ((v) ? (vres) : (a) * (b)) \ + || ((v) && TYPE_SIGNED (t) && !TYPE_TWOS_COMPLEMENT (t))); \ + ASSERT ((t) INT_MULTIPLY_WRAPV (a, b) \ + == (t) INT_CONST_MULTIPLY_WRAPV (a, b)); \ + ASSERT ((t) INT_MULTIPLY_WRAPV (b, a) \ + == (t) INT_CONST_MULTIPLY_WRAPV (a, b)) + CHECK_PRODUCT (-1, 1u, unsigned int, true, -1 * 1u); + CHECK_PRODUCT (-1, INT_MIN, int, INT_NEGATE_OVERFLOW (INT_MIN), INT_MIN); + CHECK_PRODUCT (-1, UINT_MAX, unsigned int, true, -1 * UINT_MAX); + CHECK_PRODUCT (-32768, LONG_MAX / -32768 - 1, long int, true, LONG_MIN); + CHECK_PRODUCT (-12345, LONG_MAX / -12345, long int, false, DONTCARE); + CHECK_PRODUCT (0, -1, int, false, DONTCARE); + CHECK_PRODUCT (0, 0, int, false, DONTCARE); + CHECK_PRODUCT (0, 0u, unsigned int, false, DONTCARE); + CHECK_PRODUCT (0, 1, int, false, DONTCARE); + CHECK_PRODUCT (0, INT_MAX, int, false, DONTCARE); + CHECK_PRODUCT (0, INT_MIN, int, false, DONTCARE); + CHECK_PRODUCT (0, UINT_MAX, unsigned int, false, DONTCARE); + CHECK_PRODUCT (0u, -1, unsigned int, false, DONTCARE); + CHECK_PRODUCT (0u, 0, unsigned int, false, DONTCARE); + CHECK_PRODUCT (0u, 0u, unsigned int, false, DONTCARE); + CHECK_PRODUCT (0u, 1, unsigned int, false, DONTCARE); + CHECK_PRODUCT (0u, INT_MAX, unsigned int, false, DONTCARE); + CHECK_PRODUCT (0u, INT_MIN, unsigned int, false, DONTCARE); + CHECK_PRODUCT (0u, UINT_MAX, unsigned int, false, DONTCARE); + CHECK_PRODUCT (1, INT_MAX, int, false, DONTCARE); + CHECK_PRODUCT (1, INT_MIN, int, false, DONTCARE); + CHECK_PRODUCT (1, UINT_MAX, int, false, DONTCARE); + CHECK_PRODUCT (1u, INT_MIN, unsigned int, true, 1u * INT_MIN); + CHECK_PRODUCT (1u, INT_MAX, unsigned int, UINT_MAX < INT_MAX, 1u * INT_MAX); + CHECK_PRODUCT (INT_MAX, UINT_MAX, unsigned int, true, INT_MAX * UINT_MAX); + CHECK_PRODUCT (INT_MAX, ULONG_MAX, unsigned long int, true, + INT_MAX * ULONG_MAX); + CHECK_PRODUCT (INT_MIN, LONG_MAX / INT_MIN - 1, long int, true, LONG_MIN); + CHECK_PRODUCT (INT_MIN, LONG_MAX / INT_MIN, long int, false, DONTCARE); + CHECK_PRODUCT (INT_MIN, UINT_MAX, unsigned int, true, INT_MIN * UINT_MAX); + CHECK_PRODUCT (INT_MIN, ULONG_MAX, unsigned long int, true, + INT_MIN * ULONG_MAX); + + #define CHECK_QUOTIENT(a, b, t, v) \ + VERIFY (INT_DIVIDE_OVERFLOW (a, b) == (v)); \ + VERIFY ((v) || (t) INT_DIVIDE_WRAPV (a, b) == (a) / (b)) + + CHECK_QUOTIENT (INT_MIN, -1L, long int, + TYPE_TWOS_COMPLEMENT (long int) && INT_MIN == LONG_MIN); + CHECK_QUOTIENT (INT_MIN, UINT_MAX, unsigned int, false); + CHECK_QUOTIENT (INTMAX_MIN, UINTMAX_MAX, uintmax_t, false); + CHECK_QUOTIENT (INTMAX_MIN, UINT_MAX, intmax_t, false); + CHECK_QUOTIENT (-11, 10u, unsigned int, true); + CHECK_QUOTIENT (-10, 10u, unsigned int, true); + CHECK_QUOTIENT (-9, 10u, unsigned int, false); + CHECK_QUOTIENT (11u, -10, unsigned int, true); + CHECK_QUOTIENT (10u, -10, unsigned int, true); + CHECK_QUOTIENT (9u, -10, unsigned int, false); + + #define CHECK_REMAINDER(a, b, t, v) \ + VERIFY (INT_REMAINDER_OVERFLOW (a, b) == (v)); \ + VERIFY ((v) || (t) INT_REMAINDER_WRAPV (a, b) == (a) % (b)) + + CHECK_REMAINDER (INT_MIN, -1L, long int, + TYPE_TWOS_COMPLEMENT (long int) && INT_MIN == LONG_MIN); + CHECK_REMAINDER (-1, UINT_MAX, unsigned int, true); + CHECK_REMAINDER ((intmax_t) -1, UINTMAX_MAX, uintmax_t, true); + CHECK_REMAINDER (INTMAX_MIN, UINT_MAX, intmax_t, + (INTMAX_MAX < UINT_MAX + && - (unsigned int) INTMAX_MIN % UINT_MAX != 0)); + CHECK_REMAINDER (INT_MIN, ULONG_MAX, unsigned long int, + INT_MIN % ULONG_MAX != 1); + CHECK_REMAINDER (1u, -1, unsigned int, false); + CHECK_REMAINDER (37*39u, -39, unsigned int, false); + CHECK_REMAINDER (37*39u + 1, -39, unsigned int, true); + CHECK_REMAINDER (37*39u - 1, -39, unsigned int, true); + CHECK_REMAINDER (LONG_MAX, -INT_MAX, long int, false); return 0; } -- 2.1.0