aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMark Oteiza2017-09-30 14:14:12 -0400
committerMark Oteiza2017-09-30 14:16:18 -0400
commit185f33340680d918a95ff704a8f7e2d9e1a6f0ca (patch)
treeaf80fe1f744c467325c54a0361d6f1309bbe2855 /src
parent20a09de953f437109a098fa8c4d380663d921481 (diff)
downloademacs-185f33340680d918a95ff704a8f7e2d9e1a6f0ca.tar.gz
emacs-185f33340680d918a95ff704a8f7e2d9e1a6f0ca.zip
Add logcount (Bug#22689)
* doc/lispref/numbers.texi (Bitwise Operations): Add documentation. * etc/NEWS: Mention. * src/data.c (logcount32, logcount64): New functions. (logcount): New Lisp function. (syms_of_data): Declare it. * test/src/data-tests.el (data-tests-popcnt, data-tests-logcount): New test.
Diffstat (limited to 'src')
-rw-r--r--src/data.c61
1 files changed, 61 insertions, 0 deletions
diff --git a/src/data.c b/src/data.c
index e070be6c208..b595e3fb1ac 100644
--- a/src/data.c
+++ b/src/data.c
@@ -3069,6 +3069,66 @@ usage: (logxor &rest INTS-OR-MARKERS) */)
3069 return arith_driver (Alogxor, nargs, args); 3069 return arith_driver (Alogxor, nargs, args);
3070} 3070}
3071 3071
3072#if GNUC_PREREQ (4, 1, 0)
3073#define HAVE_BUILTIN_POPCOUNTLL
3074#endif
3075
3076#ifndef HAVE_BUILTIN_POPCOUNTLL
3077static uint32_t
3078logcount32 (uint32_t b)
3079{
3080 b -= (b >> 1) & 0x55555555;
3081 b = (b & 0x33333333) + ((b >> 2) & 0x33333333);
3082 b = (b + (b >> 4)) & 0x0f0f0f0f;
3083 return (b * 0x01010101) >> 24;
3084}
3085
3086static uint64_t
3087logcount64 (uint64_t b)
3088{
3089 b -= (b >> 1) & 0x5555555555555555ULL;
3090 b = (b & 0x3333333333333333ULL) + ((b >> 2) & 0x3333333333333333ULL);
3091 b = (b + (b >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
3092 return (b * 0x0101010101010101ULL) >> 56;
3093}
3094#endif /* HAVE_BUILTIN_POPCOUNTLL */
3095
3096DEFUN ("logcount", Flogcount, Slogcount, 1, 1, 0,
3097 doc: /* Return population count of VALUE.
3098If VALUE is negative, the count is of its two's complement representation. */)
3099 (register Lisp_Object value)
3100{
3101 Lisp_Object res;
3102 EMACS_UINT v;
3103
3104 CHECK_NUMBER (value);
3105
3106 v = XUINT (value);
3107#ifdef HAVE_BUILTIN_POPCOUNTLL
3108 if (v <= UINT_MAX)
3109 XSETINT (res, __builtin_popcount (v));
3110 else if (v <= ULONG_MAX)
3111 XSETINT (res, __builtin_popcountl (v));
3112 else if (v <= ULONG_LONG_MAX)
3113 XSETINT (res, __builtin_popcountll (v));
3114#else /* HAVE_BUILTIN_POPCOUNTLL */
3115 if (v <= UINT_MAX)
3116 XSETINT (res, logcount32 (v));
3117 else if (v <= ULONG_MAX || v <= ULONG_LONG_MAX)
3118 XSETINT (res, logcount64 (v));
3119#endif /* HAVE_BUILTIN_POPCOUNTLL */
3120 else
3121 {
3122 unsigned int count;
3123 for (count = 0; v; count++)
3124 {
3125 v &= v - 1;
3126 }
3127 XSETINT (res, count);
3128 }
3129 return res;
3130}
3131
3072static Lisp_Object 3132static Lisp_Object
3073ash_lsh_impl (Lisp_Object value, Lisp_Object count, bool lsh) 3133ash_lsh_impl (Lisp_Object value, Lisp_Object count, bool lsh)
3074{ 3134{
@@ -3856,6 +3916,7 @@ syms_of_data (void)
3856 defsubr (&Slogand); 3916 defsubr (&Slogand);
3857 defsubr (&Slogior); 3917 defsubr (&Slogior);
3858 defsubr (&Slogxor); 3918 defsubr (&Slogxor);
3919 defsubr (&Slogcount);
3859 defsubr (&Slsh); 3920 defsubr (&Slsh);
3860 defsubr (&Sash); 3921 defsubr (&Sash);
3861 defsubr (&Sadd1); 3922 defsubr (&Sadd1);