diff liboctave/util/oct-inttypes.h @ 25846:144820478378 stable

eliminate OCTAVE_HAVE_FAST_INT_OPS macro and associated code (bug #54572) With current compilers, there no longer seems to be a performance advantage significant enough to justify the the trickery used in the special case code that was used when OCTAVE_HAVE_FAST_INT_OPS was defined. * acinclude.m4 (OCTAVE_FAST_INT_OPS): Delete macro. * configure.ac: Delete use. * mk-octave-config-h.sh: Don't recognize OCTAVE_HAVE_FAST_INT_OPS. * oct-inttypes.h, oct-inttypes.cc: (octave_int_arith_base<T,true>::abs, octave_int_arith_base<T,true>::minus, octave_int_arith_base<T,true>::add, octave_int_arith_base<T,true>::sub): Eliminate code blocks used if OCTAVE_HAVE_FAST_INT_OPS is defined.
author John W. Eaton <jwe@octave.org>
date Thu, 30 Aug 2018 10:03:09 -0400
parents 26c41d8bf170
children dd10eea0be97 1f52a96c8c21
line wrap: on
line diff
--- a/liboctave/util/oct-inttypes.h	Wed Aug 29 14:33:36 2018 -0700
+++ b/liboctave/util/oct-inttypes.h	Thu Aug 30 10:03:09 2018 -0400
@@ -507,32 +507,6 @@
 
 #endif
 
-// Signed integer arithmetic.
-//
-// Rationale: If OCTAVE_HAVE_FAST_INT_OPS is defined, the following
-// conditions should hold:
-//
-//   1. Signed numbers are represented by twos complement (see
-//      <http://en.wikipedia.org/wiki/Two%27s_complement>)
-//
-//   2. static_cast to unsigned int counterpart works like
-//      interpreting the signed bit pattern as unsigned (and is thus
-//      zero-cost).
-//
-//   3. Signed addition and subtraction yield the same bit results as
-//      unsigned.  (We use casts to prevent optimization interference,
-//      so there is no need for things like -ftrapv).
-//
-//   4. Bit operations on signed integers work like on unsigned
-//      integers, except for the shifts.  Shifts are arithmetic.
-//
-// The above conditions are satisfied by most modern platforms.  If
-// OCTAVE_HAVE_FAST_INT_OPS is defined, bit tricks and wraparound
-// arithmetics are used to avoid conditional jumps as much as
-// possible, thus being friendly to modern pipeline processor
-// architectures.  Otherwise, we fall back to a bullet-proof code that
-// only uses assumptions guaranteed by the standard.
-
 template <typename T>
 class octave_int_arith_base<T, true> : octave_int_base<T>
 {
@@ -550,32 +524,16 @@
   static T
   abs (T x)
   {
-#if defined (OCTAVE_HAVE_FAST_INT_OPS)
-    // This is close to how GCC does std::abs, but we can't just use std::abs,
-    // because its behavior for INT_MIN is undefined and the compiler could
-    // discard the following test.
-    T m = x >> std::numeric_limits<T>::digits;
-    T y = (x ^ m) - m;
-    if (y < 0)
-      {
-        y = octave_int_base<T>::max_val ();
-      }
-    return y;
-#else
-    // -INT_MAX is safe because C++ actually allows only three implementations
-    // of integers: sign & magnitude, ones complement and twos complement.
-    // The first test will, with modest optimizations, evaluate at compile
-    // time, and maybe eliminate the branch completely.
-    T y;
-    if (octave_int_base<T>::min_val () < -octave_int_base<T>::max_val ()
-        && x == octave_int_base<T>::min_val ())
-      {
-        y = octave_int_base<T>::max_val ();
-      }
-    else
-      y = (x < 0) ? -x : x;
-    return y;
-#endif
+    // -INT_MAX is safe because C++ actually allows only three
+    // implementations of integers: sign & magnitude, ones complement
+    // and twos complement.  The first test will, with modest
+    // optimizations, evaluate at compile time, and maybe eliminate
+    // the branch completely.
+
+    return ((octave_int_base<T>::min_val () < -octave_int_base<T>::max_val ()
+             && x == octave_int_base<T>::min_val ())
+            ? octave_int_base<T>::max_val ()
+            : ((x < 0) ? -x : x));
   }
 
   static T
@@ -596,114 +554,42 @@
   lshift (T x, int n) { return x << n; }
 
   // Minus has problems similar to abs.
+
   static T
   minus (T x)
   {
-#if defined (OCTAVE_HAVE_FAST_INT_OPS)
-    T y = -x;
-    if (y == octave_int_base<T>::min_val ())
-      {
-        --y;
-      }
-    return y;
-#else
-    T y;
-    if (octave_int_base<T>::min_val () < -octave_int_base<T>::max_val ()
-        && x == octave_int_base<T>::min_val ())
-      {
-        y = octave_int_base<T>::max_val ();
-      }
-    else
-      y = -x;
-    return y;
-#endif
+    return ((octave_int_base<T>::min_val () < -octave_int_base<T>::max_val ()
+             && x == octave_int_base<T>::min_val ())
+            ? octave_int_base<T>::max_val ()
+            : -x);
   }
 
   static T
   add (T x, T y)
   {
-#if defined (OCTAVE_HAVE_FAST_INT_OPS)
-
-    // The typecasts do nothing, but they are here to prevent an optimizing
-    // compiler from interfering.  Also, the signed operations on small types
-    // actually return int.
-    T u = static_cast<UT> (x) + static_cast<UT> (y);
-    T ux = u ^ x;
-    T uy = u ^ y;
-
-    return ((ux & uy) < 0
-            ? (u < 0
-               ? octave_int_base<T>::max_val ()
-               : octave_int_base<T>::min_val ())
-            : u);
-
-#else
+    // Avoid anything that may overflow.
 
-    // We shall carefully avoid anything that may overflow.
-    T u;
-
-    if (y < 0)
-      {
-        if (x < octave_int_base<T>::min_val () - y)
-          u = octave_int_base<T>::min_val ();
-        else
-          u = x + y;
-      }
-    else
-      {
-        if (x > octave_int_base<T>::max_val () - y)
-          u = octave_int_base<T>::max_val ();
-        else
-          u = x + y;
-      }
-
-    return u;
-
-#endif
+    return (y < 0
+            ? (x < octave_int_base<T>::min_val () - y
+               ? octave_int_base<T>::min_val ()
+               : x + y)
+            : (x > octave_int_base<T>::max_val () - y
+               ? octave_int_base<T>::max_val ()
+               : x + y));
   }
 
-  // This is very similar to addition.
   static T
   sub (T x, T y)
   {
-#if defined (OCTAVE_HAVE_FAST_INT_OPS)
-    // The typecasts do nothing, but they are here to prevent an optimizing
-    // compiler from interfering.  Also, the signed operations on small types
-    // actually return int.
-    T u = static_cast<UT> (x) - static_cast<UT> (y);
-    T ux = u ^ x;
-    T uy = u ^ ~y;
-    if ((ux & uy) < 0)
-      {
-        u = (__signbit (~u)
-             ? octave_int_base<T>::min_val ()
-             : octave_int_base<T>::max_val ());
-      }
-    return u;
-#else
-    // We shall carefully avoid anything that may overflow.
-    T u;
-    if (y < 0)
-      {
-        if (x > octave_int_base<T>::max_val () + y)
-          {
-            u = octave_int_base<T>::max_val ();
-          }
-        else
-          u = x - y;
-      }
-    else
-      {
-        if (x < octave_int_base<T>::min_val () + y)
-          {
-            u = octave_int_base<T>::min_val ();
-          }
-        else
-          u = x - y;
-      }
+    // Avoid anything that may overflow.
 
-    return u;
-#endif
+    return (y < 0
+            ? (x > octave_int_base<T>::max_val () + y
+               ? octave_int_base<T>::max_val ()
+               : x - y)
+            : (x < octave_int_base<T>::min_val () + y
+                ? octave_int_base<T>::min_val ()
+               : x - y));
   }
 
   // Multiplication is done using promotion to wider integer type.  If there is
@@ -803,9 +689,6 @@
 
   long double p = static_cast<long double> (x) * static_cast<long double> (y);
 
-  // NOTE: We could maybe do it with a single branch if
-  // OCTAVE_HAVE_FAST_INT_OPS, but it would require one more runtime
-  // conversion, so the question is whether it would really be faster.
   if (p > static_cast<long double> (octave_int_base<int64_t>::max_val ()))
     retval = octave_int_base<int64_t>::max_val ();
   else if (p < static_cast<long double> (octave_int_base<int64_t>::min_val ()))