Polyfill the 32-bit _bsr() function

This commit is contained in:
Justine Tunney 2023-08-13 21:13:32 -07:00
parent c776a32f75
commit ef6387ee5e
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
3 changed files with 47 additions and 68 deletions

View file

@ -6,7 +6,6 @@ COSMOPOLITAN_C_START_
int _bsf(int) pureconst; int _bsf(int) pureconst;
int _bsfl(long) pureconst; int _bsfl(long) pureconst;
int _bsfll(long long) pureconst; int _bsfll(long long) pureconst;
int _bsf128(uintmax_t) pureconst;
#if defined(__GNUC__) && !defined(__STRICT_ANSI__) #if defined(__GNUC__) && !defined(__STRICT_ANSI__)
#define _bsf(x) __builtin_ctz(x) #define _bsf(x) __builtin_ctz(x)

View file

@ -17,40 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/intrin/bsr.h" #include "libc/intrin/bsr.h"
// clang-format off
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 𝑥.
*
* 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 64-bit integer
* @return number in range 0..63 or undefined if 𝑥 is 0
*/
int(_bsrl)(long 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 𝑥. * Returns binary logarithm of 𝑥.
@ -70,7 +37,11 @@ int(_bsrl)(long x) {
* @return number in range 0..31 or undefined if 𝑥 is 0 * @return number in range 0..31 or undefined if 𝑥 is 0
*/ */
int(_bsr)(int x) { int(_bsr)(int x) {
return _bsrl((unsigned)x); int r = 0;
if(x & 0xFFFF0000u) { x >>= 16; r |= 16; }
if(x & 0xFF00) { x >>= 8; r |= 8; }
if(x & 0xF0) { x >>= 4; r |= 4; }
if(x & 0xC) { x >>= 2; r |= 2; }
if(x & 0x2) { r |= 1; }
return r;
} }
__weak_reference(_bsrl, _bsrll);

View file

@ -1,7 +1,7 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2023 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the any purpose with or without fee is hereby granted, provided that the
@ -16,31 +16,40 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/macros.internal.h" #include "libc/intrin/bsr.h"
// Returns binary logarithm of integer 𝑥. static const char kDebruijn[64] = {
// 0, 47, 1, 56, 48, 27, 2, 60, 57, 49, 41, 37, 28, 16, 3, 61,
// uint32 𝑥 _bsf(𝑥) tzcnt(𝑥) ffs(𝑥) bsr(𝑥) lzcnt(𝑥) 54, 58, 35, 52, 50, 42, 21, 44, 38, 32, 29, 23, 17, 11, 4, 62,
// 0x00000000 wut 32 0 wut 32 46, 55, 26, 59, 40, 36, 15, 53, 34, 51, 20, 43, 31, 22, 10, 45,
// 0x00000001 0 0 1 0 31 25, 39, 14, 33, 19, 30, 9, 24, 13, 18, 8, 12, 7, 6, 5, 63,
// 0x80000001 0 0 1 31 0 };
// 0x80000000 31 31 32 31 0
// 0x00000010 4 4 5 4 27 /**
// 0x08000010 4 4 5 27 4 * Returns binary logarithm of 𝑥.
// 0x08000000 27 27 28 27 4 *
// 0xffffffff 0 0 1 31 0 * ctz(𝑥) 31^clz(𝑥) clz(𝑥)
// * uint32 𝑥 _bsf(𝑥) tzcnt(𝑥) ffs(𝑥) _bsr(𝑥) lzcnt(𝑥)
// @param rsi:rdi is 128-bit unsigned 𝑥 value * 0x00000000 wut 32 0 wut 32
// @return eax number in range [0,128) or undef if 𝑥 is 0 * 0x00000001 0 0 1 0 31
// @see also treasure trove of nearly identical functions * 0x80000001 0 0 1 31 0
.ftrace1 * 0x80000000 31 31 32 31 0
_bsr128: * 0x00000010 4 4 5 4 27
.ftrace2 * 0x08000010 4 4 5 27 4
.leafprologue * 0x08000000 27 27 28 27 4
bsr %rsi,%rax * 0xffffffff 0 0 1 31 0
jnz 2f *
bsr %rdi,%rax * @param x is a 64-bit integer
1: .leafepilogue * @return number in range 0..63 or undefined if 𝑥 is 0
2: add $64,%eax */
jmp 1b int(_bsrl)(long x) {
.endfn _bsr128,globl x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
x |= x >> 32;
return kDebruijn[(x * 0x03f79d71b4cb0a89) >> 58];
}
__weak_reference(_bsrl, _bsrll);