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; }