intprops: port to Oracle Studio 12.3 x86
authorPaul Eggert <eggert@Penguin.CS.UCLA.EDU>
Sat, 15 Apr 2017 00:38:58 +0000 (17:38 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Sat, 15 Apr 2017 00:40:13 +0000 (17:40 -0700)
Problem reported by Gavin Smith in:
http://lists.gnu.org/archive/html/bug-gnulib/2017-04/msg00049.html
* lib/intprops.h (_GL_INT_OP_WRAPV_VIA_UNSIGNED):
Convert unsigned to signed via the usual rather than the standard way,
to avoid a compiler bug in Oracle Studio 12.3 x86.

ChangeLog
lib/intprops.h

index ae1a8bd9e7002b70160b8fc73e42495b2755d574..97d1e59873ec025a38a5748dd2a9c9c3974585ef 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2017-04-14  Paul Eggert  <eggert@Penguin.CS.UCLA.EDU>
+
+       intprops: port to Oracle Studio 12.3 x86
+       Problem reported by Gavin Smith in:
+       http://lists.gnu.org/archive/html/bug-gnulib/2017-04/msg00049.html
+       * lib/intprops.h (_GL_INT_OP_WRAPV_VIA_UNSIGNED):
+       Convert unsigned to signed via the usual rather than the standard way,
+       to avoid a compiler bug in Oracle Studio 12.3 x86.
+
 2017-04-08  Paul Eggert  <eggert@cs.ucla.edu>
 
        getopt: prefer - to _ in new file names
index eb06b6917e6b089ae163f6e121512d8f6ab6d6f3..220b509290c8cef367c31dc2425d3967c10f90c0 100644 (file)
@@ -442,17 +442,34 @@ verify (TYPE_WIDTH (unsigned int) == UINT_WIDTH);
   ((overflow (a, b) \
     || (EXPR_SIGNED ((a) op (b)) && ((a) op (b)) < (tmin)) \
     || (tmax) < ((a) op (b))) \
-   ? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t, tmin, tmax), 1) \
-   : (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t, tmin, tmax), 0))
-
-/* Return A <op> B, where the operation is given by OP.  Use the
-   unsigned type UT for calculation to avoid overflow problems.
-   Convert the result to type T without overflow by subtracting TMIN
-   from large values before converting, and adding it afterwards.
-   Compilers can optimize all the operations except OP.  */
-#define _GL_INT_OP_WRAPV_VIA_UNSIGNED(a, b, op, ut, t, tmin, tmax) \
-  (((ut) (a) op (ut) (b)) <= (tmax) \
-   ? (t) ((ut) (a) op (ut) (b)) \
-   : ((t) (((ut) (a) op (ut) (b)) - (tmin)) + (tmin)))
+   ? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 1) \
+   : (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 0))
+
+/* Return A <op> B, where the operation is given by OP.  Return the
+   low-order bits of the mathematically-correct answer.  Use the
+   unsigned type UT for calculation to avoid undefined behavior on
+   signed integer overflow.  Assume that conversion to the result type
+   T yields the low-order bits in the usual way.  UT and T are the
+   same width, T is two's complement, and there is no padding or trap
+   representations.
+
+   According to the C standard, converting UT to T yields an
+   implementation-defined result or signal for values outside T's range.
+   So, the standard way to convert UT to T is to subtract TMIN from
+   greater-than-TMAX values before converting them to T, and to add
+   TMIN afterwards, where TMIN and TMAX are T's extrema.
+   However, in practice there is no need to subtract and add TMIN.
+   E.g., GCC converts to signed integers in the usual way; see:
+   https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html
+   All other known C compilers are similar to GCC in this respect.
+   Furthermore, Oracle Studio Studio 12.3 x86 has a bug when
+   implementing the standard way; see:
+   http://lists.gnu.org/archive/html/bug-gnulib/2017-04/msg00049.html
+
+   So, implement this operation in the usual way rather than in
+   the standard way.  */
+
+#define _GL_INT_OP_WRAPV_VIA_UNSIGNED(a, b, op, ut, t) \
+  ((t) ((ut) (a) op (ut) (b)))
 
 #endif /* _GL_INTPROPS_H */