diff options
Diffstat (limited to 'Cython/Utility/Optimize.c')
-rw-r--r-- | Cython/Utility/Optimize.c | 111 |
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 { |