diff options
| author | Mark Oteiza | 2017-09-30 14:14:12 -0400 |
|---|---|---|
| committer | Mark Oteiza | 2017-09-30 14:16:18 -0400 |
| commit | 185f33340680d918a95ff704a8f7e2d9e1a6f0ca (patch) | |
| tree | af80fe1f744c467325c54a0361d6f1309bbe2855 /src | |
| parent | 20a09de953f437109a098fa8c4d380663d921481 (diff) | |
| download | emacs-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.c | 61 |
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 | ||
| 3077 | static uint32_t | ||
| 3078 | logcount32 (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 | |||
| 3086 | static uint64_t | ||
| 3087 | logcount64 (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 | |||
| 3096 | DEFUN ("logcount", Flogcount, Slogcount, 1, 1, 0, | ||
| 3097 | doc: /* Return population count of VALUE. | ||
| 3098 | If 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 | |||
| 3072 | static Lisp_Object | 3132 | static Lisp_Object |
| 3073 | ash_lsh_impl (Lisp_Object value, Lisp_Object count, bool lsh) | 3133 | ash_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); |