bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] intprops: add WRAPV and const flavors for GCC 5


From: Paul Eggert
Subject: [PATCH] intprops: add WRAPV and const flavors for GCC 5
Date: Fri, 30 Oct 2015 13:48:38 -0700

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  <address@hidden>
+
+       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  <address@hidden>
 
        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.},
address@hidden://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
address@hidden (@var{t})} expands to a constant
address@hidden (@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
address@hidden (@var{t})} expands to a constant expression
address@hidden (@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
address@hidden (@var{t})} expands to an integer constant
address@hidden (@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
address@hidden (@var{t})} expands to an integer constant
address@hidden (@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
address@hidden (@var{t})} and @code{TYPE_MAXIMUM (@var{t})} expand
-to integer constant expressions equal to the minimum and maximum
address@hidden (@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
 
address@hidden Wraparound Arithmetic
address@hidden Wraparound Arithmetic with Signed Integers
+
address@hidden wraparound integer arithmetic
+
+Signed integer arithmetic has undefined behavior on overflow in address@hidden
+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
address@hidden on a two's complement machine.  You can also use
+overflow-checking macros to check whether wraparound occurred.
address@hidden Type Overflow}.
+
address@hidden
+These macros have the following restrictions:
+
address@hidden @bullet
address@hidden
+Their arguments must be integer expressions.
+
address@hidden
+They may evaluate their arguments zero or multiple times, so the
+arguments should not have side effects.
+
address@hidden
+On non-GCC-compatible compilers that do not support C11, the type of
address@hidden (@var{a}, @var{b})} might differ from the native
+type of @address@hidden + @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.
address@hidden itemize
+
+These macros are tuned for their last argument being a constant.
+
address@hidden @code
address@hidden INT_ADD_WRAP (@var{a}, @var{b})
address@hidden INT_ADD_WRAP
+Return the low-order bits of @address@hidden + @var{b}}.  See above for
+restrictions.
+
address@hidden INT_CONST_ADD_WRAP (@var{a}, @var{b})
address@hidden INT_CONST_ADD_WRAP
+Return the low-order bits of @address@hidden + @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.
+
address@hidden INT_SUBTRACT_WRAP (@var{a}, @var{b})
address@hidden INT_SUBTRACT_WRAP
+Return the low-order bits of @address@hidden - @var{b}}.  See above for
+restrictions.
+
address@hidden INT_CONST_SUBTRACT_WRAP (@var{a}, @var{b})
address@hidden INT_CONST_SUBTRACT_WRAP
+Return the low-order bits of @address@hidden - @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.
+
address@hidden INT_NEGATE_WRAP (@var{a})
address@hidden INT_NEGATE_WRAP
+Return the low-order bits of @address@hidden  See above for restrictions.
+This macro is an integer constant expression if its arguments are.
+
address@hidden INT_MULTIPLY_WRAP (@var{a}, @var{b})
address@hidden INT_MULTIPLY_WRAP
+Return the low-order bits of @address@hidden * @var{b}}.  See above for
+restrictions.
+
address@hidden INT_CONST_MULTIPLY_WRAP (@var{a}, @var{b})
address@hidden INT_CONST_MULTIPLY_WRAP
+Return the low-order bits of @address@hidden * @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.
+
address@hidden INT_DIVIDE_WRAP (@var{a}, @var{b})
address@hidden INT_DIVIDE_WRAP
+Return the low-order bits of @address@hidden / @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.
+
address@hidden INT_REMAINDER_WRAP (@var{a}, @var{b})
address@hidden INT_REMAINDER_WRAP
+Return the low-order bits of @address@hidden % @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.
+
address@hidden INT_LEFT_SHIFT_WRAP (@var{a}, @var{b})
address@hidden INT_LEFT_SHIFT_WRAP
+Return the low-order bits of @address@hidden << @var{b}}.  See above for
+restrictions.  The C standard says that behavior is undefined for
+shifts unless address@hidden@var{b}<@var{w} where @var{w} is @var{a}'s word
+width, and that when @var{a} is negative then @address@hidden <<
address@hidden has undefined behavior, but this macro does not check these
+other restrictions.  This macro is an integer constant expression if
+its arguments are.
address@hidden table
+
address@hidden Integer Type Overflow
address@hidden Integer Type Overflow
+
address@hidden integer type overflow
address@hidden overflow, integer type
+
+Although unsigned integer arithmetic wraps around modulo a power of
+two, signed integer arithmetic has undefined behavior on overflow in
address@hidden  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:
+
address@hidden
+#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)
address@hidden
+  long int result = INT_MULTIPLY_WRAPV (a, b);
+  printf ("result is %ld (%s)\n", result,
+          (INT_MULTIPLY_OVERFLOW (a, b)
+           ? "after overflow"
+           : "no overflow"));
address@hidden
+
+/* 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))
address@hidden;
address@hidden example
+
address@hidden
+These macros have the following restrictions:
+
address@hidden @bullet
address@hidden
+Their arguments must be integer expressions.
+
address@hidden
+They may evaluate their arguments zero or multiple times, so the
+arguments should not have side effects.
address@hidden itemize
+
+These macros are tuned for their last argument being a constant.
+
address@hidden @code
address@hidden INT_ADD_OVERFLOW (@var{a}, @var{b})
address@hidden INT_ADD_OVERFLOW
+Yield 1 if @address@hidden + @var{b}} would overflow.  See above for
+restrictions.
+
address@hidden INT_CONST_ADD_OVERFLOW (@var{a}, @var{b})
address@hidden INT_CONST_ADD_OVERFLOW
+Yield 1 if @address@hidden + @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.
+
address@hidden INT_SUBTRACT_OVERFLOW (@var{a}, @var{b})
address@hidden INT_SUBTRACT_OVERFLOW
+Yield 1 if @address@hidden - @var{b}} would overflow.  See above for
+restrictions.
+
address@hidden INT_CONST_SUBTRACT_OVERFLOW (@var{a}, @var{b})
address@hidden INT_CONST_SUBTRACT_OVERFLOW
+Yield 1 if @address@hidden - @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.
+
address@hidden INT_NEGATE_OVERFLOW (@var{a})
address@hidden INT_NEGATE_OVERFLOW
+Yields 1 if @address@hidden would overflow.  See above for restrictions.
+This macro is an integer constant expression if its arguments are.
+
address@hidden INT_MULTIPLY_OVERFLOW (@var{a}, @var{b})
address@hidden INT_MULTIPLY_OVERFLOW
+Yield 1 if @address@hidden * @var{b}} would overflow.  See above for
+restrictions.
+
address@hidden INT_CONST_MULTIPLY_OVERFLOW (@var{a}, @var{b})
address@hidden INT_CONST_MULTIPLY_OVERFLOW
+Yield 1 if @address@hidden * @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.
+
address@hidden INT_DIVIDE_OVERFLOW (@var{a}, @var{b})
address@hidden INT_DIVIDE_OVERFLOW
+Yields 1 if @address@hidden / @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.
+
address@hidden INT_REMAINDER_OVERFLOW (@var{a}, @var{b})
address@hidden INT_REMAINDER_OVERFLOW
+Yield 1 if @address@hidden % @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.
+
address@hidden INT_LEFT_SHIFT_OVERFLOW (@var{a}, @var{b})
address@hidden INT_LEFT_SHIFT_OVERFLOW
+Yield 1 if @address@hidden << @var{b}} would overflow.  See above for
+restrictions.  The C standard says that behavior is undefined for
+shifts unless address@hidden@var{b}<@var{w} where @var{w} is @var{a}'s word
+width, and that when @var{a} is negative then @address@hidden <<
address@hidden has undefined behavior, but this macro does not check these
+other restrictions.  This macro is an integer constant expression if
+its arguments are.
address@hidden 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 address@hidden@var{b}<@var{w}
 where @var{w} is @var{a}'s word width, and that when @var{a} is negative
-then @address@hidden << @var{b}} has undefined behavior and
address@hidden@var{a} >> @var{b}} has implementation-defined behavior, but
-this macro does not check these other restrictions.
address@hidden table
-
address@hidden Integer Type Overflow
address@hidden Integer Type Overflow
-
address@hidden integer type overflow
address@hidden 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:
-
address@hidden
-#include <intprops.h>
-void
-print_product (long int a, long int b)
address@hidden
-  if (INT_MULTIPLY_OVERFLOW (a, b))
-    printf ("multiply would overflow");
-  else
-    printf ("product is %ld", a * b);
address@hidden
address@hidden example
-
address@hidden
-These macros have the following restrictions:
-
address@hidden @bullet
address@hidden
-Their arguments must be integer expressions.
-
address@hidden
-They may evaluate their arguments zero or multiple times, so the
-arguments should not have side effects.
address@hidden itemize
-
-These macros are tuned for their last argument being a constant.
-
address@hidden @code
address@hidden INT_ADD_OVERFLOW (@var{a}, @var{b})
address@hidden INT_ADD_OVERFLOW
-Yield 1 if @address@hidden + @var{b}} would overflow.  See above for
-restrictions.
-
address@hidden INT_SUBTRACT_OVERFLOW (@var{a}, @var{b})
address@hidden INT_SUBTRACT_OVERFLOW
-Yield 1 if @address@hidden - @var{b}} would overflow.  See above for
-restrictions.
-
address@hidden INT_NEGATE_OVERFLOW (@var{a})
address@hidden INT_NEGATE_OVERFLOW
-Yields 1 if @address@hidden would overflow.  See above for restrictions.
-
address@hidden INT_MULTIPLY_OVERFLOW (@var{a}, @var{b})
address@hidden INT_MULTIPLY_OVERFLOW
-Yield 1 if @address@hidden * @var{b}} would overflow.  See above for
-restrictions.
-
address@hidden INT_DIVIDE_OVERFLOW (@var{a}, @var{b})
address@hidden INT_DIVIDE_OVERFLOW
-Yields 1 if @address@hidden / @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.
-
address@hidden INT_REMAINDER_OVERFLOW (@var{a}, @var{b})
address@hidden INT_REMAINDER_OVERFLOW
-Yield 1 if @address@hidden % @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.
-
address@hidden INT_LEFT_SHIFT_OVERFLOW (@var{a}, @var{b})
address@hidden INT_LEFT_SHIFT_OVERFLOW
-Yield 1 if @address@hidden << @var{b}} would overflow.  See above for
-restrictions.  The C standard says that behavior is undefined for
-shifts unless address@hidden@var{b}<@var{w} where @var{w} is @var{a}'s word
-width, and that when @var{a} is negative then @address@hidden <<
address@hidden has undefined behavior and @address@hidden >> @var{b}} has
-implementation-defined behavior, but this macro does not check these
-other restrictions.
+then @address@hidden << @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





reply via email to

[Prev in Thread] Current Thread [Next in Thread]