summaryrefslogtreecommitdiffstats
path: root/Include
diff options
context:
space:
mode:
authorNiklas Fiekas <niklas.fiekas@backscattering.de>2020-06-15 12:33:48 (GMT)
committerGitHub <noreply@github.com>2020-06-15 12:33:48 (GMT)
commit794e7d1ab2d7afe70fe0dd87ca8174ac860413e4 (patch)
tree48ad4d0b5a06b4f80706b16e6ca069f660b25414 /Include
parent25f38d7044a3a47465edd851c4e04f337b2c4b9b (diff)
downloadcpython-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.h47
-rw-r--r--Include/pymath.h8
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 */