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
* 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.
* Binary and/or/xor operations and modulus with small constant Python integers
......
......@@ -571,26 +571,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("")
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:
code.putln('#include "%s"' % filename)
code.putln("#ifndef Py_PYTHON_H")
......
......@@ -40,6 +40,10 @@
#define CYTHON_COMPILING_IN_CPYTHON 1
#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)
#define Py_OptimizeFlag 0
#endif
......
......@@ -448,7 +448,7 @@ static PyObject* __Pyx__PyNumber_PowerOf2(PyObject *two, PyObject *exp, PyObject
} else
#endif
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)) {
case 0: shiftby = 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
}
#endif
#if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3 && CYTHON_USE_PYLONG_INTERNALS
#if CYTHON_USE_PYLONG_INTERNALS
if (likely(PyLong_CheckExact({{pyval}}))) {
const long {{'a' if order == 'CObj' else 'b'}} = intval;
long x, {{ival}};
const Py_ssize_t size = Py_SIZE({{pyval}});
switch (size) {
case 0: {{ival}} = 0; break;
{{if c_op != '%'}}
case -1: {{ival}} = -(sdigit)((PyLongObject*){{pyval}})->ob_digit[0]; break;
{{else}}
case -1:
// fall through to positive calculation for '%'
{{endif}}
case -1: {{if c_op != '%'}}
{{ival}} = -(sdigit)((PyLongObject*){{pyval}})->ob_digit[0]; break;
{{endif}}
// fall through to positive calculation for '%'
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:
if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) {
{{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
default: return PyLong_Type.tp_as_number->nb_{{op.lower()}}(op1, op2);
}
{{if c_op == '%'}}
if (unlikely(size < 0)) {
x = (-a) % b;
if (x) x = b - x;
} else {
x = a % b;
x = a % b;
if (unlikely(size < 0) && x) {
x = b - x;
}
{{else}}
x = a {{c_op}} b;
......@@ -612,7 +614,7 @@ static PyObject* __Pyx_PyFloat_{{op}}{{order}}(PyObject *op1, PyObject *op2, dou
#endif
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}});
switch (size) {
case -1: {{fval}} = -(double)((PyLongObject*){{pyval}})->ob_digit[0]; break;
......
......@@ -721,7 +721,7 @@ static CYTHON_INLINE int __Pyx_PyByteArray_AppendObject(PyObject* bytearray, PyO
}
ival = (unsigned char) (PyString_AS_STRING(value)[0]);
} else
#else
#endif
#if CYTHON_USE_PYLONG_INTERNALS
if (likely(PyLong_CheckExact(value)) && likely(Py_SIZE(value) == 1 || Py_SIZE(value) == 0)) {
if (Py_SIZE(value) == 0) {
......@@ -731,7 +731,6 @@ static CYTHON_INLINE int __Pyx_PyByteArray_AppendObject(PyObject* bytearray, PyO
if (unlikely(ival > 255)) goto bad_range;
}
} else
#endif
#endif
{
// CPython calls PyNumber_Index() internally
......
......@@ -292,16 +292,21 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) {
}
#endif
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)) {
case -1: return -(sdigit)((PyLongObject*)b)->ob_digit[0];
case 0: return 0;
case 1: return ((PyLongObject*)b)->ob_digit[0];
case -1: return -(sdigit)((PyLongObject*)b)->ob_digit[0];
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;
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
return PyLong_AsSsize_t(b);
......@@ -522,10 +527,8 @@ static CYTHON_INLINE PyObject* {{TO_PY_FUNCTION}}({{TYPE}} value) {
/////////////// PyLongInternals ///////////////
#if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3
#if CYTHON_USE_PYLONG_INTERNALS
#if CYTHON_USE_PYLONG_INTERNALS
#include "longintrepr.h"
#endif
#endif
......@@ -555,19 +558,19 @@ static CYTHON_INLINE {{TYPE}} {{FROM_PY_FUNCTION}}(PyObject *x) {
#endif
if (likely(PyLong_Check(x))) {
if (is_unsigned) {
#if CYTHON_COMPILING_IN_CPYTHON
#if PY_MAJOR_VERSION >= 3 && CYTHON_USE_PYLONG_INTERNALS
#if CYTHON_USE_PYLONG_INTERNALS
switch (Py_SIZE(x)) {
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:
if ((8 * sizeof({{TYPE}}) > PyLong_SHIFT) && (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) {
__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;
}
#endif
#endif
#if CYTHON_COMPILING_IN_CPYTHON
if (unlikely(Py_SIZE(x) < 0)) {
goto raise_neg_overflow;
}
......@@ -578,15 +581,22 @@ static CYTHON_INLINE {{TYPE}} {{FROM_PY_FUNCTION}}(PyObject *x) {
__PYX_VERIFY_RETURN_INT({{TYPE}}, unsigned long long, PyLong_AsUnsignedLongLong(x))
}
} else {
#if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3 && CYTHON_USE_PYLONG_INTERNALS
// signed
#if CYTHON_USE_PYLONG_INTERNALS
switch (Py_SIZE(x)) {
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}}, digit, +(((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 2:
if ((8 * sizeof({{TYPE}}) > PyLong_SHIFT) && (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) {
__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;
}
......
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