Skip to content

Commit 0bd4265

Browse files
committed
Ensure future compatibility
1 parent 6464ca6 commit 0bd4265

File tree

2 files changed

+22
-14
lines changed

2 files changed

+22
-14
lines changed

Include/internal/pycore_bitutils.h

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,26 +135,34 @@ _Py_popcount32(uint32_t x)
135135
// integer k such that x < 2**k. Equivalent to floor(log2(x)) + 1 for x != 0.
136136
static inline int
137137
_Py_bit_length(unsigned long x) {
138-
if (!x) {
138+
if (x == 0) {
139139
return 0;
140140
}
141141
#if (defined(__clang__) || (defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ >= 4))))
142+
// Undefined behavior for x == 0.
142143
return sizeof(unsigned long) * 8 - __builtin_clzl(x);
143144
#elif defined(_MSC_VER)
144-
Py_BUILD_ASSERT(4 == sizeof(unsigned long));
145+
Py_BUILD_ASSERT(sizeof(unsigned long) <= 4);
146+
// Does not write to msb if x == 0.
145147
unsigned long msb;
146148
_BitScanReverse(&msb, x);
147-
return msb + 1;
149+
return (int)msb + 1;
148150
#else
149151
int msb = 0;
150-
while (x != 0) {
152+
do {
151153
msb += 1;
152154
x >>= 1;
153-
}
155+
} while (x != 0);
154156
return msb;
155157
#endif
156158
}
157159

160+
static inline int
161+
_Py_bit_length_digit(digit x) {
162+
Py_BUILD_ASSERT(PyLong_SHIFT <= sizeof(unsigned long) * 8);
163+
return _Py_popcount32((unsigned long)x);
164+
}
165+
158166

159167
#ifdef __cplusplus
160168
}

Objects/longobject.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -712,7 +712,7 @@ _PyLong_NumBits(PyObject *vv)
712712
if ((size_t)(ndigits - 1) > SIZE_MAX / (size_t)PyLong_SHIFT)
713713
goto Overflow;
714714
result = (size_t)(ndigits - 1) * (size_t)PyLong_SHIFT;
715-
msd_bits = _Py_bit_length(msd);
715+
msd_bits = _Py_bit_length_digit(msd);
716716
if (SIZE_MAX - msd_bits < result)
717717
goto Overflow;
718718
result += msd_bits;
@@ -1822,7 +1822,7 @@ long_format_binary(PyObject *aa, int base, int alternate,
18221822
return -1;
18231823
}
18241824
size_a_in_bits = (size_a - 1) * PyLong_SHIFT +
1825-
_Py_bit_length(a->ob_digit[size_a - 1]);
1825+
_Py_bit_length_digit(a->ob_digit[size_a - 1]);
18261826
/* Allow 1 character for a '-' sign. */
18271827
sz = negative + (size_a_in_bits + (bits - 1)) / bits;
18281828
}
@@ -2642,7 +2642,7 @@ x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem)
26422642

26432643
/* normalize: shift w1 left so that its top digit is >= PyLong_BASE/2.
26442644
shift v1 left by the same amount. Results go into w and v. */
2645-
d = PyLong_SHIFT - _Py_bit_length(w1->ob_digit[size_w-1]);
2645+
d = PyLong_SHIFT - _Py_bit_length_digit(w1->ob_digit[size_w-1]);
26462646
carry = v_lshift(w->ob_digit, w1->ob_digit, size_w, d);
26472647
assert(carry == 0);
26482648
carry = v_lshift(v->ob_digit, v1->ob_digit, size_v, d);
@@ -2764,7 +2764,7 @@ _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e)
27642764
*e = 0;
27652765
return 0.0;
27662766
}
2767-
a_bits = _Py_bit_length(a->ob_digit[a_size-1]);
2767+
a_bits = _Py_bit_length_digit(a->ob_digit[a_size-1]);
27682768
/* The following is an overflow-free version of the check
27692769
"if ((a_size - 1) * PyLong_SHIFT + a_bits > PY_SSIZE_T_MAX) ..." */
27702770
if (a_size >= (PY_SSIZE_T_MAX - 1) / PyLong_SHIFT + 1 &&
@@ -3857,8 +3857,8 @@ long_true_divide(PyObject *v, PyObject *w)
38573857
/* Extreme underflow */
38583858
goto underflow_or_zero;
38593859
/* Next line is now safe from overflowing a Py_ssize_t */
3860-
diff = diff * PyLong_SHIFT + _Py_bit_length(a->ob_digit[a_size - 1]) -
3861-
_Py_bit_length(b->ob_digit[b_size - 1]);
3860+
diff = diff * PyLong_SHIFT + _Py_bit_length_digit(a->ob_digit[a_size - 1]) -
3861+
_Py_bit_length_digit(b->ob_digit[b_size - 1]);
38623862
/* Now diff = a_bits - b_bits. */
38633863
if (diff > DBL_MAX_EXP)
38643864
goto overflow;
@@ -3934,7 +3934,7 @@ long_true_divide(PyObject *v, PyObject *w)
39343934
}
39353935
x_size = Py_ABS(Py_SIZE(x));
39363936
assert(x_size > 0); /* result of division is never zero */
3937-
x_bits = (x_size-1)*PyLong_SHIFT+_Py_bit_length(x->ob_digit[x_size-1]);
3937+
x_bits = (x_size-1)*PyLong_SHIFT+_Py_bit_length_digit(x->ob_digit[x_size-1]);
39383938

39393939
/* The number of extra bits that have to be rounded away. */
39403940
extra_bits = Py_MAX(x_bits, DBL_MIN_EXP - shift) - DBL_MANT_DIG;
@@ -4748,7 +4748,7 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg)
47484748
alloc_b = Py_SIZE(b);
47494749
/* reduce until a fits into 2 digits */
47504750
while ((size_a = Py_SIZE(a)) > 2) {
4751-
nbits = _Py_bit_length(a->ob_digit[size_a-1]);
4751+
nbits = _Py_bit_length_digit(a->ob_digit[size_a-1]);
47524752
/* extract top 2*PyLong_SHIFT bits of a into x, along with
47534753
corresponding bits of b into y */
47544754
size_b = Py_SIZE(b);
@@ -5269,7 +5269,7 @@ int_bit_length_impl(PyObject *self)
52695269
return PyLong_FromLong(0);
52705270

52715271
msd = ((PyLongObject *)self)->ob_digit[ndigits-1];
5272-
msd_bits = _Py_bit_length(msd);
5272+
msd_bits = _Py_bit_length_digit(msd);
52735273

52745274
if (ndigits <= PY_SSIZE_T_MAX/PyLong_SHIFT)
52755275
return PyLong_FromSsize_t((ndigits-1)*PyLong_SHIFT + msd_bits);

0 commit comments

Comments
 (0)