]> git.eshelyaron.com Git - emacs.git/commitdiff
Help GCC compute modiff_incr
authorPaul Eggert <eggert@cs.ucla.edu>
Mon, 15 May 2023 01:51:24 +0000 (18:51 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Mon, 15 May 2023 02:28:13 +0000 (19:28 -0700)
* src/floatfns.c: Don’t include count-leading-zeros.h,
since we no longer use it directly.
(ecount_leading_zeros): Remove.
(Flogb): Use elogb instead of doing it by hand.
* src/lisp.h: Include count-leading-zeros.h.
(elogb): New macro.
(modiff_incr): Use it so that on typical platforms we
use a hardware instruction instead of a loop.

src/floatfns.c
src/lisp.h

index 13f0ca3e129a1571354ea3cf955562f6be5850a8..e40364f81886e4fc987757f11dd27566dde5525f 100644 (file)
@@ -55,8 +55,6 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include <math.h>
 
-#include <count-leading-zeros.h>
-
 /* Emacs needs proper handling of +/-inf; correct printing as well as
    important packages depend on it.  Make sure the user didn't specify
    -ffinite-math-only, either directly or implicitly with -Ofast or
@@ -304,14 +302,6 @@ DEFUN ("float", Ffloat, Sfloat, 1, 1, 0,
   return FLOATP (arg) ? arg : make_float (XFLOATINT (arg));
 }
 
-static int
-ecount_leading_zeros (EMACS_UINT x)
-{
-  return (EMACS_UINT_WIDTH == UINT_WIDTH ? count_leading_zeros (x)
-         : EMACS_UINT_WIDTH == ULONG_WIDTH ? count_leading_zeros_l (x)
-         : count_leading_zeros_ll (x));
-}
-
 DEFUN ("logb", Flogb, Slogb, 1, 1, 0,
        doc: /* Returns largest integer <= the base 2 log of the magnitude of ARG.
 This is the same as the exponent of a float.  */)
@@ -338,7 +328,7 @@ This is the same as the exponent of a float.  */)
       EMACS_INT i = XFIXNUM (arg);
       if (i == 0)
        return make_float (-HUGE_VAL);
-      value = EMACS_UINT_WIDTH - 1 - ecount_leading_zeros (eabs (i));
+      value = elogb (eabs (i));
     }
 
   return make_fixnum (value);
index 8f7d44bfb0d31638ef5cea25fa877770aa8882e7..c9a64f07427f2deaaa0364bb970d6a27a75c23f8 100644 (file)
@@ -30,6 +30,7 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 #include <limits.h>
 
 #include <attribute.h>
+#include <count-leading-zeros.h>
 #include <intprops.h>
 #include <verify.h>
 
@@ -3904,6 +3905,20 @@ integer_to_uintmax (Lisp_Object num, uintmax_t *n)
     }
 }
 
+/* Return floor (log2 (N)) as an int, where 0 < N <= ULLONG_MAX.  */
+#if (201112 <= __STDC_VERSION__ && INT_MAX <= UINT_MAX \
+     && LONG_MAX <= ULONG_MAX && LLONG_MAX <= ULLONG_MAX)
+# define elogb(n) \
+    _Generic (+(n), \
+             int:           UINT_WIDTH   - 1 - count_leading_zeros    (n), \
+             unsigned int:  UINT_WIDTH   - 1 - count_leading_zeros    (n), \
+             long:          ULONG_WIDTH  - 1 - count_leading_zeros_l  (n), \
+             unsigned long: ULONG_WIDTH  - 1 - count_leading_zeros_l  (n), \
+             default:       ULLONG_WIDTH - 1 - count_leading_zeros_ll (n))
+#else
+# define elogb(n) (ULLONG_WIDTH - 1 - count_leading_zeros_ll (n))
+#endif
+
 /* A modification count.  These are wide enough, and incremented
    rarely enough, so that they should never overflow a 60-bit counter
    in practice, and the code below assumes this so a compiler can
@@ -3913,11 +3928,12 @@ typedef intmax_t modiff_count;
 INLINE modiff_count
 modiff_incr (modiff_count *a, ptrdiff_t len)
 {
-  modiff_count a0 = *a; int incr = len ? 1 : 0;
+  modiff_count a0 = *a;
   /* Increase the counter more for a large modification and less for a
      small modification.  Increase it logarithmically to avoid
      increasing it too much.  */
-  while (len >>= 1) incr++;
+  verify (PTRDIFF_MAX <= ULLONG_MAX);
+  int incr = len == 0 ? 1 : elogb (len) + 1;
   bool modiff_overflow = INT_ADD_WRAPV (a0, incr, a);
   eassert (!modiff_overflow && *a >> 30 >> 30 == 0);
   return a0;