diff --git a/Include/graminit.h b/Include/graminit.h diff --git a/Include/longintrepr.h b/Include/longintrepr.h diff --git a/Objects/longobject.c b/Objects/longobject.c index ecc71bb..fd00bbd 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -164,6 +164,7 @@ _PyLong_Copy(PyLongObject *src) result = _PyLong_New(i); if (result != NULL) { Py_SIZE(result) = Py_SIZE(src); + /* FIXME: use memcpy() */ while (--i >= 0) result->ob_digit[i] = src->ob_digit[i]; } @@ -228,6 +229,11 @@ PyLong_FromLong(long ival) digit *p = v->ob_digit; Py_SIZE(v) = ndigits*sign; t = abs_ival; + /* unroll the loop: we have at least two digits */ + *p++ = (digit)(t & PyLong_MASK); + t >>= PyLong_SHIFT; + *p++ = (digit)(t & PyLong_MASK); + t >>= PyLong_SHIFT; while (t) { *p++ = (digit)(t & PyLong_MASK); t >>= PyLong_SHIFT; @@ -2852,6 +2858,13 @@ long_mul(PyLongObject *a, PyLongObject *b) int sign; PyLongObject *v; sign = Py_SIZE(a) * Py_SIZE(b); + if (!(a->ob_digit[0] >> 15) && !(b->ob_digit[0] >> 15)) { + sdigit product = a->ob_digit[0]; + product *= b->ob_digit[0]; + if (sign < 0) + product = -product; + return PyLong_FromLong(product); + } if (sign == 0) return PyLong_FromLong(0L); absv = (twodigits)a->ob_digit[0] * b->ob_digit[0]; @@ -2953,6 +2966,17 @@ long_div(PyObject *a, PyObject *b) PyLongObject *div; CHECK_BINOP(a, b); + + /* fast path for single-digit divison */ + if (ABS(Py_SIZE(a)) <= 1 && ABS(Py_SIZE(b)) <= 1) { + sdigit aa = MEDIUM_VALUE((PyLongObject*)a); + sdigit bb = MEDIUM_VALUE((PyLongObject*)b); + sdigit q = aa / bb; + if (((aa < 0) != (bb < 0)) && (aa % bb != 0)) + q -= 1; + return PyLong_FromLong(q); + } + if (l_divmod((PyLongObject*)a, (PyLongObject*)b, &div, NULL) < 0) div = NULL; return (PyObject *)div; @@ -3008,6 +3032,16 @@ long_mod(PyObject *a, PyObject *b) CHECK_BINOP(a, b); + /* fast path for single-digit modulo */ + if (ABS(Py_SIZE(a)) <= 1 && ABS(Py_SIZE(b)) <= 1) { + sdigit aa = MEDIUM_VALUE((PyLongObject*)a); + sdigit bb = MEDIUM_VALUE((PyLongObject*)b); + sdigit r = aa % bb; + if (r && (aa < 0) != (bb < 0)) + r += bb; + return PyLong_FromLong(r); + } + if (l_divmod((PyLongObject*)a, (PyLongObject*)b, NULL, &mod) < 0) mod = NULL; return (PyObject *)mod; @@ -3228,7 +3262,7 @@ long_invert(PyLongObject *v) PyLongObject *x; PyLongObject *w; if (ABS(Py_SIZE(v)) <=1) - return PyLong_FromLong(-(MEDIUM_VALUE(v)+1)); + return PyLong_FromLong(~MEDIUM_VALUE(v)); w = (PyLongObject *)PyLong_FromLong(1L); if (w == NULL) return NULL; @@ -3339,6 +3373,8 @@ long_lshift(PyObject *v, PyObject *w) CHECK_BINOP(a, b); + /* FIXME: hacks small ints */ + shiftby = PyLong_AsLong((PyObject *)b); if (shiftby == -1L && PyErr_Occurred()) goto lshift_error; @@ -3397,6 +3433,18 @@ long_bitwise(PyLongObject *a, digit diga, digb; PyObject *v; + if (ABS(Py_SIZE(a)) <= 1 && ABS(Py_SIZE(b)) <= 1) { + sdigit aa = MEDIUM_VALUE((PyLongObject*)a); + sdigit bb = MEDIUM_VALUE((PyLongObject*)b); + sdigit r; + switch (op) { + case '^': r = aa ^ bb; break; + case '&': r = aa & bb; break; + case '|': r = aa | bb; break; + } + return PyLong_FromLong(r); + } + if (Py_SIZE(a) < 0) { a = (PyLongObject *) long_invert(a); if (a == NULL) diff --git a/Python/graminit.c b/Python/graminit.c