Replace the "clever trick" with the popcount intrinsic#19
Replace the "clever trick" with the popcount intrinsic#19
Conversation
Both [GCC][1] and [clang][2] have long supported the `__builtin_popcount` family of bit operation builtins. Let's use them! (One [C23][3] day, we could `#include <stdbit.h>` and `stdc_count_ones`.) [1]: https://gcc.gnu.org/onlinedocs/gcc/Bit-Operation-Builtins.html#index-_005f_005fbuiltin_005fpopcountg "Bit Operation Builtins (GCC)" [2]: https://clang.llvm.org/docs/LanguageExtensions.html#builtin-popcountg "Clang Language Extensions - __builtin_popcountg" [3]: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3220.pdf "C International Standard (ISO/IEC 9899:2024)" --- I ran this test to confirm identical behaviour: ```c #include <assert.h> #include <stdint.h> #include <stdio.h> static int old_count_set_bits(uint32_t x) { register uint32_t i = x; /* take no chances! */ /* clever trick for adding bits together in parallel to count them */ i = ((i & 0xAAAAAAAA) >> 1) + (i & ~0xAAAAAAAA); i = ((i & 0xCCCCCCCC) >> 2) + (i & ~0xCCCCCCCC); i = ((i & 0xF0F0F0F0) >> 4) + (i & ~0xF0F0F0F0); i = ((i & 0xFF00FF00) >> 8) + (i & ~0xFF00FF00); i = ((i & 0xFFFF0000) >> 16) + (i & ~0xFFFF0000); return i; } static int new_count_set_bits(uint32_t x) { return __builtin_popcountg(x); } int main(void) { for (uint32_t x = 0; x < UINT32_MAX; x++) { assert(old_count_set_bits(x) == new_count_set_bits(x)); if (0 == (x & (UINT32_MAX >> 4))) { printf( "%llu%% (%x / %x)\n", ((uint64_t) x * 100) / UINT32_MAX, x, UINT32_MAX ); } } } ``` It's still magic that computers can now count to UINT32_MAX, in seconds!
Yeah, sometimes it's nice to be living in The Future. |
|
So, for this, I would want the autoconf thingie that checks whether the compiler can actually do this (is this in C11?) on the platform in question -- currently we have something known to work everywhere and I'd like to preserve that state of affairs, even if we almost certainly want to use the builtin if it's available -- and then be #ifdeffing out the guts of count_set_bits (and maybe making it conditionally inline cf. how Unicode routines in utf.h/utf-ctype.h work) rather than replacing it everywhere. Also now wondering about similar issues in bf_random() (see numbers.c) which might then make this worth a new fake system header... |
|
popcount isn’t in C11, sadly. Is that our minimum supported standard? Or are you thinking to maybe carve off a place to put functions like this that enable backwards compat?
Regardless, I’ll give a crack at the m4 madness when I get a free moment!
…On Wed, Oct 15, 2025, at 02:16, Roger Crew wrote:
*wrog* left a comment (wrog/lambdamoo#19) <#19 (comment)>
So, for this, I would want the autoconf thingie that checks whether the compiler can actually do this (is this in C11?) on the platform in question, and then be #ifdeffing out the guts of count_set_bits rather than replacing it everywhere.
Also now wondering about similar issues in bf_random() (see numbers.c) which might then make this worth a new fake system header...
—
Reply to this email directly, view it on GitHub <#19 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAAF3WPGYLEZMDR2N7GTULL3XUHTDAVCNFSM6AAAAACILNSDNSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTIMBSGM3TKMZUGE>.
You are receiving this because you authored the thread.Message ID: ***@***.***>
|
|
Right now we're at C99. I think I could be talked into C11 (since that's been 15 years and we've actually already got one POSIX 2007ism that I know of [the %ms in scxnf]) but I at least need to see what's in there. Baby steps :-) |
|
I will never get around to taking a crack at the m4 madness because, as it turns out, becoming a father has made me bereft of free moments. (unsubscribing!) |
Both GCC and clang have long supported the
__builtin_popcountfamily of bit operation builtins.Let's use them!
(One C23 day, we could
#include <stdbit.h>andstdc_count_ones.)I ran this test to confirm identical behaviour:
It's still magic that computers can now count to UINT32_MAX, in seconds!