@@ -2179,6 +2179,40 @@ BITWISE_LONGS_ACTION(compactlongs_and, &)
21792179BITWISE_LONGS_ACTION (compactlongs_xor , ^)
21802180#undef BITWISE_LONGS_ACTION
21812181
2182+ static int
2183+ small_power_guard (PyObject * lhs , PyObject * rhs )
2184+ {
2185+ if (!is_compactlong (lhs ) || !is_compactlong (rhs )) {
2186+ return false;
2187+ }
2188+ Py_ssize_t exponent = _PyLong_CompactValue ((PyLongObject * )rhs );
2189+ if (exponent == 2 ) {
2190+ /* |x| < 2^30 (compact), so x*x < 2^60: fits a 64-bit
2191+ intermediate even where Py_ssize_t is 32 bits. */
2192+ return true;
2193+ }
2194+ if (exponent == 3 ) {
2195+ /* Need |x*x*x| < 2^60, so |x| < 2^20. */
2196+ Py_ssize_t x = _PyLong_CompactValue ((PyLongObject * )lhs );
2197+ return x < (1 << 20 ) && x > - (1 << 20 );
2198+ }
2199+ return false;
2200+ }
2201+
2202+ static PyObject *
2203+ small_power (PyObject * lhs , PyObject * rhs )
2204+ {
2205+ /* Compute in int64_t (not Py_ssize_t): the guard bounds keep the
2206+ product below 2^60, which overflows a 32-bit Py_ssize_t. */
2207+ int64_t x = (int64_t )_PyLong_CompactValue ((PyLongObject * )lhs );
2208+ int64_t exponent = (int64_t )_PyLong_CompactValue ((PyLongObject * )rhs );
2209+ assert (exponent == 2 || exponent == 3 );
2210+ if (exponent == 2 ) {
2211+ return PyLong_FromLongLong (x * x );
2212+ }
2213+ return PyLong_FromLongLong (x * x * x );
2214+ }
2215+
21822216/* float-long */
21832217
21842218static inline int
@@ -2259,6 +2293,11 @@ static _PyBinaryOpSpecializationDescr binaryop_extend_descrs[] = {
22592293 {NB_INPLACE_AND , compactlongs_guard , compactlongs_and , & PyLong_Type , 1 , NULL , NULL },
22602294 {NB_INPLACE_XOR , compactlongs_guard , compactlongs_xor , & PyLong_Type , 1 , NULL , NULL },
22612295
2296+ /* x ** 2 / x ** 3 for compact ints; PyLong_FromLongLong may return
2297+ the cached immortal small ints, which result_unique accepts. */
2298+ {NB_POWER , small_power_guard , small_power , & PyLong_Type , 1 , NULL , NULL },
2299+ {NB_INPLACE_POWER , small_power_guard , small_power , & PyLong_Type , 1 , NULL , NULL },
2300+
22622301 /* float-long arithmetic: guards also check NaN and compactness. */
22632302 {NB_ADD , float_compactlong_guard , float_compactlong_add , & PyFloat_Type , 1 , NULL , NULL },
22642303 {NB_SUBTRACT , float_compactlong_guard , float_compactlong_subtract , & PyFloat_Type , 1 , NULL , NULL },
0 commit comments