]> code.delx.au - gnu-emacs/blobdiff - lib/intprops.h
Merge from gnulib.
[gnu-emacs] / lib / intprops.h
index f85ccade4e1adf07abf0e98ac82378b8da9f641a..4441f1c294e7215db3aabdcf76825016b9406781 100644 (file)
     : (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
    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)
                       _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 */