Commit 0897f269 authored by Stefan Behnel's avatar Stefan Behnel

extend PyLong optimisations to larger negative numbers, enable it also in Py2.7

parent 89fec0ac
...@@ -15,6 +15,8 @@ Features added ...@@ -15,6 +15,8 @@ Features added
* Tracing is supported in ``nogil`` functions/sections and module init code. * Tracing is supported in ``nogil`` functions/sections and module init code.
* Optimisations for PyLong are enabled in Py2.7 (not only Py3.x).
* Adding/subtracting constant Python floats and small integers is faster. * Adding/subtracting constant Python floats and small integers is faster.
* Binary and/or/xor operations and modulus with small constant Python integers * Binary and/or/xor operations and modulus with small constant Python integers
......
...@@ -571,26 +571,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -571,26 +571,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("") code.putln("")
code.putln("#define PY_SSIZE_T_CLEAN") code.putln("#define PY_SSIZE_T_CLEAN")
# sizeof(PyLongObject.ob_digit[0]) may have been determined dynamically
# at compile time in CPython, in which case we can't know the correct
# storage size for an installed system. We can rely on it only if
# pyconfig.h defines it statically, i.e. if it was set by "configure".
# Once we include "Python.h", it will come up with its own idea about
# a suitable value, which may or may not match the real one.
code.putln("#ifndef CYTHON_USE_PYLONG_INTERNALS")
code.putln("#ifdef PYLONG_BITS_IN_DIGIT")
# assume it's an incorrect left-over
code.putln("#define CYTHON_USE_PYLONG_INTERNALS 0")
code.putln("#else")
code.putln('#include "pyconfig.h"')
code.putln("#ifdef PYLONG_BITS_IN_DIGIT")
code.putln("#define CYTHON_USE_PYLONG_INTERNALS 1")
code.putln("#else")
code.putln("#define CYTHON_USE_PYLONG_INTERNALS 0")
code.putln("#endif")
code.putln("#endif")
code.putln("#endif")
for filename in env.python_include_files: for filename in env.python_include_files:
code.putln('#include "%s"' % filename) code.putln('#include "%s"' % filename)
code.putln("#ifndef Py_PYTHON_H") code.putln("#ifndef Py_PYTHON_H")
......
...@@ -40,6 +40,10 @@ ...@@ -40,6 +40,10 @@
#define CYTHON_COMPILING_IN_CPYTHON 1 #define CYTHON_COMPILING_IN_CPYTHON 1
#endif #endif
#if !defined(CYTHON_USE_PYLONG_INTERNALS) && CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x02070000
#define CYTHON_USE_PYLONG_INTERNALS 1
#endif
#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x02070600 && !defined(Py_OptimizeFlag) #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x02070600 && !defined(Py_OptimizeFlag)
#define Py_OptimizeFlag 0 #define Py_OptimizeFlag 0
#endif #endif
......
...@@ -448,7 +448,7 @@ static PyObject* __Pyx__PyNumber_PowerOf2(PyObject *two, PyObject *exp, PyObject ...@@ -448,7 +448,7 @@ static PyObject* __Pyx__PyNumber_PowerOf2(PyObject *two, PyObject *exp, PyObject
} else } else
#endif #endif
if (likely(PyLong_CheckExact(exp))) { if (likely(PyLong_CheckExact(exp))) {
#if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3 && CYTHON_USE_PYLONG_INTERNALS #if CYTHON_USE_PYLONG_INTERNALS
switch (Py_SIZE(exp)) { switch (Py_SIZE(exp)) {
case 0: shiftby = 0; break; case 0: shiftby = 0; break;
case 1: shiftby = ((PyLongObject*)exp)->ob_digit[0]; break; case 1: shiftby = ((PyLongObject*)exp)->ob_digit[0]; break;
...@@ -528,21 +528,25 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO ...@@ -528,21 +528,25 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO
} }
#endif #endif
#if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3 && CYTHON_USE_PYLONG_INTERNALS #if CYTHON_USE_PYLONG_INTERNALS
if (likely(PyLong_CheckExact({{pyval}}))) { if (likely(PyLong_CheckExact({{pyval}}))) {
const long {{'a' if order == 'CObj' else 'b'}} = intval; const long {{'a' if order == 'CObj' else 'b'}} = intval;
long x, {{ival}}; long x, {{ival}};
const Py_ssize_t size = Py_SIZE({{pyval}}); const Py_ssize_t size = Py_SIZE({{pyval}});
switch (size) { switch (size) {
case 0: {{ival}} = 0; break; case 0: {{ival}} = 0; break;
{{if c_op != '%'}} case -1: {{if c_op != '%'}}
case -1: {{ival}} = -(sdigit)((PyLongObject*){{pyval}})->ob_digit[0]; break; {{ival}} = -(sdigit)((PyLongObject*){{pyval}})->ob_digit[0]; break;
{{else}} {{endif}}
case -1: // fall through to positive calculation for '%'
// fall through to positive calculation for '%'
{{endif}}
case 1: {{ival}} = ((PyLongObject*){{pyval}})->ob_digit[0]; break; case 1: {{ival}} = ((PyLongObject*){{pyval}})->ob_digit[0]; break;
case -2: case -2: {{if c_op != '%'}}
if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) {
{{ival}} = -(long) ((((unsigned long)((PyLongObject*){{pyval}})->ob_digit[1]) << PyLong_SHIFT) | ((PyLongObject*){{pyval}})->ob_digit[0]);
break;
}
{{endif}}
// fall through to positive calculation for '%'
case 2: case 2:
if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) {
{{ival}} = (long) ((((unsigned long)((PyLongObject*){{pyval}})->ob_digit[1]) << PyLong_SHIFT) | ((PyLongObject*){{pyval}})->ob_digit[0]); {{ival}} = (long) ((((unsigned long)((PyLongObject*){{pyval}})->ob_digit[1]) << PyLong_SHIFT) | ((PyLongObject*){{pyval}})->ob_digit[0]);
...@@ -552,11 +556,9 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO ...@@ -552,11 +556,9 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO
default: return PyLong_Type.tp_as_number->nb_{{op.lower()}}(op1, op2); default: return PyLong_Type.tp_as_number->nb_{{op.lower()}}(op1, op2);
} }
{{if c_op == '%'}} {{if c_op == '%'}}
if (unlikely(size < 0)) { x = a % b;
x = (-a) % b; if (unlikely(size < 0) && x) {
if (x) x = b - x; x = b - x;
} else {
x = a % b;
} }
{{else}} {{else}}
x = a {{c_op}} b; x = a {{c_op}} b;
...@@ -612,7 +614,7 @@ static PyObject* __Pyx_PyFloat_{{op}}{{order}}(PyObject *op1, PyObject *op2, dou ...@@ -612,7 +614,7 @@ static PyObject* __Pyx_PyFloat_{{op}}{{order}}(PyObject *op1, PyObject *op2, dou
#endif #endif
if (likely(PyLong_CheckExact({{pyval}}))) { if (likely(PyLong_CheckExact({{pyval}}))) {
#if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3 && CYTHON_USE_PYLONG_INTERNALS #if CYTHON_USE_PYLONG_INTERNALS
const Py_ssize_t size = Py_SIZE({{pyval}}); const Py_ssize_t size = Py_SIZE({{pyval}});
switch (size) { switch (size) {
case -1: {{fval}} = -(double)((PyLongObject*){{pyval}})->ob_digit[0]; break; case -1: {{fval}} = -(double)((PyLongObject*){{pyval}})->ob_digit[0]; break;
......
...@@ -721,7 +721,7 @@ static CYTHON_INLINE int __Pyx_PyByteArray_AppendObject(PyObject* bytearray, PyO ...@@ -721,7 +721,7 @@ static CYTHON_INLINE int __Pyx_PyByteArray_AppendObject(PyObject* bytearray, PyO
} }
ival = (unsigned char) (PyString_AS_STRING(value)[0]); ival = (unsigned char) (PyString_AS_STRING(value)[0]);
} else } else
#else #endif
#if CYTHON_USE_PYLONG_INTERNALS #if CYTHON_USE_PYLONG_INTERNALS
if (likely(PyLong_CheckExact(value)) && likely(Py_SIZE(value) == 1 || Py_SIZE(value) == 0)) { if (likely(PyLong_CheckExact(value)) && likely(Py_SIZE(value) == 1 || Py_SIZE(value) == 0)) {
if (Py_SIZE(value) == 0) { if (Py_SIZE(value) == 0) {
...@@ -731,7 +731,6 @@ static CYTHON_INLINE int __Pyx_PyByteArray_AppendObject(PyObject* bytearray, PyO ...@@ -731,7 +731,6 @@ static CYTHON_INLINE int __Pyx_PyByteArray_AppendObject(PyObject* bytearray, PyO
if (unlikely(ival > 255)) goto bad_range; if (unlikely(ival > 255)) goto bad_range;
} }
} else } else
#endif
#endif #endif
{ {
// CPython calls PyNumber_Index() internally // CPython calls PyNumber_Index() internally
......
...@@ -292,16 +292,21 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { ...@@ -292,16 +292,21 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) {
} }
#endif #endif
if (likely(PyLong_CheckExact(b))) { if (likely(PyLong_CheckExact(b))) {
#if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3 && CYTHON_USE_PYLONG_INTERNALS #if CYTHON_USE_PYLONG_INTERNALS
switch (Py_SIZE(b)) { switch (Py_SIZE(b)) {
case -1: return -(sdigit)((PyLongObject*)b)->ob_digit[0];
case 0: return 0; case 0: return 0;
case 1: return ((PyLongObject*)b)->ob_digit[0]; case 1: return ((PyLongObject*)b)->ob_digit[0];
case -1: return -(sdigit)((PyLongObject*)b)->ob_digit[0];
case 2: case 2:
if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) {
return (Py_ssize_t) ((((size_t)((PyLongObject*)b)->ob_digit[1]) << PyLong_SHIFT) | ((PyLongObject*)b)->ob_digit[0]); return (Py_ssize_t) ((((size_t)((PyLongObject*)b)->ob_digit[1]) << PyLong_SHIFT) | ((PyLongObject*)b)->ob_digit[0]);
} }
break; break;
case -2:
if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) {
return -(Py_ssize_t) ((((size_t)((PyLongObject*)b)->ob_digit[1]) << PyLong_SHIFT) | ((PyLongObject*)b)->ob_digit[0]);
}
break;
} }
#endif #endif
return PyLong_AsSsize_t(b); return PyLong_AsSsize_t(b);
...@@ -522,10 +527,8 @@ static CYTHON_INLINE PyObject* {{TO_PY_FUNCTION}}({{TYPE}} value) { ...@@ -522,10 +527,8 @@ static CYTHON_INLINE PyObject* {{TO_PY_FUNCTION}}({{TYPE}} value) {
/////////////// PyLongInternals /////////////// /////////////// PyLongInternals ///////////////
#if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3 #if CYTHON_USE_PYLONG_INTERNALS
#if CYTHON_USE_PYLONG_INTERNALS
#include "longintrepr.h" #include "longintrepr.h"
#endif
#endif #endif
...@@ -555,19 +558,19 @@ static CYTHON_INLINE {{TYPE}} {{FROM_PY_FUNCTION}}(PyObject *x) { ...@@ -555,19 +558,19 @@ static CYTHON_INLINE {{TYPE}} {{FROM_PY_FUNCTION}}(PyObject *x) {
#endif #endif
if (likely(PyLong_Check(x))) { if (likely(PyLong_Check(x))) {
if (is_unsigned) { if (is_unsigned) {
#if CYTHON_COMPILING_IN_CPYTHON #if CYTHON_USE_PYLONG_INTERNALS
#if PY_MAJOR_VERSION >= 3 && CYTHON_USE_PYLONG_INTERNALS
switch (Py_SIZE(x)) { switch (Py_SIZE(x)) {
case 0: return 0; case 0: return 0;
case 1: __PYX_VERIFY_RETURN_INT({{TYPE}}, digit, ((PyLongObject*)x)->ob_digit[0]); case 1: __PYX_VERIFY_RETURN_INT({{TYPE}}, digit, ((PyLongObject*)x)->ob_digit[0])
case 2: case 2:
if ((8 * sizeof({{TYPE}}) > PyLong_SHIFT) && (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { if ((8 * sizeof({{TYPE}}) > PyLong_SHIFT) && (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) {
__PYX_VERIFY_RETURN_INT({{TYPE}}, unsigned long, __PYX_VERIFY_RETURN_INT({{TYPE}}, unsigned long,
(((unsigned long)((PyLongObject*)x)->ob_digit[1]) << PyLong_SHIFT) | ((PyLongObject*)x)->ob_digit[0]); (((unsigned long)((PyLongObject*)x)->ob_digit[1]) << PyLong_SHIFT) | ((PyLongObject*)x)->ob_digit[0])
} }
break; break;
} }
#endif #endif
#if CYTHON_COMPILING_IN_CPYTHON
if (unlikely(Py_SIZE(x) < 0)) { if (unlikely(Py_SIZE(x) < 0)) {
goto raise_neg_overflow; goto raise_neg_overflow;
} }
...@@ -578,15 +581,22 @@ static CYTHON_INLINE {{TYPE}} {{FROM_PY_FUNCTION}}(PyObject *x) { ...@@ -578,15 +581,22 @@ static CYTHON_INLINE {{TYPE}} {{FROM_PY_FUNCTION}}(PyObject *x) {
__PYX_VERIFY_RETURN_INT({{TYPE}}, unsigned long long, PyLong_AsUnsignedLongLong(x)) __PYX_VERIFY_RETURN_INT({{TYPE}}, unsigned long long, PyLong_AsUnsignedLongLong(x))
} }
} else { } else {
#if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3 && CYTHON_USE_PYLONG_INTERNALS // signed
#if CYTHON_USE_PYLONG_INTERNALS
switch (Py_SIZE(x)) { switch (Py_SIZE(x)) {
case 0: return 0; case 0: return 0;
case -1: __PYX_VERIFY_RETURN_INT({{TYPE}}, sdigit, -(sdigit) ((PyLongObject*)x)->ob_digit[0]); case -1: __PYX_VERIFY_RETURN_INT({{TYPE}}, sdigit, -(sdigit) ((PyLongObject*)x)->ob_digit[0])
case 1: __PYX_VERIFY_RETURN_INT({{TYPE}}, digit, +(((PyLongObject*)x)->ob_digit[0])); case 1: __PYX_VERIFY_RETURN_INT({{TYPE}}, digit, +(((PyLongObject*)x)->ob_digit[0]))
case 2: case 2:
if ((8 * sizeof({{TYPE}}) > PyLong_SHIFT) && (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { if ((8 * sizeof({{TYPE}}) > PyLong_SHIFT) && (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) {
__PYX_VERIFY_RETURN_INT({{TYPE}}, unsigned long, __PYX_VERIFY_RETURN_INT({{TYPE}}, unsigned long,
(((unsigned long)((PyLongObject*)x)->ob_digit[1]) << PyLong_SHIFT) | ((PyLongObject*)x)->ob_digit[0]); (((unsigned long)((PyLongObject*)x)->ob_digit[1]) << PyLong_SHIFT) | ((PyLongObject*)x)->ob_digit[0])
}
break;
case -2:
if ((8 * sizeof({{TYPE}}) > 2 * PyLong_SHIFT) && (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) {
__PYX_VERIFY_RETURN_INT({{TYPE}}, long,
-(long) (((unsigned long)((PyLongObject*)x)->ob_digit[1]) << PyLong_SHIFT) | ((PyLongObject*)x)->ob_digit[0])
} }
break; break;
} }
......
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