diff --git a/libc/intrin/bsf.c b/libc/intrin/bsf.c index da6eca51e..70989f7ca 100644 --- a/libc/intrin/bsf.c +++ b/libc/intrin/bsf.c @@ -32,11 +32,20 @@ * 0x08000000 27 27 28 27 4 * 0xffffffff 0 0 1 31 0 * - * @param x is a 32-bit integer - * @return number in range 0..31 or undefined if 𝑥 is 0 + * @param 𝑥 is a 64-bit integer + * @return number in range 0..63 or undefined if 𝑥 is 0 */ -int(_bsf)(int x) { - return _bsf(x); +int(_bsfl)(long x) { + unsigned l, r; + x &= -x; + l = x | x >> 32; + r = !!(x >> 32), r <<= 1; + r += !!((l & 0xffff0000)), r <<= 1; + r += !!((l & 0xff00ff00)), r <<= 1; + r += !!((l & 0xf0f0f0f0)), r <<= 1; + r += !!((l & 0xcccccccc)), r <<= 1; + r += !!((l & 0xaaaaaaaa)); + return r; } /** @@ -53,11 +62,11 @@ int(_bsf)(int x) { * 0x08000000 27 27 28 27 4 * 0xffffffff 0 0 1 31 0 * - * @param 𝑥 is a 64-bit integer - * @return number in range 0..63 or undefined if 𝑥 is 0 + * @param x is a 32-bit integer + * @return number in range 0..31 or undefined if 𝑥 is 0 */ -int(_bsfl)(long x) { - return _bsfl(x); +int(_bsf)(int x) { + return _bsf((unsigned)x); } __weak_reference(_bsfl, _bsfll); diff --git a/libc/intrin/bsr.c b/libc/intrin/bsr.c index 31e25879e..b8d8646dc 100644 --- a/libc/intrin/bsr.c +++ b/libc/intrin/bsr.c @@ -18,26 +18,12 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/intrin/bsr.h" -/** - * Returns binary logarithm of 𝑥. - * - * ctz(𝑥) 31^clz(𝑥) clz(𝑥) - * uint32 𝑥 _bsf(𝑥) tzcnt(𝑥) ffs(𝑥) _bsr(𝑥) lzcnt(𝑥) - * 0x00000000 wut 32 0 wut 32 - * 0x00000001 0 0 1 0 31 - * 0x80000001 0 0 1 31 0 - * 0x80000000 31 31 32 31 0 - * 0x00000010 4 4 5 4 27 - * 0x08000010 4 4 5 27 4 - * 0x08000000 27 27 28 27 4 - * 0xffffffff 0 0 1 31 0 - * - * @param x is a 32-bit integer - * @return number in range 0..31 or undefined if 𝑥 is 0 - */ -int(_bsr)(int x) { - return _bsr(x); -} +static const char kDebruijn[64] = { + 0, 47, 1, 56, 48, 27, 2, 60, 57, 49, 41, 37, 28, 16, 3, 61, + 54, 58, 35, 52, 50, 42, 21, 44, 38, 32, 29, 23, 17, 11, 4, 62, + 46, 55, 26, 59, 40, 36, 15, 53, 34, 51, 20, 43, 31, 22, 10, 45, + 25, 39, 14, 33, 19, 30, 9, 24, 13, 18, 8, 12, 7, 6, 5, 63, +}; /** * Returns binary logarithm of 𝑥. @@ -57,7 +43,34 @@ int(_bsr)(int x) { * @return number in range 0..63 or undefined if 𝑥 is 0 */ int(_bsrl)(long x) { - return _bsrl(x); + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + x |= x >> 32; + return kDebruijn[(x * 0x03f79d71b4cb0a89) >> 58]; +} + +/** + * Returns binary logarithm of 𝑥. + * + * ctz(𝑥) 31^clz(𝑥) clz(𝑥) + * uint32 𝑥 _bsf(𝑥) tzcnt(𝑥) ffs(𝑥) _bsr(𝑥) lzcnt(𝑥) + * 0x00000000 wut 32 0 wut 32 + * 0x00000001 0 0 1 0 31 + * 0x80000001 0 0 1 31 0 + * 0x80000000 31 31 32 31 0 + * 0x00000010 4 4 5 4 27 + * 0x08000010 4 4 5 27 4 + * 0x08000000 27 27 28 27 4 + * 0xffffffff 0 0 1 31 0 + * + * @param x is a 32-bit integer + * @return number in range 0..31 or undefined if 𝑥 is 0 + */ +int(_bsr)(int x) { + return _bsrl((unsigned)x); } __weak_reference(_bsrl, _bsrll);