diff options
author | Niklas Fiekas <niklas.fiekas@backscattering.de> | 2020-06-15 12:33:48 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-15 12:33:48 (GMT) |
commit | 794e7d1ab2d7afe70fe0dd87ca8174ac860413e4 (patch) | |
tree | 48ad4d0b5a06b4f80706b16e6ca069f660b25414 /Include | |
parent | 25f38d7044a3a47465edd851c4e04f337b2c4b9b (diff) | |
download | cpython-794e7d1ab2d7afe70fe0dd87ca8174ac860413e4.zip cpython-794e7d1ab2d7afe70fe0dd87ca8174ac860413e4.tar.gz cpython-794e7d1ab2d7afe70fe0dd87ca8174ac860413e4.tar.bz2 |
bpo-29782: Consolidate _Py_Bit_Length() (GH-20739)
In GH-2866, _Py_Bit_Length() was added to pymath.h for lack of a better
location. GH-20518 added a more appropriate header file for bit utilities. It
also shows how to properly use intrinsics. This allows reconsidering bpo-29782.
* Move the function to the new header.
* Changed return type to match __builtin_clzl() and reviewed usage.
* Use intrinsics where available.
* Pick a fallback implementation suitable for inlining.
Diffstat (limited to 'Include')
-rw-r--r-- | Include/internal/pycore_bitutils.h | 47 | ||||
-rw-r--r-- | Include/pymath.h | 8 |
2 files changed, 43 insertions, 12 deletions
diff --git a/Include/internal/pycore_bitutils.h b/Include/internal/pycore_bitutils.h index 36ffe23..0bd3270 100644 --- a/Include/internal/pycore_bitutils.h +++ b/Include/internal/pycore_bitutils.h @@ -7,8 +7,8 @@ - _Py_bswap64(uint64_t) */ -#ifndef Py_INTERNAL_BSWAP_H -#define Py_INTERNAL_BSWAP_H +#ifndef Py_INTERNAL_BITUTILS_H +#define Py_INTERNAL_BITUTILS_H #ifdef __cplusplus extern "C" { #endif @@ -131,8 +131,47 @@ _Py_popcount32(uint32_t x) } +// Return the index of the most significant 1 bit in 'x'. This is the smallest +// integer k such that x < 2**k. Equivalent to floor(log2(x)) + 1 for x != 0. +static inline int +_Py_bit_length(unsigned long x) +{ +#if (defined(__clang__) || defined(__GNUC__)) + if (x != 0) { + // __builtin_clzl() is available since GCC 3.4. + // Undefined behavior for x == 0. + return (int)sizeof(unsigned long) * 8 - __builtin_clzl(x); + } + else { + return 0; + } +#elif defined(_MSC_VER) + // _BitScanReverse() is documented to search 32 bits. + Py_BUILD_ASSERT(sizeof(unsigned long) <= 4); + unsigned long msb; + if (_BitScanReverse(&msb, x)) { + return (int)msb + 1; + } + else { + return 0; + } +#else + const int BIT_LENGTH_TABLE[32] = { + 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + }; + int msb = 0; + while (x >= 32) { + msb += 6; + x >>= 6; + } + msb += BIT_LENGTH_TABLE[x]; + return msb; +#endif +} + + #ifdef __cplusplus } #endif -#endif /* !Py_INTERNAL_BSWAP_H */ - +#endif /* !Py_INTERNAL_BITUTILS_H */ diff --git a/Include/pymath.h b/Include/pymath.h index 63ca972..f869724 100644 --- a/Include/pymath.h +++ b/Include/pymath.h @@ -227,12 +227,4 @@ PyAPI_FUNC(void) _Py_set_387controlword(unsigned short); * behavior. */ #define _Py_InIntegralTypeRange(type, v) (_Py_IntegralTypeMin(type) <= v && v <= _Py_IntegralTypeMax(type)) -/* Return the smallest integer k such that n < 2**k, or 0 if n == 0. - * Equivalent to floor(log2(x))+1. Also equivalent to: bitwidth_of_type - - * count_leading_zero_bits(x) - */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(unsigned int) _Py_bit_length(unsigned long d); -#endif - #endif /* Py_PYMATH_H */ |