diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2013-10-07 14:37:19 -0700 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2013-10-07 14:37:19 -0700 |
commit | 595e113b15e2ce80b95d39d1851ce78f25ffa1f4 (patch) | |
tree | 42c02de46a13e0af39fcc83de9d57c29e309f99e /src/data.c | |
parent | ddb317ba828f05eb48e98fda530443955485e75d (diff) | |
download | emacs-595e113b15e2ce80b95d39d1851ce78f25ffa1f4.tar.gz |
Improve support for popcount and counting trailing zeros.
Do this by using the Gnulib modules for this.
This should generate faster code on non-GCC, non-MSC platforms,
and make the code a bit more portable, at least in theory.
* admin/merge-gnulib (GNULIB_MODULES): Add count-one-bits
and count-trailing-zeros.
* lib/count-one-bits.c, lib/count-one-bits.h:
* lib/count-trailing-zeros.c, lib/count-trailing-zeros.h:
* m4/count-one-bits.m4, m4/count-trailing-zeros.m4:
New files, copied from gnulib.
* lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate.
* nt/gnulib.mk: Merge changes from lib/gnulib.mk.
* src/data.c: Include <count-one-bits.h>, <count-trailing-zeros.h>.
(USE_MSC_POPCOUNT, POPCOUNT_STATIC_INLINE)
(NEED_GENERIC_POPCOUNT, popcount_size_t_generic)
(popcount_size_t_msc, popcount_size_t_gcc):
Remove; now done by Gnulib.
(popcount_size_t): Now a macro that defers to Gnulib.
(count_trailing_zero_bits): Return int, for consistency with
Gnulib and because Emacs prefers signed to unsigned int.
Don't assume that size_t is either unsigned int or unsigned long
or unsigned long long.
(size_t_to_host_endian): Do not assume that size_t is either
exactly 32 or exactly 64 bits wide.
* src/lisp.h (BITS_PER_SIZE_T): Define consistently with BITS_PER_LONG
etc., so that it's now an enum constant, not a macro.
No need to assume that it's either 32 or 64.
Fixes: debbugs:15550
Diffstat (limited to 'src/data.c')
-rw-r--r-- | src/data.c | 179 |
1 files changed, 44 insertions, 135 deletions
diff --git a/src/data.c b/src/data.c index a6bfe50a3bb..4ef326e4cfd 100644 --- a/src/data.c +++ b/src/data.c @@ -22,6 +22,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ #include <stdio.h> #include <byteswap.h> +#include <count-one-bits.h> +#include <count-trailing-zeros.h> #include <intprops.h> #include "lisp.h" @@ -2971,108 +2973,16 @@ bool_vector_spare_mask (ptrdiff_t nr_bits) return (((size_t) 1) << (nr_bits % BITS_PER_SIZE_T)) - 1; } -#if _MSC_VER >= 1500 && (defined _M_IX86 || defined _M_X64) -# define USE_MSC_POPCOUNT -# define POPCOUNT_STATIC_INLINE static inline -#elif __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) -# define USE_GCC_POPCOUNT -# if 199901L <= __STDC_VERSION__ || !__STRICT_ANSI__ -# define POPCOUNT_STATIC_INLINE static inline -# endif +#if SIZE_MAX <= UINT_MAX +# define popcount_size_t count_one_bits +#elif SIZE_MAX <= ULONG_MAX +# define popcount_size_t count_one_bits_l +#elif SIZE_MAX <= ULLONG_MAX +# define popcount_size_t count_one_bits_ll #else -# define NEED_GENERIC_POPCOUNT -#endif -#ifndef POPCOUNT_STATIC_INLINE -# define POPCOUNT_STATIC_INLINE static -#endif - -#ifdef USE_MSC_POPCOUNT -# define NEED_GENERIC_POPCOUNT -#endif - -#ifdef NEED_GENERIC_POPCOUNT -POPCOUNT_STATIC_INLINE unsigned int -popcount_size_t_generic (size_t val) -{ - unsigned short j; - unsigned int count = 0; - - for (j = 0; j < BITS_PER_SIZE_T; ++j) - count += !!((((size_t) 1) << j) & val); - - return count; -} +# error "size_t wider than long long? Please file a bug report." #endif -#ifdef USE_MSC_POPCOUNT -POPCOUNT_STATIC_INLINE unsigned int -popcount_size_t_msc (size_t val) -{ - unsigned int count; - -#pragma intrinsic __cpuid - /* While gcc falls back to its own generic code if the machine on - which it's running doesn't support popcount, we need to perform the - detection and fallback ourselves when compiling with Microsoft's - compiler. */ - - static enum { - popcount_unknown_support, - popcount_use_generic, - popcount_use_intrinsic - } popcount_state; - - if (popcount_state == popcount_unknown_support) - { - int cpu_info[4]; - __cpuid (cpu_info, 1); - if (cpu_info[2] & (1<<23)) /* See MSDN. */ - popcount_state = popcount_use_intrinsic; - else - popcount_state = popcount_use_generic; - } - - if (popcount_state == popcount_use_intrinsic) - { -# if BITS_PER_SIZE_T == 64 -# pragma intrinsic __popcnt64 - count = __popcnt64 (val); -# else -# pragma intrinsic __popcnt - count = __popcnt (val); -# endif - } - else - count = popcount_size_t_generic (val); - - return count; -} -#endif /* USE_MSC_POPCOUNT */ - -#ifdef USE_GCC_POPCOUNT -POPCOUNT_STATIC_INLINE unsigned int -popcount_size_t_gcc (size_t val) -{ -# if BITS_PER_SIZE_T == 64 - return __builtin_popcountll (val); -# else - return __builtin_popcount (val); -# endif -} -#endif /* USE_GCC_POPCOUNT */ - -POPCOUNT_STATIC_INLINE unsigned int -popcount_size_t (size_t val) -{ -#if defined USE_MSC_POPCOUNT - return popcount_size_t_msc (val); -#elif defined USE_GCC_POPCOUNT - return popcount_size_t_gcc (val); -#else - return popcount_size_t_generic (val); -#endif -} - enum bool_vector_op { bool_vector_exclusive_or, bool_vector_union, bool_vector_intersection, @@ -3143,55 +3053,54 @@ bool_vector_binop_driver (Lisp_Object op1, /* Compute the number of trailing zero bits in val. If val is zero, return the number of bits in val. */ -static unsigned int +static int count_trailing_zero_bits (size_t val) { + if (SIZE_MAX == UINT_MAX) + return count_trailing_zeros (val); + if (SIZE_MAX == ULONG_MAX) + return count_trailing_zeros_l (val); +# if HAVE_UNSIGNED_LONG_LONG_INT + if (SIZE_MAX == ULLONG_MAX) + return count_trailing_zeros_ll (val); +# endif + + /* The rest of this code is for the unlikely platform where size_t differs + in width from unsigned int, unsigned long, and unsigned long long. */ if (val == 0) return CHAR_BIT * sizeof (val); - -#if defined USE_GCC_POPCOUNT && BITS_PER_SIZE_T == 64 - return __builtin_ctzll (val); -#elif defined USE_GCC_POPCOUNT && BITS_PER_SIZE_T == 32 - return __builtin_ctz (val); -#elif _MSC_VER && BITS_PER_SIZE_T == 64 -# pragma intrinsic _BitScanForward64 + if (SIZE_MAX <= UINT_MAX) + return count_trailing_zeros (val); + if (SIZE_MAX <= ULONG_MAX) + return count_trailing_zeros_l (val); { - /* No support test needed: support since 386. */ - unsigned long result; - _BitScanForward64 (&result, val); - return (unsigned int) result; - } -#elif _MSC_VER && BITS_PER_SIZE_T == 32 -# pragma intrinsic _BitScanForward - { - /* No support test needed: support since 386. */ - unsigned long result; - _BitScanForward (&result, val); - return (unsigned int) result; - } -#else - { - unsigned int count; - count = 0; - for (val = ~val; val & 1; val >>= 1) - ++count; - - return count; +# if HAVE_UNSIGNED_LONG_LONG_INT + verify (SIZE_MAX <= ULLONG_MAX); + return count_trailing_zeros_ll (val); +# else + verify (SIZE_MAX <= ULONG_MAX); +# endif } -#endif } static size_t size_t_to_host_endian (size_t val) { -#ifdef WORDS_BIGENDIAN -# if BITS_PER_SIZE_T == 64 - return bswap_64 (val); -# else +#ifndef WORDS_BIGENDIAN + return val; +#elif SIZE_MAX >> 31 == 1 return bswap_32 (val); -# endif +#elif SIZE_MAX >> 31 >> 31 >> 1 == 1 + return bswap_64 (val); #else - return val; + int i; + size_t r = 0; + for (i = 0; i < sizeof val; i++) + { + r = (r << CHAR_BIT) | (val & ((1u << CHAR_BIT) - 1)); + val >>= CHAR_BIT; + } + return r; #endif } |