From da57f0b369f62a07715c5f7e00684768794a273b Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 18 Aug 2021 15:07:17 +0100 Subject: [PATCH 01/17] Streamline binary operations and creating new int objects for common case of single 'digit'. --- Objects/longobject.c | 144 ++++++++++++++++++++++++++----------------- 1 file changed, 88 insertions(+), 56 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index d9127b31fd4867..87b076df69519f 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -26,15 +26,18 @@ class int "PyObject *" "&PyLong_Type" _Py_IDENTIFIER(little); _Py_IDENTIFIER(big); +/* Is this PyLong of size 1, 0 or -1? */ +#define IS_MEDIUM_VALUE(x) (((size_t)Py_SIZE(x)) + 1 < 3) + /* convert a PyLong of size 1, 0 or -1 to an sdigit */ -#define MEDIUM_VALUE(x) (assert(-1 <= Py_SIZE(x) && Py_SIZE(x) <= 1), \ - Py_SIZE(x) < 0 ? -(sdigit)(x)->ob_digit[0] : \ - (Py_SIZE(x) == 0 ? (sdigit)0 : \ - (sdigit)(x)->ob_digit[0])) +#define MEDIUM_VALUE(x) (assert(IS_MEDIUM_VALUE(x)), \ + ((sdigit)(Py_SIZE(x) * (x)->ob_digit[0]))) #define IS_SMALL_INT(ival) (-NSMALLNEGINTS <= (ival) && (ival) < NSMALLPOSINTS) #define IS_SMALL_UINT(ival) ((ival) < NSMALLPOSINTS) +#define IS_MEDIUM_INT(utype, x) (((utype)x)+PyLong_MASK <= 2*PyLong_MASK) + static PyObject * get_small_int(sdigit ival) { @@ -47,7 +50,7 @@ get_small_int(sdigit ival) static PyLongObject * maybe_small_long(PyLongObject *v) { - if (v && Py_ABS(Py_SIZE(v)) <= 1) { + if (v && IS_MEDIUM_VALUE(v)) { sdigit ival = MEDIUM_VALUE(v); if (IS_SMALL_INT(ival)) { Py_DECREF(v); @@ -167,20 +170,34 @@ _PyLong_Copy(PyLongObject *src) return (PyObject *)result; } -/* Create a new int object from a C long int */ +static PyObject * +PyLong_FromMedium(sdigit x) +{ + assert(!IS_SMALL_INT(x)); + assert(x > (sdigit)-PyLong_BASE); + assert(x < (sdigit)PyLong_BASE); + /* We could use a freelist here */ + PyLongObject *v = PyObject_Malloc(sizeof(PyLongObject)); + if (v == NULL) { + PyErr_NoMemory(); + return NULL; + } + Py_ssize_t sign = x < 0 ? -1: 1; + digit abs_x = x < 0 ? -x : x; + _PyObject_InitVar((PyVarObject*)v, &PyLong_Type, sign); + v->ob_digit[0] = abs_x; + return (PyObject*)v; +} -PyObject * -PyLong_FromLong(long ival) +static PyObject * +PyLong_FromLarge(long ival) { PyLongObject *v; unsigned long abs_ival; unsigned long t; /* unsigned so >> doesn't propagate sign bit */ int ndigits = 0; int sign; - - if (IS_SMALL_INT(ival)) { - return get_small_int((sdigit)ival); - } + assert(!IS_MEDIUM_INT(unsigned long, ival)); if (ival < 0) { /* negate: can't write this as abs_ival = -ival since that @@ -190,36 +207,9 @@ PyLong_FromLong(long ival) } else { abs_ival = (unsigned long)ival; - sign = ival == 0 ? 0 : 1; - } - - /* Fast path for single-digit ints */ - if (!(abs_ival >> PyLong_SHIFT)) { - v = _PyLong_New(1); - if (v) { - Py_SET_SIZE(v, sign); - v->ob_digit[0] = Py_SAFE_DOWNCAST( - abs_ival, unsigned long, digit); - } - return (PyObject*)v; - } - -#if PyLong_SHIFT==15 - /* 2 digits */ - if (!(abs_ival >> 2*PyLong_SHIFT)) { - v = _PyLong_New(2); - if (v) { - Py_SET_SIZE(v, 2 * sign); - v->ob_digit[0] = Py_SAFE_DOWNCAST( - abs_ival & PyLong_MASK, unsigned long, digit); - v->ob_digit[1] = Py_SAFE_DOWNCAST( - abs_ival >> PyLong_SHIFT, unsigned long, digit); - } - return (PyObject*)v; + sign = 1; } -#endif - - /* Larger numbers: loop to determine number of digits */ + /* Loop to determine number of digits */ t = abs_ival; while (t) { ++ndigits; @@ -239,6 +229,39 @@ PyLong_FromLong(long ival) return (PyObject *)v; } +/* Convert result of add/subtract of medium values + * to a PyLong. + */ +static inline PyObject * +PyLong_FromDigitPlusOneBit(sdigit x) +{ + if (IS_SMALL_INT(x)) { + return get_small_int(x); + } + assert(x != 0); + if (IS_MEDIUM_INT(digit, x)) { + return PyLong_FromMedium(x); + } + return PyLong_FromLarge(x); +} + +/* Create a new int object from a C long int */ + +PyObject * +PyLong_FromLong(long ival) +{ + + if (IS_SMALL_INT(ival)) { + return get_small_int((sdigit)ival); + } + + assert(ival != 0); + if (IS_MEDIUM_INT(unsigned long, ival)) { + return PyLong_FromMedium(ival); + } + return PyLong_FromLarge(ival); +} + #define PYLONG_FROM_UINT(INT_TYPE, ival) \ do { \ if (IS_SMALL_UINT(ival)) { \ @@ -2860,7 +2883,7 @@ PyLong_AsDouble(PyObject *v) PyErr_SetString(PyExc_TypeError, "an integer is required"); return -1.0; } - if (Py_ABS(Py_SIZE(v)) <= 1) { + if (IS_MEDIUM_VALUE(v)) { /* Fast path; single digit long (31 bits) will cast safely to double. This improves performance of FP/long operations by 20%. @@ -3067,7 +3090,7 @@ long_add(PyLongObject *a, PyLongObject *b) CHECK_BINOP(a, b); - if (Py_ABS(Py_SIZE(a)) <= 1 && Py_ABS(Py_SIZE(b)) <= 1) { + if (IS_MEDIUM_VALUE(a) && IS_MEDIUM_VALUE(b)) { return PyLong_FromLong(MEDIUM_VALUE(a) + MEDIUM_VALUE(b)); } if (Py_SIZE(a) < 0) { @@ -3101,8 +3124,8 @@ long_sub(PyLongObject *a, PyLongObject *b) CHECK_BINOP(a, b); - if (Py_ABS(Py_SIZE(a)) <= 1 && Py_ABS(Py_SIZE(b)) <= 1) { - return PyLong_FromLong(MEDIUM_VALUE(a) - MEDIUM_VALUE(b)); + if (IS_MEDIUM_VALUE(a) && IS_MEDIUM_VALUE(b)) { + return PyLong_FromDigitPlusOneBit(MEDIUM_VALUE(a) - MEDIUM_VALUE(b)); } if (Py_SIZE(a) < 0) { if (Py_SIZE(b) < 0) { @@ -3536,7 +3559,7 @@ long_mul(PyLongObject *a, PyLongObject *b) CHECK_BINOP(a, b); /* fast path for single-digit multiplication */ - if (Py_ABS(Py_SIZE(a)) <= 1 && Py_ABS(Py_SIZE(b)) <= 1) { + if (IS_MEDIUM_VALUE(a) && IS_MEDIUM_VALUE(b)) { stwodigits v = (stwodigits)(MEDIUM_VALUE(a)) * MEDIUM_VALUE(b); return PyLong_FromLongLong((long long)v); } @@ -4358,7 +4381,7 @@ static PyObject * long_neg(PyLongObject *v) { PyLongObject *z; - if (Py_ABS(Py_SIZE(v)) <= 1) + if (IS_MEDIUM_VALUE(v)) return PyLong_FromLong(-MEDIUM_VALUE(v)); z = (PyLongObject *)_PyLong_Copy(v); if (z != NULL) @@ -4704,28 +4727,37 @@ long_bitwise(PyLongObject *a, static PyObject * long_and(PyObject *a, PyObject *b) { - PyObject *c; CHECK_BINOP(a, b); - c = long_bitwise((PyLongObject*)a, '&', (PyLongObject*)b); - return c; + PyLongObject *x = (PyLongObject*)a; + PyLongObject *y = (PyLongObject*)b; + if (IS_MEDIUM_VALUE(x) && IS_MEDIUM_VALUE(y)) { + return PyLong_FromDigitPlusOneBit(MEDIUM_VALUE(x) & MEDIUM_VALUE(y)); + } + return long_bitwise(x, '&', y); } static PyObject * long_xor(PyObject *a, PyObject *b) { - PyObject *c; CHECK_BINOP(a, b); - c = long_bitwise((PyLongObject*)a, '^', (PyLongObject*)b); - return c; + PyLongObject *x = (PyLongObject*)a; + PyLongObject *y = (PyLongObject*)b; + if (IS_MEDIUM_VALUE(x) && IS_MEDIUM_VALUE(y)) { + return PyLong_FromDigitPlusOneBit(MEDIUM_VALUE(x) ^ MEDIUM_VALUE(y)); + } + return long_bitwise(x, '^', y); } static PyObject * long_or(PyObject *a, PyObject *b) { - PyObject *c; CHECK_BINOP(a, b); - c = long_bitwise((PyLongObject*)a, '|', (PyLongObject*)b); - return c; + PyLongObject *x = (PyLongObject*)a; + PyLongObject *y = (PyLongObject*)b; + if (IS_MEDIUM_VALUE(x) && IS_MEDIUM_VALUE(y)) { + return PyLong_FromDigitPlusOneBit(MEDIUM_VALUE(x) | MEDIUM_VALUE(y)); + } + return long_bitwise(x, '|', y); } static PyObject * From 0533a9f891f0c54616eef369239cd6554972816f Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 19 Aug 2021 14:39:12 +0100 Subject: [PATCH 02/17] Make sure that all ints, even internal, temporary ones, have at least one digit. --- Objects/longobject.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index 87b076df69519f..4d161a9baa60f8 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -124,18 +124,21 @@ PyLongObject * _PyLong_New(Py_ssize_t size) { PyLongObject *result; - /* Number of bytes needed is: offsetof(PyLongObject, ob_digit) + - sizeof(digit)*size. Previous incarnations of this code used - sizeof(PyVarObject) instead of the offsetof, but this risks being - incorrect in the presence of padding between the PyVarObject header - and the digits. */ if (size > (Py_ssize_t)MAX_LONG_DIGITS) { PyErr_SetString(PyExc_OverflowError, "too many digits in integer"); return NULL; } + /* Fast operations for single digit integers (including zero) + * assume that there is always at least one digit present. */ + Py_ssize_t ndigits = size ? size : 1; + /* Number of bytes needed is: offsetof(PyLongObject, ob_digit) + + sizeof(digit)*size. Previous incarnations of this code used + sizeof(PyVarObject) instead of the offsetof, but this risks being + incorrect in the presence of padding between the PyVarObject header + and the digits. */ result = PyObject_Malloc(offsetof(PyLongObject, ob_digit) + - size*sizeof(digit)); + ndigits*sizeof(digit)); if (!result) { PyErr_NoMemory(); return NULL; From 9349daa9b9d763a2d3114f7d4ae30254033716d6 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 19 Aug 2021 15:07:56 +0100 Subject: [PATCH 03/17] Readability improvements as suggested by Victor Stinner. --- Objects/longobject.c | 56 +++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index 4d161a9baa60f8..d95b1a2cd3aba3 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -29,14 +29,18 @@ _Py_IDENTIFIER(big); /* Is this PyLong of size 1, 0 or -1? */ #define IS_MEDIUM_VALUE(x) (((size_t)Py_SIZE(x)) + 1 < 3) -/* convert a PyLong of size 1, 0 or -1 to an sdigit */ -#define MEDIUM_VALUE(x) (assert(IS_MEDIUM_VALUE(x)), \ - ((sdigit)(Py_SIZE(x) * (x)->ob_digit[0]))) +/* convert a PyLong of size 1, 0 or -1 to a C integer */ +static inline sdigit +medium_value(PyLongObject *x) +{ + assert(IS_MEDIUM_VALUE(x)); + return Py_SIZE(x) * x->ob_digit[0]; +} #define IS_SMALL_INT(ival) (-NSMALLNEGINTS <= (ival) && (ival) < NSMALLPOSINTS) #define IS_SMALL_UINT(ival) ((ival) < NSMALLPOSINTS) -#define IS_MEDIUM_INT(utype, x) (((utype)x)+PyLong_MASK <= 2*PyLong_MASK) +#define IS_MEDIUM_INT(x) (((unsigned long)x)+PyLong_MASK <= 2*PyLong_MASK) static PyObject * get_small_int(sdigit ival) @@ -51,7 +55,7 @@ static PyLongObject * maybe_small_long(PyLongObject *v) { if (v && IS_MEDIUM_VALUE(v)) { - sdigit ival = MEDIUM_VALUE(v); + long ival = medium_value(v); if (IS_SMALL_INT(ival)) { Py_DECREF(v); return (PyLongObject *)get_small_int(ival); @@ -73,7 +77,7 @@ _PyLong_Negate(PyLongObject **x_p) return; } - *x_p = (PyLongObject *)PyLong_FromLong(-MEDIUM_VALUE(x)); + *x_p = (PyLongObject *)PyLong_FromLong(-medium_value(x)); Py_DECREF(x); } @@ -158,7 +162,7 @@ _PyLong_Copy(PyLongObject *src) if (i < 0) i = -(i); if (i < 2) { - sdigit ival = MEDIUM_VALUE(src); + sdigit ival = medium_value(src); if (IS_SMALL_INT(ival)) { return get_small_int(ival); } @@ -177,8 +181,7 @@ static PyObject * PyLong_FromMedium(sdigit x) { assert(!IS_SMALL_INT(x)); - assert(x > (sdigit)-PyLong_BASE); - assert(x < (sdigit)PyLong_BASE); + assert(IS_MEDIUM_INT(x)); /* We could use a freelist here */ PyLongObject *v = PyObject_Malloc(sizeof(PyLongObject)); if (v == NULL) { @@ -193,14 +196,14 @@ PyLong_FromMedium(sdigit x) } static PyObject * -PyLong_FromLarge(long ival) +_PyLong_FromLarge(long ival) { PyLongObject *v; unsigned long abs_ival; unsigned long t; /* unsigned so >> doesn't propagate sign bit */ int ndigits = 0; int sign; - assert(!IS_MEDIUM_INT(unsigned long, ival)); + assert(!IS_MEDIUM_INT(ival)); if (ival < 0) { /* negate: can't write this as abs_ival = -ival since that @@ -236,16 +239,16 @@ PyLong_FromLarge(long ival) * to a PyLong. */ static inline PyObject * -PyLong_FromDigitPlusOneBit(sdigit x) +_PyLong_FromSDigit(sdigit x) { if (IS_SMALL_INT(x)) { return get_small_int(x); } assert(x != 0); - if (IS_MEDIUM_INT(digit, x)) { + if (IS_MEDIUM_INT(x)) { return PyLong_FromMedium(x); } - return PyLong_FromLarge(x); + return _PyLong_FromLarge(x); } /* Create a new int object from a C long int */ @@ -253,16 +256,15 @@ PyLong_FromDigitPlusOneBit(sdigit x) PyObject * PyLong_FromLong(long ival) { - if (IS_SMALL_INT(ival)) { return get_small_int((sdigit)ival); } assert(ival != 0); - if (IS_MEDIUM_INT(unsigned long, ival)) { + if (IS_MEDIUM_INT(ival)) { return PyLong_FromMedium(ival); } - return PyLong_FromLarge(ival); + return _PyLong_FromLarge(ival); } #define PYLONG_FROM_UINT(INT_TYPE, ival) \ @@ -2891,7 +2893,7 @@ PyLong_AsDouble(PyObject *v) to double. This improves performance of FP/long operations by 20%. */ - return (double)MEDIUM_VALUE((PyLongObject *)v); + return (double)medium_value((PyLongObject *)v); } x = _PyLong_Frexp((PyLongObject *)v, &exponent); if ((x == -1.0 && PyErr_Occurred()) || exponent > DBL_MAX_EXP) { @@ -3094,7 +3096,7 @@ long_add(PyLongObject *a, PyLongObject *b) CHECK_BINOP(a, b); if (IS_MEDIUM_VALUE(a) && IS_MEDIUM_VALUE(b)) { - return PyLong_FromLong(MEDIUM_VALUE(a) + MEDIUM_VALUE(b)); + return PyLong_FromLong(medium_value(a) + medium_value(b)); } if (Py_SIZE(a) < 0) { if (Py_SIZE(b) < 0) { @@ -3128,7 +3130,7 @@ long_sub(PyLongObject *a, PyLongObject *b) CHECK_BINOP(a, b); if (IS_MEDIUM_VALUE(a) && IS_MEDIUM_VALUE(b)) { - return PyLong_FromDigitPlusOneBit(MEDIUM_VALUE(a) - MEDIUM_VALUE(b)); + return _PyLong_FromSDigit(medium_value(a) - medium_value(b)); } if (Py_SIZE(a) < 0) { if (Py_SIZE(b) < 0) { @@ -3563,7 +3565,7 @@ long_mul(PyLongObject *a, PyLongObject *b) /* fast path for single-digit multiplication */ if (IS_MEDIUM_VALUE(a) && IS_MEDIUM_VALUE(b)) { - stwodigits v = (stwodigits)(MEDIUM_VALUE(a)) * MEDIUM_VALUE(b); + stwodigits v = (stwodigits)(medium_value(a)) * medium_value(b); return PyLong_FromLongLong((long long)v); } @@ -4369,8 +4371,8 @@ long_invert(PyLongObject *v) { /* Implement ~x as -(x+1) */ PyLongObject *x; - if (Py_ABS(Py_SIZE(v)) <=1) - return PyLong_FromLong(-(MEDIUM_VALUE(v)+1)); + if (IS_MEDIUM_VALUE(v)) + return PyLong_FromLong(-(medium_value(v)+1)); x = (PyLongObject *) long_add(v, (PyLongObject *)_PyLong_GetOne()); if (x == NULL) return NULL; @@ -4385,7 +4387,7 @@ long_neg(PyLongObject *v) { PyLongObject *z; if (IS_MEDIUM_VALUE(v)) - return PyLong_FromLong(-MEDIUM_VALUE(v)); + return PyLong_FromLong(-medium_value(v)); z = (PyLongObject *)_PyLong_Copy(v); if (z != NULL) Py_SET_SIZE(z, -(Py_SIZE(v))); @@ -4734,7 +4736,7 @@ long_and(PyObject *a, PyObject *b) PyLongObject *x = (PyLongObject*)a; PyLongObject *y = (PyLongObject*)b; if (IS_MEDIUM_VALUE(x) && IS_MEDIUM_VALUE(y)) { - return PyLong_FromDigitPlusOneBit(MEDIUM_VALUE(x) & MEDIUM_VALUE(y)); + return _PyLong_FromSDigit(medium_value(x) & medium_value(y)); } return long_bitwise(x, '&', y); } @@ -4746,7 +4748,7 @@ long_xor(PyObject *a, PyObject *b) PyLongObject *x = (PyLongObject*)a; PyLongObject *y = (PyLongObject*)b; if (IS_MEDIUM_VALUE(x) && IS_MEDIUM_VALUE(y)) { - return PyLong_FromDigitPlusOneBit(MEDIUM_VALUE(x) ^ MEDIUM_VALUE(y)); + return _PyLong_FromSDigit(medium_value(x) ^ medium_value(y)); } return long_bitwise(x, '^', y); } @@ -4758,7 +4760,7 @@ long_or(PyObject *a, PyObject *b) PyLongObject *x = (PyLongObject*)a; PyLongObject *y = (PyLongObject*)b; if (IS_MEDIUM_VALUE(x) && IS_MEDIUM_VALUE(y)) { - return PyLong_FromDigitPlusOneBit(MEDIUM_VALUE(x) | MEDIUM_VALUE(y)); + return _PyLong_FromSDigit(medium_value(x) | medium_value(y)); } return long_bitwise(x, '|', y); } From 96496e256d87dba6e4554642e445885fd4799af0 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 19 Aug 2021 15:44:57 +0100 Subject: [PATCH 04/17] Prefix private function name with _ --- Objects/longobject.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index d95b1a2cd3aba3..c38373d1de4db2 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -178,7 +178,7 @@ _PyLong_Copy(PyLongObject *src) } static PyObject * -PyLong_FromMedium(sdigit x) +_PyLong_FromMedium(sdigit x) { assert(!IS_SMALL_INT(x)); assert(IS_MEDIUM_INT(x)); @@ -246,7 +246,7 @@ _PyLong_FromSDigit(sdigit x) } assert(x != 0); if (IS_MEDIUM_INT(x)) { - return PyLong_FromMedium(x); + return _PyLong_FromMedium(x); } return _PyLong_FromLarge(x); } @@ -262,7 +262,7 @@ PyLong_FromLong(long ival) assert(ival != 0); if (IS_MEDIUM_INT(ival)) { - return PyLong_FromMedium(ival); + return _PyLong_FromMedium(ival); } return _PyLong_FromLarge(ival); } From 5e4aad51ed94127100029d032d866445e0057037 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 19 Aug 2021 21:16:42 +0100 Subject: [PATCH 05/17] Reduce the number of casts. --- Objects/longobject.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index c38373d1de4db2..10ab6e7e0987de 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -27,14 +27,14 @@ _Py_IDENTIFIER(little); _Py_IDENTIFIER(big); /* Is this PyLong of size 1, 0 or -1? */ -#define IS_MEDIUM_VALUE(x) (((size_t)Py_SIZE(x)) + 1 < 3) +#define IS_MEDIUM_VALUE(x) (((size_t)Py_SIZE(x)) + 1U < 3U) /* convert a PyLong of size 1, 0 or -1 to a C integer */ -static inline sdigit +static inline stwodigits medium_value(PyLongObject *x) { assert(IS_MEDIUM_VALUE(x)); - return Py_SIZE(x) * x->ob_digit[0]; + return ((stwodigits)Py_SIZE(x)) * x->ob_digit[0]; } #define IS_SMALL_INT(ival) (-NSMALLNEGINTS <= (ival) && (ival) < NSMALLPOSINTS) @@ -55,7 +55,7 @@ static PyLongObject * maybe_small_long(PyLongObject *v) { if (v && IS_MEDIUM_VALUE(v)) { - long ival = medium_value(v); + sdigit ival = medium_value(v); if (IS_SMALL_INT(ival)) { Py_DECREF(v); return (PyLongObject *)get_small_int(ival); @@ -3565,7 +3565,7 @@ long_mul(PyLongObject *a, PyLongObject *b) /* fast path for single-digit multiplication */ if (IS_MEDIUM_VALUE(a) && IS_MEDIUM_VALUE(b)) { - stwodigits v = (stwodigits)(medium_value(a)) * medium_value(b); + stwodigits v = medium_value(a) * medium_value(b); return PyLong_FromLongLong((long long)v); } From 59ba47614f136ab0a68660ecd33a3a62c38c44d6 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 19 Aug 2021 22:56:07 +0100 Subject: [PATCH 06/17] Avoid casting away top bits. --- Objects/longobject.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index 10ab6e7e0987de..b7179fec137129 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -40,7 +40,7 @@ medium_value(PyLongObject *x) #define IS_SMALL_INT(ival) (-NSMALLNEGINTS <= (ival) && (ival) < NSMALLPOSINTS) #define IS_SMALL_UINT(ival) ((ival) < NSMALLPOSINTS) -#define IS_MEDIUM_INT(x) (((unsigned long)x)+PyLong_MASK <= 2*PyLong_MASK) +#define IS_MEDIUM_INT(x) (((twodigits)x)+PyLong_MASK <= 2*PyLong_MASK) static PyObject * get_small_int(sdigit ival) @@ -239,7 +239,7 @@ _PyLong_FromLarge(long ival) * to a PyLong. */ static inline PyObject * -_PyLong_FromSDigit(sdigit x) +_PyLong_FromSDigit(stwodigits x) { if (IS_SMALL_INT(x)) { return get_small_int(x); From 0d3ca1d8e7dc06ff0c273861b1b97ef2bd604bd5 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 20 Aug 2021 11:04:55 +0100 Subject: [PATCH 07/17] Streamline integer negation and invert a bit. Suggested by Mark Dickinson. --- Objects/longobject.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index b7179fec137129..e89eb654467149 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -4372,7 +4372,7 @@ long_invert(PyLongObject *v) /* Implement ~x as -(x+1) */ PyLongObject *x; if (IS_MEDIUM_VALUE(v)) - return PyLong_FromLong(-(medium_value(v)+1)); + return _PyLong_FromSDigit(~medium_value(v)); x = (PyLongObject *) long_add(v, (PyLongObject *)_PyLong_GetOne()); if (x == NULL) return NULL; @@ -4387,7 +4387,7 @@ long_neg(PyLongObject *v) { PyLongObject *z; if (IS_MEDIUM_VALUE(v)) - return PyLong_FromLong(-medium_value(v)); + return _PyLong_FromSDigit(-medium_value(v)); z = (PyLongObject *)_PyLong_Copy(v); if (z != NULL) Py_SET_SIZE(z, -(Py_SIZE(v))); From c73333ba8d916cb7c2afeb573384fda62f18a53e Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 20 Aug 2021 11:25:36 +0100 Subject: [PATCH 08/17] Clarify comment and internal function name. Remove a bit of redundant code. --- Objects/longobject.c | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index e89eb654467149..63b11629c549b4 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -235,11 +235,9 @@ _PyLong_FromLarge(long ival) return (PyObject *)v; } -/* Convert result of add/subtract of medium values - * to a PyLong. - */ +/* Create a new int object from a C word-sized int */ static inline PyObject * -_PyLong_FromSDigit(stwodigits x) +_PyLong_FromSTwoDigits(stwodigits x) { if (IS_SMALL_INT(x)) { return get_small_int(x); @@ -252,19 +250,11 @@ _PyLong_FromSDigit(stwodigits x) } /* Create a new int object from a C long int */ - PyObject * PyLong_FromLong(long ival) { - if (IS_SMALL_INT(ival)) { - return get_small_int((sdigit)ival); - } - - assert(ival != 0); - if (IS_MEDIUM_INT(ival)) { - return _PyLong_FromMedium(ival); - } - return _PyLong_FromLarge(ival); + Py_BUILD_ASSERT(sizeof(stwodigits) >= sizeof(long)); + return _PyLong_FromSTwoDigits(ival); } #define PYLONG_FROM_UINT(INT_TYPE, ival) \ @@ -3130,7 +3120,7 @@ long_sub(PyLongObject *a, PyLongObject *b) CHECK_BINOP(a, b); if (IS_MEDIUM_VALUE(a) && IS_MEDIUM_VALUE(b)) { - return _PyLong_FromSDigit(medium_value(a) - medium_value(b)); + return _PyLong_FromSTwoDigits(medium_value(a) - medium_value(b)); } if (Py_SIZE(a) < 0) { if (Py_SIZE(b) < 0) { @@ -4372,7 +4362,7 @@ long_invert(PyLongObject *v) /* Implement ~x as -(x+1) */ PyLongObject *x; if (IS_MEDIUM_VALUE(v)) - return _PyLong_FromSDigit(~medium_value(v)); + return _PyLong_FromSTwoDigits(~medium_value(v)); x = (PyLongObject *) long_add(v, (PyLongObject *)_PyLong_GetOne()); if (x == NULL) return NULL; @@ -4387,7 +4377,7 @@ long_neg(PyLongObject *v) { PyLongObject *z; if (IS_MEDIUM_VALUE(v)) - return _PyLong_FromSDigit(-medium_value(v)); + return _PyLong_FromSTwoDigits(-medium_value(v)); z = (PyLongObject *)_PyLong_Copy(v); if (z != NULL) Py_SET_SIZE(z, -(Py_SIZE(v))); @@ -4736,7 +4726,7 @@ long_and(PyObject *a, PyObject *b) PyLongObject *x = (PyLongObject*)a; PyLongObject *y = (PyLongObject*)b; if (IS_MEDIUM_VALUE(x) && IS_MEDIUM_VALUE(y)) { - return _PyLong_FromSDigit(medium_value(x) & medium_value(y)); + return _PyLong_FromSTwoDigits(medium_value(x) & medium_value(y)); } return long_bitwise(x, '&', y); } @@ -4748,7 +4738,7 @@ long_xor(PyObject *a, PyObject *b) PyLongObject *x = (PyLongObject*)a; PyLongObject *y = (PyLongObject*)b; if (IS_MEDIUM_VALUE(x) && IS_MEDIUM_VALUE(y)) { - return _PyLong_FromSDigit(medium_value(x) ^ medium_value(y)); + return _PyLong_FromSTwoDigits(medium_value(x) ^ medium_value(y)); } return long_bitwise(x, '^', y); } @@ -4760,7 +4750,7 @@ long_or(PyObject *a, PyObject *b) PyLongObject *x = (PyLongObject*)a; PyLongObject *y = (PyLongObject*)b; if (IS_MEDIUM_VALUE(x) && IS_MEDIUM_VALUE(y)) { - return _PyLong_FromSDigit(medium_value(x) | medium_value(y)); + return _PyLong_FromSTwoDigits(medium_value(x) | medium_value(y)); } return long_bitwise(x, '|', y); } From 16d316702da83125e8a68a92f532ac4686b541a8 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 20 Aug 2021 12:39:10 +0100 Subject: [PATCH 09/17] Remove two more narrowing casts. --- Objects/longobject.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index 63b11629c549b4..a9d3a63e4c4ddc 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -55,7 +55,7 @@ static PyLongObject * maybe_small_long(PyLongObject *v) { if (v && IS_MEDIUM_VALUE(v)) { - sdigit ival = medium_value(v); + stwodigits ival = medium_value(v); if (IS_SMALL_INT(ival)) { Py_DECREF(v); return (PyLongObject *)get_small_int(ival); @@ -64,23 +64,6 @@ maybe_small_long(PyLongObject *v) return v; } -/* If a freshly-allocated int is already shared, it must - be a small integer, so negating it must go to PyLong_FromLong */ -Py_LOCAL_INLINE(void) -_PyLong_Negate(PyLongObject **x_p) -{ - PyLongObject *x; - - x = (PyLongObject *)*x_p; - if (Py_REFCNT(x) == 1) { - Py_SET_SIZE(x, -Py_SIZE(x)); - return; - } - - *x_p = (PyLongObject *)PyLong_FromLong(-medium_value(x)); - Py_DECREF(x); -} - /* For int multiplication, use the O(N**2) school algorithm unless * both operands contain more than KARATSUBA_CUTOFF digits (this * being an internal Python int digit, in base BASE). @@ -249,6 +232,23 @@ _PyLong_FromSTwoDigits(stwodigits x) return _PyLong_FromLarge(x); } +/* If a freshly-allocated int is already shared, it must + be a small integer, so negating it must go to PyLong_FromLong */ +Py_LOCAL_INLINE(void) +_PyLong_Negate(PyLongObject **x_p) +{ + PyLongObject *x; + + x = (PyLongObject *)*x_p; + if (Py_REFCNT(x) == 1) { + Py_SET_SIZE(x, -Py_SIZE(x)); + return; + } + + *x_p = (PyLongObject *)_PyLong_FromSTwoDigits(-medium_value(x)); + Py_DECREF(x); +} + /* Create a new int object from a C long int */ PyObject * PyLong_FromLong(long ival) From f20a2a803231530845344851f2f0df7c3dc14e9c Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 20 Aug 2021 12:43:17 +0100 Subject: [PATCH 10/17] Change _PyLong_FromLarge to use correctly sized int. --- Objects/longobject.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index a9d3a63e4c4ddc..a2b90f6fa4327c 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -179,39 +179,37 @@ _PyLong_FromMedium(sdigit x) } static PyObject * -_PyLong_FromLarge(long ival) +_PyLong_FromLarge(stwodigits ival) { - PyLongObject *v; - unsigned long abs_ival; - unsigned long t; /* unsigned so >> doesn't propagate sign bit */ - int ndigits = 0; + twodigits abs_ival; int sign; assert(!IS_MEDIUM_INT(ival)); if (ival < 0) { /* negate: can't write this as abs_ival = -ival since that invokes undefined behaviour when ival is LONG_MIN */ - abs_ival = 0U-(unsigned long)ival; + abs_ival = 0U-(twodigits)ival; sign = -1; } else { - abs_ival = (unsigned long)ival; + abs_ival = (twodigits)ival; sign = 1; } /* Loop to determine number of digits */ - t = abs_ival; + twodigits t = abs_ival; + Py_ssize_t ndigits = 0; while (t) { ++ndigits; t >>= PyLong_SHIFT; } - v = _PyLong_New(ndigits); + PyLongObject *v = _PyLong_New(ndigits); if (v != NULL) { digit *p = v->ob_digit; Py_SET_SIZE(v, ndigits * sign); t = abs_ival; while (t) { *p++ = Py_SAFE_DOWNCAST( - t & PyLong_MASK, unsigned long, digit); + t & PyLong_MASK, twodigits, digit); t >>= PyLong_SHIFT; } } From ab2b908b57654162a07b9876aa361664a6642f12 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 20 Aug 2021 13:46:28 +0100 Subject: [PATCH 11/17] Avoid more narrowings. --- Objects/longobject.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index a2b90f6fa4327c..274932dbc5262b 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -43,7 +43,7 @@ medium_value(PyLongObject *x) #define IS_MEDIUM_INT(x) (((twodigits)x)+PyLong_MASK <= 2*PyLong_MASK) static PyObject * -get_small_int(sdigit ival) +get_small_int(stwodigits ival) { assert(IS_SMALL_INT(ival)); PyObject *v = __PyLong_GetSmallInt_internal(ival); @@ -145,7 +145,7 @@ _PyLong_Copy(PyLongObject *src) if (i < 0) i = -(i); if (i < 2) { - sdigit ival = medium_value(src); + stwodigits ival = medium_value(src); if (IS_SMALL_INT(ival)) { return get_small_int(ival); } @@ -258,7 +258,7 @@ PyLong_FromLong(long ival) #define PYLONG_FROM_UINT(INT_TYPE, ival) \ do { \ if (IS_SMALL_UINT(ival)) { \ - return get_small_int((sdigit)(ival)); \ + return get_small_int((stwodigits)(ival)); \ } \ /* Count the number of Python digits. */ \ Py_ssize_t ndigits = 0; \ @@ -1050,7 +1050,7 @@ PyLong_FromLongLong(long long ival) int negative = 0; if (IS_SMALL_INT(ival)) { - return get_small_int((sdigit)ival); + return get_small_int((stwodigits)ival); } if (ival < 0) { @@ -1097,7 +1097,7 @@ PyLong_FromSsize_t(Py_ssize_t ival) int negative = 0; if (IS_SMALL_INT(ival)) { - return get_small_int((sdigit)ival); + return get_small_int((stwodigits)ival); } if (ival < 0) { From e43060a0ebfd0f5415470fd8bf05d0569fa509db Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 20 Aug 2021 14:25:46 +0100 Subject: [PATCH 12/17] Revert get_small_int to taking a sdigit. Place narrowing casts in correct places. --- Objects/longobject.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index 274932dbc5262b..c739a495616f08 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -43,7 +43,7 @@ medium_value(PyLongObject *x) #define IS_MEDIUM_INT(x) (((twodigits)x)+PyLong_MASK <= 2*PyLong_MASK) static PyObject * -get_small_int(stwodigits ival) +get_small_int(sdigit ival) { assert(IS_SMALL_INT(ival)); PyObject *v = __PyLong_GetSmallInt_internal(ival); @@ -58,7 +58,7 @@ maybe_small_long(PyLongObject *v) stwodigits ival = medium_value(v); if (IS_SMALL_INT(ival)) { Py_DECREF(v); - return (PyLongObject *)get_small_int(ival); + return (PyLongObject *)get_small_int((sdigit)ival); } } return v; @@ -147,7 +147,7 @@ _PyLong_Copy(PyLongObject *src) if (i < 2) { stwodigits ival = medium_value(src); if (IS_SMALL_INT(ival)) { - return get_small_int(ival); + return get_small_int((sdigit)ival); } } result = _PyLong_New(i); @@ -221,11 +221,11 @@ static inline PyObject * _PyLong_FromSTwoDigits(stwodigits x) { if (IS_SMALL_INT(x)) { - return get_small_int(x); + return get_small_int((sdigit)x); } assert(x != 0); if (IS_MEDIUM_INT(x)) { - return _PyLong_FromMedium(x); + return _PyLong_FromMedium((sdigit)x); } return _PyLong_FromLarge(x); } @@ -258,7 +258,7 @@ PyLong_FromLong(long ival) #define PYLONG_FROM_UINT(INT_TYPE, ival) \ do { \ if (IS_SMALL_UINT(ival)) { \ - return get_small_int((stwodigits)(ival)); \ + return get_small_int((sdigit)(ival)); \ } \ /* Count the number of Python digits. */ \ Py_ssize_t ndigits = 0; \ @@ -1050,7 +1050,7 @@ PyLong_FromLongLong(long long ival) int negative = 0; if (IS_SMALL_INT(ival)) { - return get_small_int((stwodigits)ival); + return get_small_int((sdigit)ival); } if (ival < 0) { @@ -1097,7 +1097,7 @@ PyLong_FromSsize_t(Py_ssize_t ival) int negative = 0; if (IS_SMALL_INT(ival)) { - return get_small_int((stwodigits)ival); + return get_small_int((sdigit)ival); } if (ival < 0) { From ed2a4303ddcf4d92adcfc95f2d199b76b5b6179d Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 20 Aug 2021 15:44:12 +0100 Subject: [PATCH 13/17] Use _PyLong_FromSTwoDigits not PyLong_FromLong in long_add. --- Objects/longobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index c739a495616f08..08608456ff645d 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -3084,7 +3084,7 @@ long_add(PyLongObject *a, PyLongObject *b) CHECK_BINOP(a, b); if (IS_MEDIUM_VALUE(a) && IS_MEDIUM_VALUE(b)) { - return PyLong_FromLong(medium_value(a) + medium_value(b)); + return _PyLong_FromSTwoDigits(medium_value(a) + medium_value(b)); } if (Py_SIZE(a) < 0) { if (Py_SIZE(b) < 0) { From 1f2d47c5b2d9c5c300d16443d33f58af75873db6 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 23 Aug 2021 09:37:52 +0100 Subject: [PATCH 14/17] Implement PyLong_FromLong separately from _PyLong_FromSTwoDigits to allow for 15 bit digits on 64 bit machines. --- Objects/longobject.c | 51 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index 08608456ff645d..09516a06ed6b5b 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -40,6 +40,8 @@ medium_value(PyLongObject *x) #define IS_SMALL_INT(ival) (-NSMALLNEGINTS <= (ival) && (ival) < NSMALLPOSINTS) #define IS_SMALL_UINT(ival) ((ival) < NSMALLPOSINTS) +/* To be valid the type of x must cover -PyLong_BASE to +PyLong_BASE. + int, long, Py_ssize_t are all ok */ #define IS_MEDIUM_INT(x) (((twodigits)x)+PyLong_MASK <= 2*PyLong_MASK) static PyObject * @@ -195,9 +197,10 @@ _PyLong_FromLarge(stwodigits ival) abs_ival = (twodigits)ival; sign = 1; } - /* Loop to determine number of digits */ - twodigits t = abs_ival; - Py_ssize_t ndigits = 0; + /* Must be at least two digits */ + assert(abs_ival >> PyLong_SHIFT != 0); + twodigits t = abs_ival >> (PyLong_SHIFT *2); + Py_ssize_t ndigits = 2; while (t) { ++ndigits; t >>= PyLong_SHIFT; @@ -251,8 +254,44 @@ _PyLong_Negate(PyLongObject **x_p) PyObject * PyLong_FromLong(long ival) { - Py_BUILD_ASSERT(sizeof(stwodigits) >= sizeof(long)); - return _PyLong_FromSTwoDigits(ival); + if (IS_SMALL_INT(ival)) { + return get_small_int((sdigit)ival); + } + unsigned long abs_ival; + int sign; + if (ival < 0) { + /* negate: can't write this as abs_ival = -ival since that + invokes undefined behaviour when ival is LONG_MIN */ + abs_ival = 0U-(twodigits)ival; + sign = -1; + } + else { + abs_ival = (unsigned long)ival; + sign = 1; + } + /* Fast path for single-digit ints */ + if (!(abs_ival >> PyLong_SHIFT)) { + return _PyLong_FromMedium((sdigit)ival); + } + /* Must be at least two digits */ + unsigned long t = abs_ival >> (PyLong_SHIFT *2); + Py_ssize_t ndigits = 2; + while (t) { + ++ndigits; + t >>= PyLong_SHIFT; + } + PyLongObject *v = _PyLong_New(ndigits); + if (v != NULL) { + digit *p = v->ob_digit; + Py_SET_SIZE(v, ndigits * sign); + t = abs_ival; + while (t) { + *p++ = Py_SAFE_DOWNCAST( + t & PyLong_MASK, unsigned long, digit); + t >>= PyLong_SHIFT; + } + } + return (PyObject *)v; } #define PYLONG_FROM_UINT(INT_TYPE, ival) \ @@ -3554,7 +3593,7 @@ long_mul(PyLongObject *a, PyLongObject *b) /* fast path for single-digit multiplication */ if (IS_MEDIUM_VALUE(a) && IS_MEDIUM_VALUE(b)) { stwodigits v = medium_value(a) * medium_value(b); - return PyLong_FromLongLong((long long)v); + return _PyLong_FromSTwoDigits(v); } z = k_mul(a, b); From 649c31180fbf72416cfe3d063ca592769e2cf049 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 23 Aug 2021 15:29:09 +0100 Subject: [PATCH 15/17] Don't overflow shift in PyLong_FromLong. --- Objects/longobject.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index 09516a06ed6b5b..f6bf7ebd248537 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -273,8 +273,9 @@ PyLong_FromLong(long ival) if (!(abs_ival >> PyLong_SHIFT)) { return _PyLong_FromMedium((sdigit)ival); } - /* Must be at least two digits */ - unsigned long t = abs_ival >> (PyLong_SHIFT *2); + /* Must be at least two digits. + * Do shift in two steps to avoid undefined behavior. */ + unsigned long t = (abs_ival >> PyLong_SHIFT) >> PyLong_SHIFT; Py_ssize_t ndigits = 2; while (t) { ++ndigits; From a69f420e9f81e21cdcda5d57fa8d11e70139f680 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 25 Aug 2021 12:05:33 +0100 Subject: [PATCH 16/17] Convert IS_MEDIUM_INT macro to inline function. --- Objects/longobject.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index f6bf7ebd248537..a90542b79dc378 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -40,9 +40,13 @@ medium_value(PyLongObject *x) #define IS_SMALL_INT(ival) (-NSMALLNEGINTS <= (ival) && (ival) < NSMALLPOSINTS) #define IS_SMALL_UINT(ival) ((ival) < NSMALLPOSINTS) -/* To be valid the type of x must cover -PyLong_BASE to +PyLong_BASE. - int, long, Py_ssize_t are all ok */ -#define IS_MEDIUM_INT(x) (((twodigits)x)+PyLong_MASK <= 2*PyLong_MASK) +static inline int is_medium_int(stwodigits x) +{ + /* We have to take care here to make sure that we are + * comparing unsigned values. */ + twodigits x_plus_mask = ((twodigits)x) + PyLong_MASK; + return x_plus_mask < ((twodigits)PyLong_MASK) + PyLong_BASE; +} static PyObject * get_small_int(sdigit ival) @@ -166,7 +170,7 @@ static PyObject * _PyLong_FromMedium(sdigit x) { assert(!IS_SMALL_INT(x)); - assert(IS_MEDIUM_INT(x)); + assert(is_medium_int(x)); /* We could use a freelist here */ PyLongObject *v = PyObject_Malloc(sizeof(PyLongObject)); if (v == NULL) { @@ -185,7 +189,7 @@ _PyLong_FromLarge(stwodigits ival) { twodigits abs_ival; int sign; - assert(!IS_MEDIUM_INT(ival)); + assert(!is_medium_int(ival)); if (ival < 0) { /* negate: can't write this as abs_ival = -ival since that @@ -199,7 +203,7 @@ _PyLong_FromLarge(stwodigits ival) } /* Must be at least two digits */ assert(abs_ival >> PyLong_SHIFT != 0); - twodigits t = abs_ival >> (PyLong_SHIFT *2); + twodigits t = abs_ival >> (PyLong_SHIFT * 2); Py_ssize_t ndigits = 2; while (t) { ++ndigits; @@ -227,7 +231,7 @@ _PyLong_FromSTwoDigits(stwodigits x) return get_small_int((sdigit)x); } assert(x != 0); - if (IS_MEDIUM_INT(x)) { + if (is_medium_int(x)) { return _PyLong_FromMedium((sdigit)x); } return _PyLong_FromLarge(x); From 47571ffaeee4f9758876bb0de9e1e8ee594a36c7 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 25 Aug 2021 13:51:19 +0100 Subject: [PATCH 17/17] Edit comment --- Objects/longobject.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index a90542b79dc378..18b0839adb6b05 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -42,8 +42,7 @@ medium_value(PyLongObject *x) static inline int is_medium_int(stwodigits x) { - /* We have to take care here to make sure that we are - * comparing unsigned values. */ + /* Take care that we are comparing unsigned values. */ twodigits x_plus_mask = ((twodigits)x) + PyLong_MASK; return x_plus_mask < ((twodigits)PyLong_MASK) + PyLong_BASE; } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy