summaryrefslogtreecommitdiff
path: root/Cython/Utility/Optimize.c
diff options
context:
space:
mode:
Diffstat (limited to 'Cython/Utility/Optimize.c')
-rw-r--r--Cython/Utility/Optimize.c111
1 files changed, 53 insertions, 58 deletions
diff --git a/Cython/Utility/Optimize.c b/Cython/Utility/Optimize.c
index 9ec7bda37..a16fb6ac9 100644
--- a/Cython/Utility/Optimize.c
+++ b/Cython/Utility/Optimize.c
@@ -979,14 +979,12 @@ static PyObject* __Pyx__PyNumber_PowerOf2(PyObject *two, PyObject *exp, PyObject
#endif
if (likely(PyLong_CheckExact(exp))) {
#if CYTHON_USE_PYLONG_INTERNALS
- const Py_ssize_t size = Py_SIZE(exp);
- // tuned to optimise branch prediction
- if (likely(size == 1)) {
- shiftby = __Pyx_PyLong_Digits(exp)[0];
- } else if (size == 0) {
+ if (__Pyx_PyLong_IsZero(exp)) {
return PyInt_FromLong(1L);
- } else if (unlikely(size < 0)) {
+ } else if (__Pyx_PyLong_IsNeg(exp)) {
goto fallback;
+ } else if (__Pyx_PyLong_IsCompact(exp)) {
+ shiftby = __Pyx_PyLong_CompactValueUnsigned(exp);
} else {
shiftby = PyLong_AsSsize_t(exp);
}
@@ -1062,21 +1060,18 @@ static CYTHON_INLINE {{c_ret_type}} __Pyx_PyInt_{{'' if ret_type.is_pyobject els
if (likely(PyLong_CheckExact({{pyval}}))) {
int unequal;
unsigned long uintval;
- Py_ssize_t size = Py_SIZE({{pyval}});
+ Py_ssize_t size = __Pyx_PyLong_DigitCount({{pyval}});
const digit* digits = __Pyx_PyLong_Digits({{pyval}});
if (intval == 0) {
- // == 0 => Py_SIZE(pyval) == 0
- {{return_compare('size', '0', c_op)}}
+ {{return_compare('__Pyx_PyLong_IsZero(%s)' % pyval, '1', c_op)}}
} else if (intval < 0) {
- // < 0 => Py_SIZE(pyval) < 0
- if (size >= 0)
+ if (__Pyx_PyLong_IsNonNeg({{pyval}}))
{{return_false if op == 'Eq' else return_true}};
// both are negative => can use absolute values now.
intval = -intval;
- size = -size;
} else {
// > 0 => Py_SIZE(pyval) > 0
- if (size <= 0)
+ if (__Pyx_PyLong_IsNeg({{pyval}}))
{{return_false if op == 'Eq' else return_true}};
}
// After checking that the sign is the same (and excluding 0), now compare the absolute values.
@@ -1242,20 +1237,15 @@ static {{c_ret_type}} {{cfunc_name}}(PyObject *op1, PyObject *op2, long intval,
PY_LONG_LONG ll{{ival}}, llx;
#endif
{{endif}}
- const digit* digits = __Pyx_PyLong_Digits({{pyval}});
- const Py_ssize_t size = Py_SIZE({{pyval}});
{{if c_op == '&'}}
// special case for &-ing arbitrarily large numbers with known single digit operands
if ((intval & PyLong_MASK) == intval) {
- long result = 0;
- if(likely(size)) {
- result = intval & (likely(size>0) ? digits[0] : (PyLong_MASK - digits[0] + 1));
- }
+ long result = intval & (long) __Pyx_PyLong_CompactValue({{pyval}});
return PyLong_FromLong(result);
}
{{endif}}
// special cases for 0: + - * % / // | ^ & >> <<
- if (unlikely(size == 0)) {
+ if (unlikely(__Pyx_PyLong_IsZero({{pyval}}))) {
{{if order == 'CObj' and c_op in '%/'}}
// division by zero!
{{zerodiv_check('0')}}
@@ -1277,10 +1267,11 @@ static {{c_ret_type}} {{cfunc_name}}(PyObject *op1, PyObject *op2, long intval,
{{endif}}
}
// handle most common case first to avoid indirect branch and optimise branch prediction
- if (likely(__Pyx_sst_abs(size) <= 1)) {
- {{ival}} = likely(size) ? digits[0] : 0;
- if (size == -1) {{ival}} = -{{ival}};
+ if (likely(__Pyx_PyLong_IsCompact({{pyval}}))) {
+ {{ival}} = __Pyx_PyLong_CompactValue({{pyval}});
} else {
+ const digit* digits = __Pyx_PyLong_Digits({{pyval}});
+ const Py_ssize_t size = __Pyx_PyLong_SignedDigitCount({{pyval}});
switch (size) {
{{for _size in range(2, 5)}}
{{for _case in (-_size, _size)}}
@@ -1337,7 +1328,7 @@ static {{c_ret_type}} {{cfunc_name}}(PyObject *op1, PyObject *op2, long intval,
x += ((x != 0) & ((x ^ b) < 0)) * b;
{{elif op == 'TrueDivide'}}
if ((8 * sizeof(long) <= 53 || likely(labs({{ival}}) <= ((PY_LONG_LONG)1 << 53)))
- || __Pyx_sst_abs(size) <= 52 / PyLong_SHIFT) {
+ || __Pyx_PyLong_DigitCount({{pyval}}) <= 52 / PyLong_SHIFT) {
return PyFloat_FromDouble((double)a / (double)b);
}
return PyLong_Type.tp_as_number->nb_{{slot_name}}(op1, op2);
@@ -1497,46 +1488,50 @@ static {{c_ret_type}} {{cfunc_name}}(PyObject *op1, PyObject *op2, double floatv
if (likely(PyLong_CheckExact({{pyval}}))) {
#if CYTHON_USE_PYLONG_INTERNALS
- const digit* digits = __Pyx_PyLong_Digits({{pyval}});
- const Py_ssize_t size = Py_SIZE({{pyval}});
- switch (size) {
- case 0: {{fval}} = 0.0; {{zerodiv_check(fval)}} break;
- case -1: {{fval}} = -(double) digits[0]; break;
- case 1: {{fval}} = (double) digits[0]; break;
- {{for _size in (2, 3, 4)}}
- case -{{_size}}:
- case {{_size}}:
- if (8 * sizeof(unsigned long) > {{_size}} * PyLong_SHIFT && ((8 * sizeof(unsigned long) < 53) || ({{_size-1}} * PyLong_SHIFT < 53))) {
- {{fval}} = (double) {{pylong_join(_size, 'digits')}};
- // let CPython do its own float rounding from 2**53 on (max. consecutive integer in double float)
- if ((8 * sizeof(unsigned long) < 53) || ({{_size}} * PyLong_SHIFT < 53) || ({{fval}} < (double) ((PY_LONG_LONG)1 << 53))) {
- if (size == {{-_size}})
- {{fval}} = -{{fval}};
- break;
+ if (__Pyx_PyLong_IsZero({{pyval}})) {
+ {{fval}} = 0.0;
+ {{zerodiv_check(fval)}}
+ } else if (__Pyx_PyLong_IsCompact({{pyval}})) {
+ {{fval}} = (double) __Pyx_PyLong_CompactValue({{pyval}});
+ } else {
+ const digit* digits = __Pyx_PyLong_Digits({{pyval}});
+ const Py_ssize_t size = __Pyx_PyLong_SignedDigitCount({{pyval}});
+ switch (size) {
+ {{for _size in (2, 3, 4)}}
+ case -{{_size}}:
+ case {{_size}}:
+ if (8 * sizeof(unsigned long) > {{_size}} * PyLong_SHIFT && ((8 * sizeof(unsigned long) < 53) || ({{_size-1}} * PyLong_SHIFT < 53))) {
+ {{fval}} = (double) {{pylong_join(_size, 'digits')}};
+ // let CPython do its own float rounding from 2**53 on (max. consecutive integer in double float)
+ if ((8 * sizeof(unsigned long) < 53) || ({{_size}} * PyLong_SHIFT < 53) || ({{fval}} < (double) ((PY_LONG_LONG)1 << 53))) {
+ if (size == {{-_size}})
+ {{fval}} = -{{fval}};
+ break;
+ }
}
- }
- // Fall through if size doesn't fit safely into a double anymore.
- // It may not be obvious that this is a safe fall-through given the "fval < 2**53"
- // check above. However, the number of digits that CPython uses for a given PyLong
- // value is minimal, and together with the "(size-1) * SHIFT < 53" check above,
- // this should make it safe.
- CYTHON_FALLTHROUGH;
- {{endfor}}
- default:
+ // Fall through if size doesn't fit safely into a double anymore.
+ // It may not be obvious that this is a safe fall-through given the "fval < 2**53"
+ // check above. However, the number of digits that CPython uses for a given PyLong
+ // value is minimal, and together with the "(size-1) * SHIFT < 53" check above,
+ // this should make it safe.
+ CYTHON_FALLTHROUGH;
+ {{endfor}}
+ default:
#endif
{{if op in ('Eq', 'Ne')}}
- return {{'' if ret_type.is_pyobject else '__Pyx_PyObject_IsTrueAndDecref'}}(
- PyFloat_Type.tp_richcompare({{'op1, op2' if order == 'CObj' else 'op2, op1'}}, Py_{{op.upper()}}));
+ return {{'' if ret_type.is_pyobject else '__Pyx_PyObject_IsTrueAndDecref'}}(
+ PyFloat_Type.tp_richcompare({{'op1, op2' if order == 'CObj' else 'op2, op1'}}, Py_{{op.upper()}}));
{{else}}
- {{fval}} = PyLong_AsDouble({{pyval}});
- if (unlikely({{fval}} == -1.0 && PyErr_Occurred())) return NULL;
- {{if zerodiv_check(fval)}}
- #if !CYTHON_USE_PYLONG_INTERNALS
- {{zerodiv_check(fval)}}
- #endif
- {{endif}}
+ {{fval}} = PyLong_AsDouble({{pyval}});
+ if (unlikely({{fval}} == -1.0 && PyErr_Occurred())) return NULL;
+ {{if zerodiv_check(fval)}}
+ #if !CYTHON_USE_PYLONG_INTERNALS
+ {{zerodiv_check(fval)}}
+ #endif
+ {{endif}}
{{endif}}
#if CYTHON_USE_PYLONG_INTERNALS
+ }
}
#endif
} else {