Commit 20a10e73 authored by Stefan Behnel's avatar Stefan Behnel

tune PyLong optimisations at (gcc) assembly level so that they prefer the most...

tune PyLong optimisations at (gcc) assembly level so that they prefer the most common case of a single-digit
parent b79a55d8
...@@ -183,6 +183,10 @@ ...@@ -183,6 +183,10 @@
#define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass) #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass)
#endif #endif
#define __Pyx_sst_abs(value) \
(sizeof(int) >= sizeof(Py_ssize_t) ? abs(value) : \
(sizeof(long) >= sizeof(Py_ssize_t) ? labs(value) : llabs(value)))
/* inline attribute */ /* inline attribute */
#ifndef CYTHON_INLINE #ifndef CYTHON_INLINE
#if defined(__GNUC__) #if defined(__GNUC__)
......
...@@ -449,12 +449,16 @@ static PyObject* __Pyx__PyNumber_PowerOf2(PyObject *two, PyObject *exp, PyObject ...@@ -449,12 +449,16 @@ static PyObject* __Pyx__PyNumber_PowerOf2(PyObject *two, PyObject *exp, PyObject
#endif #endif
if (likely(PyLong_CheckExact(exp))) { if (likely(PyLong_CheckExact(exp))) {
#if CYTHON_USE_PYLONG_INTERNALS #if CYTHON_USE_PYLONG_INTERNALS
switch (Py_SIZE(exp)) { const Py_ssize_t size = Py_SIZE(exp);
case 0: shiftby = 0; break; // tuned to optimise branch prediction
case 1: shiftby = ((PyLongObject*)exp)->ob_digit[0]; break; if (likely(size == 1)) {
default: shiftby = ((PyLongObject*)exp)->ob_digit[0];
if (unlikely(Py_SIZE(exp) < 0)) goto fallback; } else if (size == 0) {
shiftby = PyLong_AsSsize_t(exp); break; return PyInt_FromLong(1L);
} else if (unlikely(size < 0)) {
goto fallback;
} else {
shiftby = PyLong_AsSsize_t(exp);
} }
#else #else
shiftby = PyLong_AsSsize_t(exp); shiftby = PyLong_AsSsize_t(exp);
...@@ -563,26 +567,26 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO ...@@ -563,26 +567,26 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO
long x, {{ival}}; long x, {{ival}};
const digit* digits = ((PyLongObject*){{pyval}})->ob_digit; const digit* digits = ((PyLongObject*){{pyval}})->ob_digit;
const Py_ssize_t size = Py_SIZE({{pyval}}); const Py_ssize_t size = Py_SIZE({{pyval}});
switch (size) { // handle most common case first to avoid indirect branch and optimise branch prediction
case 0: {{ival}} = 0; break; if (likely(__Pyx_sst_abs(size) <= 1)) {
case -1: {{if c_op != '%'}} {{ival}} = likely(size) ? digits[0] : 0;
{{ival}} = -(sdigit)digits[0]; break; {{if c_op != '%'}}if (size == -1) {{ival}} = -{{ival}};{{endif}}
{{endif}} } else {
// fall through to positive calculation for '%' switch (size) {
case 1: {{ival}} = digits[0]; break; {{for _size in (2, 3, 4)}}
{{for _size in (2, 3, 4)}} {{for _case in (-_size, _size)}}
{{for _case in (-_size, _size)}} case {{_case}}: {{if c_op != '%' or _case > 0}}
case {{_case}}: {{if c_op != '%' or _case > 0}} if (8 * sizeof(long) - 1 > {{_size}} * PyLong_SHIFT{{if op == 'TrueDivide'}} && {{_size-1}} * PyLong_SHIFT < 53{{endif}}) {
if (8 * sizeof(long) - 1 > {{_size}} * PyLong_SHIFT{{if op == 'TrueDivide'}} && {{_size-1}} * PyLong_SHIFT < 53{{endif}}) { {{ival}} = {{'-' if _case < 0 else ''}}(long) {{pylong_join(_size, 'digits')}};
{{ival}} = {{'-' if _case < 0 else ''}}(long) {{pylong_join(_size, 'digits')}}; break;
break; }
} {{endif}}
{{endif}} // in negative case, fall through to positive calculation for '%'
// in negative case, fall through to positive calculation for '%' // if size doesn't fit into a long anymore, fall through to default
// if size doesn't fit into a long anymore, fall through to default {{endfor}}
{{endfor}} {{endfor}}
{{endfor}} default: return PyLong_Type.tp_as_number->nb_{{slot_name}}(op1, op2);
default: return PyLong_Type.tp_as_number->nb_{{slot_name}}(op1, op2); }
} }
{{if c_op == '%'}} {{if c_op == '%'}}
x = a % b; x = a % b;
......
...@@ -297,23 +297,23 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { ...@@ -297,23 +297,23 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) {
#if CYTHON_USE_PYLONG_INTERNALS #if CYTHON_USE_PYLONG_INTERNALS
const digit* digits = ((PyLongObject*)b)->ob_digit; const digit* digits = ((PyLongObject*)b)->ob_digit;
const Py_ssize_t size = Py_SIZE(b); const Py_ssize_t size = Py_SIZE(b);
switch (size) { // handle most common case first to avoid indirect branch and optimise branch prediction
case 0: return 0; if (likely(__Pyx_sst_abs(size) <= 1)) {
case 1: return digits[0]; ival = likely(size) ? digits[0] : 0;
case -1: return -(sdigit) digits[0]; if (size == -1) ival = -ival;
default: return ival;
// move the substantially less common cases out of the way } else {
switch (size) { switch (size) {
{{for _size in (2, 3, 4)}} {{for _size in (2, 3, 4)}}
{{for _case in (_size, -_size)}} {{for _case in (_size, -_size)}}
case {{_case}}: case {{_case}}:
if (8 * sizeof(Py_ssize_t) > {{_size}} * PyLong_SHIFT) { if (8 * sizeof(Py_ssize_t) > {{_size}} * PyLong_SHIFT) {
return (Py_ssize_t) {{pylong_join(_size, 'digits', 'size_t')}}; return (Py_ssize_t) {{pylong_join(_size, 'digits', 'size_t')}};
} }
break; break;
{{endfor}} {{endfor}}
{{endfor}} {{endfor}}
} }
} }
#endif #endif
return PyLong_AsSsize_t(b); return PyLong_AsSsize_t(b);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment