@@ -26,15 +26,27 @@ class int "PyObject *" "&PyLong_Type"
2626_Py_IDENTIFIER (little );
2727_Py_IDENTIFIER (big );
2828
29- /* convert a PyLong of size 1, 0 or -1 to an sdigit */
30- #define MEDIUM_VALUE (x ) (assert(-1 <= Py_SIZE(x) && Py_SIZE(x) <= 1), \
31- Py_SIZE(x) < 0 ? -(sdigit)(x)->ob_digit[0] : \
32- (Py_SIZE(x) == 0 ? (sdigit)0 : \
33- (sdigit)(x)->ob_digit[0]))
29+ /* Is this PyLong of size 1, 0 or -1? */
30+ #define IS_MEDIUM_VALUE (x ) (((size_t)Py_SIZE(x)) + 1U < 3U)
31+
32+ /* convert a PyLong of size 1, 0 or -1 to a C integer */
33+ static inline stwodigits
34+ medium_value (PyLongObject * x )
35+ {
36+ assert (IS_MEDIUM_VALUE (x ));
37+ return ((stwodigits )Py_SIZE (x )) * x -> ob_digit [0 ];
38+ }
3439
3540#define IS_SMALL_INT (ival ) (-NSMALLNEGINTS <= (ival) && (ival) < NSMALLPOSINTS)
3641#define IS_SMALL_UINT (ival ) ((ival) < NSMALLPOSINTS)
3742
43+ static inline int is_medium_int (stwodigits x )
44+ {
45+ /* Take care that we are comparing unsigned values. */
46+ twodigits x_plus_mask = ((twodigits )x ) + PyLong_MASK ;
47+ return x_plus_mask < ((twodigits )PyLong_MASK ) + PyLong_BASE ;
48+ }
49+
3850static PyObject *
3951get_small_int (sdigit ival )
4052{
@@ -47,33 +59,16 @@ get_small_int(sdigit ival)
4759static PyLongObject *
4860maybe_small_long (PyLongObject * v )
4961{
50- if (v && Py_ABS ( Py_SIZE ( v )) <= 1 ) {
51- sdigit ival = MEDIUM_VALUE (v );
62+ if (v && IS_MEDIUM_VALUE ( v ) ) {
63+ stwodigits ival = medium_value (v );
5264 if (IS_SMALL_INT (ival )) {
5365 Py_DECREF (v );
54- return (PyLongObject * )get_small_int (ival );
66+ return (PyLongObject * )get_small_int (( sdigit ) ival );
5567 }
5668 }
5769 return v ;
5870}
5971
60- /* If a freshly-allocated int is already shared, it must
61- be a small integer, so negating it must go to PyLong_FromLong */
62- Py_LOCAL_INLINE (void )
63- _PyLong_Negate (PyLongObject * * x_p )
64- {
65- PyLongObject * x ;
66-
67- x = (PyLongObject * )* x_p ;
68- if (Py_REFCNT (x ) == 1 ) {
69- Py_SET_SIZE (x , - Py_SIZE (x ));
70- return ;
71- }
72-
73- * x_p = (PyLongObject * )PyLong_FromLong (- MEDIUM_VALUE (x ));
74- Py_DECREF (x );
75- }
76-
7772/* For int multiplication, use the O(N**2) school algorithm unless
7873 * both operands contain more than KARATSUBA_CUTOFF digits (this
7974 * being an internal Python int digit, in base BASE).
@@ -121,18 +116,21 @@ PyLongObject *
121116_PyLong_New (Py_ssize_t size )
122117{
123118 PyLongObject * result ;
124- /* Number of bytes needed is: offsetof(PyLongObject, ob_digit) +
125- sizeof(digit)*size. Previous incarnations of this code used
126- sizeof(PyVarObject) instead of the offsetof, but this risks being
127- incorrect in the presence of padding between the PyVarObject header
128- and the digits. */
129119 if (size > (Py_ssize_t )MAX_LONG_DIGITS ) {
130120 PyErr_SetString (PyExc_OverflowError ,
131121 "too many digits in integer" );
132122 return NULL ;
133123 }
124+ /* Fast operations for single digit integers (including zero)
125+ * assume that there is always at least one digit present. */
126+ Py_ssize_t ndigits = size ? size : 1 ;
127+ /* Number of bytes needed is: offsetof(PyLongObject, ob_digit) +
128+ sizeof(digit)*size. Previous incarnations of this code used
129+ sizeof(PyVarObject) instead of the offsetof, but this risks being
130+ incorrect in the presence of padding between the PyVarObject header
131+ and the digits. */
134132 result = PyObject_Malloc (offsetof(PyLongObject , ob_digit ) +
135- size * sizeof (digit ));
133+ ndigits * sizeof (digit ));
136134 if (!result ) {
137135 PyErr_NoMemory ();
138136 return NULL ;
@@ -152,9 +150,9 @@ _PyLong_Copy(PyLongObject *src)
152150 if (i < 0 )
153151 i = - (i );
154152 if (i < 2 ) {
155- sdigit ival = MEDIUM_VALUE (src );
153+ stwodigits ival = medium_value (src );
156154 if (IS_SMALL_INT (ival )) {
157- return get_small_int (ival );
155+ return get_small_int (( sdigit ) ival );
158156 }
159157 }
160158 result = _PyLong_New (i );
@@ -167,65 +165,126 @@ _PyLong_Copy(PyLongObject *src)
167165 return (PyObject * )result ;
168166}
169167
170- /* Create a new int object from a C long int */
168+ static PyObject *
169+ _PyLong_FromMedium (sdigit x )
170+ {
171+ assert (!IS_SMALL_INT (x ));
172+ assert (is_medium_int (x ));
173+ /* We could use a freelist here */
174+ PyLongObject * v = PyObject_Malloc (sizeof (PyLongObject ));
175+ if (v == NULL ) {
176+ PyErr_NoMemory ();
177+ return NULL ;
178+ }
179+ Py_ssize_t sign = x < 0 ? -1 : 1 ;
180+ digit abs_x = x < 0 ? - x : x ;
181+ _PyObject_InitVar ((PyVarObject * )v , & PyLong_Type , sign );
182+ v -> ob_digit [0 ] = abs_x ;
183+ return (PyObject * )v ;
184+ }
171185
172- PyObject *
173- PyLong_FromLong ( long ival )
186+ static PyObject *
187+ _PyLong_FromLarge ( stwodigits ival )
174188{
175- PyLongObject * v ;
176- unsigned long abs_ival ;
177- unsigned long t ; /* unsigned so >> doesn't propagate sign bit */
178- int ndigits = 0 ;
189+ twodigits abs_ival ;
179190 int sign ;
191+ assert (!is_medium_int (ival ));
180192
193+ if (ival < 0 ) {
194+ /* negate: can't write this as abs_ival = -ival since that
195+ invokes undefined behaviour when ival is LONG_MIN */
196+ abs_ival = 0U - (twodigits )ival ;
197+ sign = -1 ;
198+ }
199+ else {
200+ abs_ival = (twodigits )ival ;
201+ sign = 1 ;
202+ }
203+ /* Must be at least two digits */
204+ assert (abs_ival >> PyLong_SHIFT != 0 );
205+ twodigits t = abs_ival >> (PyLong_SHIFT * 2 );
206+ Py_ssize_t ndigits = 2 ;
207+ while (t ) {
208+ ++ ndigits ;
209+ t >>= PyLong_SHIFT ;
210+ }
211+ PyLongObject * v = _PyLong_New (ndigits );
212+ if (v != NULL ) {
213+ digit * p = v -> ob_digit ;
214+ Py_SET_SIZE (v , ndigits * sign );
215+ t = abs_ival ;
216+ while (t ) {
217+ * p ++ = Py_SAFE_DOWNCAST (
218+ t & PyLong_MASK , twodigits , digit );
219+ t >>= PyLong_SHIFT ;
220+ }
221+ }
222+ return (PyObject * )v ;
223+ }
224+
225+ /* Create a new int object from a C word-sized int */
226+ static inline PyObject *
227+ _PyLong_FromSTwoDigits (stwodigits x )
228+ {
229+ if (IS_SMALL_INT (x )) {
230+ return get_small_int ((sdigit )x );
231+ }
232+ assert (x != 0 );
233+ if (is_medium_int (x )) {
234+ return _PyLong_FromMedium ((sdigit )x );
235+ }
236+ return _PyLong_FromLarge (x );
237+ }
238+
239+ /* If a freshly-allocated int is already shared, it must
240+ be a small integer, so negating it must go to PyLong_FromLong */
241+ Py_LOCAL_INLINE (void )
242+ _PyLong_Negate (PyLongObject * * x_p )
243+ {
244+ PyLongObject * x ;
245+
246+ x = (PyLongObject * )* x_p ;
247+ if (Py_REFCNT (x ) == 1 ) {
248+ Py_SET_SIZE (x , - Py_SIZE (x ));
249+ return ;
250+ }
251+
252+ * x_p = (PyLongObject * )_PyLong_FromSTwoDigits (- medium_value (x ));
253+ Py_DECREF (x );
254+ }
255+
256+ /* Create a new int object from a C long int */
257+ PyObject *
258+ PyLong_FromLong (long ival )
259+ {
181260 if (IS_SMALL_INT (ival )) {
182261 return get_small_int ((sdigit )ival );
183262 }
184-
263+ unsigned long abs_ival ;
264+ int sign ;
185265 if (ival < 0 ) {
186266 /* negate: can't write this as abs_ival = -ival since that
187267 invokes undefined behaviour when ival is LONG_MIN */
188- abs_ival = 0U - (unsigned long )ival ;
268+ abs_ival = 0U - (twodigits )ival ;
189269 sign = -1 ;
190270 }
191271 else {
192272 abs_ival = (unsigned long )ival ;
193- sign = ival == 0 ? 0 : 1 ;
273+ sign = 1 ;
194274 }
195-
196275 /* Fast path for single-digit ints */
197276 if (!(abs_ival >> PyLong_SHIFT )) {
198- v = _PyLong_New (1 );
199- if (v ) {
200- Py_SET_SIZE (v , sign );
201- v -> ob_digit [0 ] = Py_SAFE_DOWNCAST (
202- abs_ival , unsigned long , digit );
203- }
204- return (PyObject * )v ;
205- }
206-
207- #if PyLong_SHIFT == 15
208- /* 2 digits */
209- if (!(abs_ival >> 2 * PyLong_SHIFT )) {
210- v = _PyLong_New (2 );
211- if (v ) {
212- Py_SET_SIZE (v , 2 * sign );
213- v -> ob_digit [0 ] = Py_SAFE_DOWNCAST (
214- abs_ival & PyLong_MASK , unsigned long , digit );
215- v -> ob_digit [1 ] = Py_SAFE_DOWNCAST (
216- abs_ival >> PyLong_SHIFT , unsigned long , digit );
217- }
218- return (PyObject * )v ;
277+ return _PyLong_FromMedium ((sdigit )ival );
219278 }
220- #endif
221-
222- /* Larger numbers: loop to determine number of digits */
223- t = abs_ival ;
279+ /* Must be at least two digits.
280+ * Do shift in two steps to avoid undefined behavior. */
281+ unsigned long t = ( abs_ival >> PyLong_SHIFT ) >> PyLong_SHIFT ;
282+ Py_ssize_t ndigits = 2 ;
224283 while (t ) {
225284 ++ ndigits ;
226285 t >>= PyLong_SHIFT ;
227286 }
228- v = _PyLong_New (ndigits );
287+ PyLongObject * v = _PyLong_New (ndigits );
229288 if (v != NULL ) {
230289 digit * p = v -> ob_digit ;
231290 Py_SET_SIZE (v , ndigits * sign );
@@ -2860,12 +2919,12 @@ PyLong_AsDouble(PyObject *v)
28602919 PyErr_SetString (PyExc_TypeError , "an integer is required" );
28612920 return -1.0 ;
28622921 }
2863- if (Py_ABS ( Py_SIZE ( v )) <= 1 ) {
2922+ if (IS_MEDIUM_VALUE ( v ) ) {
28642923 /* Fast path; single digit long (31 bits) will cast safely
28652924 to double. This improves performance of FP/long operations
28662925 by 20%.
28672926 */
2868- return (double )MEDIUM_VALUE ((PyLongObject * )v );
2927+ return (double )medium_value ((PyLongObject * )v );
28692928 }
28702929 x = _PyLong_Frexp ((PyLongObject * )v , & exponent );
28712930 if ((x == -1.0 && PyErr_Occurred ()) || exponent > DBL_MAX_EXP ) {
@@ -3067,8 +3126,8 @@ long_add(PyLongObject *a, PyLongObject *b)
30673126
30683127 CHECK_BINOP (a , b );
30693128
3070- if (Py_ABS ( Py_SIZE ( a )) <= 1 && Py_ABS ( Py_SIZE ( b )) <= 1 ) {
3071- return PyLong_FromLong ( MEDIUM_VALUE (a ) + MEDIUM_VALUE (b ));
3129+ if (IS_MEDIUM_VALUE ( a ) && IS_MEDIUM_VALUE ( b ) ) {
3130+ return _PyLong_FromSTwoDigits ( medium_value (a ) + medium_value (b ));
30723131 }
30733132 if (Py_SIZE (a ) < 0 ) {
30743133 if (Py_SIZE (b ) < 0 ) {
@@ -3101,8 +3160,8 @@ long_sub(PyLongObject *a, PyLongObject *b)
31013160
31023161 CHECK_BINOP (a , b );
31033162
3104- if (Py_ABS ( Py_SIZE ( a )) <= 1 && Py_ABS ( Py_SIZE ( b )) <= 1 ) {
3105- return PyLong_FromLong ( MEDIUM_VALUE (a ) - MEDIUM_VALUE (b ));
3163+ if (IS_MEDIUM_VALUE ( a ) && IS_MEDIUM_VALUE ( b ) ) {
3164+ return _PyLong_FromSTwoDigits ( medium_value (a ) - medium_value (b ));
31063165 }
31073166 if (Py_SIZE (a ) < 0 ) {
31083167 if (Py_SIZE (b ) < 0 ) {
@@ -3536,9 +3595,9 @@ long_mul(PyLongObject *a, PyLongObject *b)
35363595 CHECK_BINOP (a , b );
35373596
35383597 /* fast path for single-digit multiplication */
3539- if (Py_ABS ( Py_SIZE ( a )) <= 1 && Py_ABS ( Py_SIZE ( b )) <= 1 ) {
3540- stwodigits v = ( stwodigits )( MEDIUM_VALUE ( a )) * MEDIUM_VALUE (b );
3541- return PyLong_FromLongLong (( long long ) v );
3598+ if (IS_MEDIUM_VALUE ( a ) && IS_MEDIUM_VALUE ( b ) ) {
3599+ stwodigits v = medium_value ( a ) * medium_value (b );
3600+ return _PyLong_FromSTwoDigits ( v );
35423601 }
35433602
35443603 z = k_mul (a , b );
@@ -4343,8 +4402,8 @@ long_invert(PyLongObject *v)
43434402{
43444403 /* Implement ~x as -(x+1) */
43454404 PyLongObject * x ;
4346- if (Py_ABS ( Py_SIZE ( v )) <= 1 )
4347- return PyLong_FromLong ( - ( MEDIUM_VALUE ( v ) + 1 ));
4405+ if (IS_MEDIUM_VALUE ( v ) )
4406+ return _PyLong_FromSTwoDigits (~ medium_value ( v ));
43484407 x = (PyLongObject * ) long_add (v , (PyLongObject * )_PyLong_GetOne ());
43494408 if (x == NULL )
43504409 return NULL ;
@@ -4358,8 +4417,8 @@ static PyObject *
43584417long_neg (PyLongObject * v )
43594418{
43604419 PyLongObject * z ;
4361- if (Py_ABS ( Py_SIZE ( v )) <= 1 )
4362- return PyLong_FromLong ( - MEDIUM_VALUE (v ));
4420+ if (IS_MEDIUM_VALUE ( v ) )
4421+ return _PyLong_FromSTwoDigits ( - medium_value (v ));
43634422 z = (PyLongObject * )_PyLong_Copy (v );
43644423 if (z != NULL )
43654424 Py_SET_SIZE (z , - (Py_SIZE (v )));
@@ -4704,28 +4763,37 @@ long_bitwise(PyLongObject *a,
47044763static PyObject *
47054764long_and (PyObject * a , PyObject * b )
47064765{
4707- PyObject * c ;
47084766 CHECK_BINOP (a , b );
4709- c = long_bitwise ((PyLongObject * )a , '&' , (PyLongObject * )b );
4710- return c ;
4767+ PyLongObject * x = (PyLongObject * )a ;
4768+ PyLongObject * y = (PyLongObject * )b ;
4769+ if (IS_MEDIUM_VALUE (x ) && IS_MEDIUM_VALUE (y )) {
4770+ return _PyLong_FromSTwoDigits (medium_value (x ) & medium_value (y ));
4771+ }
4772+ return long_bitwise (x , '&' , y );
47114773}
47124774
47134775static PyObject *
47144776long_xor (PyObject * a , PyObject * b )
47154777{
4716- PyObject * c ;
47174778 CHECK_BINOP (a , b );
4718- c = long_bitwise ((PyLongObject * )a , '^' , (PyLongObject * )b );
4719- return c ;
4779+ PyLongObject * x = (PyLongObject * )a ;
4780+ PyLongObject * y = (PyLongObject * )b ;
4781+ if (IS_MEDIUM_VALUE (x ) && IS_MEDIUM_VALUE (y )) {
4782+ return _PyLong_FromSTwoDigits (medium_value (x ) ^ medium_value (y ));
4783+ }
4784+ return long_bitwise (x , '^' , y );
47204785}
47214786
47224787static PyObject *
47234788long_or (PyObject * a , PyObject * b )
47244789{
4725- PyObject * c ;
47264790 CHECK_BINOP (a , b );
4727- c = long_bitwise ((PyLongObject * )a , '|' , (PyLongObject * )b );
4728- return c ;
4791+ PyLongObject * x = (PyLongObject * )a ;
4792+ PyLongObject * y = (PyLongObject * )b ;
4793+ if (IS_MEDIUM_VALUE (x ) && IS_MEDIUM_VALUE (y )) {
4794+ return _PyLong_FromSTwoDigits (medium_value (x ) | medium_value (y ));
4795+ }
4796+ return long_bitwise (x , '|' , y );
47294797}
47304798
47314799static PyObject *
0 commit comments