From 0f5b1fcdf0be8c1b3084518f1c4f6f375828094b Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 14 May 2023 18:51:24 -0700 Subject: Help GCC compute modiff_incr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 | 12 +----------- src/lisp.h | 20 ++++++++++++++++++-- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/floatfns.c b/src/floatfns.c index 13f0ca3e129..e40364f8188 100644 --- a/src/floatfns.c +++ b/src/floatfns.c @@ -55,8 +55,6 @@ along with GNU Emacs. If not, see . */ #include -#include - /* 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); diff --git a/src/lisp.h b/src/lisp.h index 8f7d44bfb0d..c9a64f07427 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -30,6 +30,7 @@ along with GNU Emacs. If not, see . */ #include #include +#include #include #include @@ -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; -- cgit v1.2.1