| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803 |
- // Int primitive operations (tagged arbitrary-precision integers)
- //
- // These are registered in mypyc.primitives.int_ops.
- #include <Python.h>
- #include "CPy.h"
- #ifndef _WIN32
- // On 64-bit Linux and macOS, ssize_t and long are both 64 bits, and
- // PyLong_FromLong is faster than PyLong_FromSsize_t, so use the faster one
- #define CPyLong_FromSsize_t PyLong_FromLong
- #else
- // On 64-bit Windows, ssize_t is 64 bits but long is 32 bits, so we
- // can't use the above trick
- #define CPyLong_FromSsize_t PyLong_FromSsize_t
- #endif
- CPyTagged CPyTagged_FromSsize_t(Py_ssize_t value) {
- // We use a Python object if the value shifted left by 1 is too
- // large for Py_ssize_t
- if (unlikely(CPyTagged_TooBig(value))) {
- PyObject *object = PyLong_FromSsize_t(value);
- return ((CPyTagged)object) | CPY_INT_TAG;
- } else {
- return value << 1;
- }
- }
- CPyTagged CPyTagged_FromVoidPtr(void *ptr) {
- if ((uintptr_t)ptr > PY_SSIZE_T_MAX) {
- PyObject *object = PyLong_FromVoidPtr(ptr);
- return ((CPyTagged)object) | CPY_INT_TAG;
- } else {
- return CPyTagged_FromSsize_t((Py_ssize_t)ptr);
- }
- }
- CPyTagged CPyTagged_FromInt64(int64_t value) {
- if (unlikely(CPyTagged_TooBigInt64(value))) {
- PyObject *object = PyLong_FromLongLong(value);
- return ((CPyTagged)object) | CPY_INT_TAG;
- } else {
- return value << 1;
- }
- }
- CPyTagged CPyTagged_FromObject(PyObject *object) {
- int overflow;
- // The overflow check knows about CPyTagged's width
- Py_ssize_t value = CPyLong_AsSsize_tAndOverflow(object, &overflow);
- if (unlikely(overflow != 0)) {
- Py_INCREF(object);
- return ((CPyTagged)object) | CPY_INT_TAG;
- } else {
- return value << 1;
- }
- }
- CPyTagged CPyTagged_StealFromObject(PyObject *object) {
- int overflow;
- // The overflow check knows about CPyTagged's width
- Py_ssize_t value = CPyLong_AsSsize_tAndOverflow(object, &overflow);
- if (unlikely(overflow != 0)) {
- return ((CPyTagged)object) | CPY_INT_TAG;
- } else {
- Py_DECREF(object);
- return value << 1;
- }
- }
- CPyTagged CPyTagged_BorrowFromObject(PyObject *object) {
- int overflow;
- // The overflow check knows about CPyTagged's width
- Py_ssize_t value = CPyLong_AsSsize_tAndOverflow(object, &overflow);
- if (unlikely(overflow != 0)) {
- return ((CPyTagged)object) | CPY_INT_TAG;
- } else {
- return value << 1;
- }
- }
- PyObject *CPyTagged_AsObject(CPyTagged x) {
- PyObject *value;
- if (unlikely(CPyTagged_CheckLong(x))) {
- value = CPyTagged_LongAsObject(x);
- Py_INCREF(value);
- } else {
- value = CPyLong_FromSsize_t(CPyTagged_ShortAsSsize_t(x));
- if (value == NULL) {
- CPyError_OutOfMemory();
- }
- }
- return value;
- }
- PyObject *CPyTagged_StealAsObject(CPyTagged x) {
- PyObject *value;
- if (unlikely(CPyTagged_CheckLong(x))) {
- value = CPyTagged_LongAsObject(x);
- } else {
- value = CPyLong_FromSsize_t(CPyTagged_ShortAsSsize_t(x));
- if (value == NULL) {
- CPyError_OutOfMemory();
- }
- }
- return value;
- }
- Py_ssize_t CPyTagged_AsSsize_t(CPyTagged x) {
- if (likely(CPyTagged_CheckShort(x))) {
- return CPyTagged_ShortAsSsize_t(x);
- } else {
- return PyLong_AsSsize_t(CPyTagged_LongAsObject(x));
- }
- }
- CPy_NOINLINE
- void CPyTagged_IncRef(CPyTagged x) {
- if (unlikely(CPyTagged_CheckLong(x))) {
- Py_INCREF(CPyTagged_LongAsObject(x));
- }
- }
- CPy_NOINLINE
- void CPyTagged_DecRef(CPyTagged x) {
- if (unlikely(CPyTagged_CheckLong(x))) {
- Py_DECREF(CPyTagged_LongAsObject(x));
- }
- }
- CPy_NOINLINE
- void CPyTagged_XDecRef(CPyTagged x) {
- if (unlikely(CPyTagged_CheckLong(x))) {
- Py_XDECREF(CPyTagged_LongAsObject(x));
- }
- }
- CPyTagged CPyTagged_Negate(CPyTagged num) {
- if (CPyTagged_CheckShort(num)
- && num != (CPyTagged) ((Py_ssize_t)1 << (CPY_INT_BITS - 1))) {
- // The only possibility of an overflow error happening when negating a short is if we
- // attempt to negate the most negative number.
- return -num;
- }
- PyObject *num_obj = CPyTagged_AsObject(num);
- PyObject *result = PyNumber_Negative(num_obj);
- if (result == NULL) {
- CPyError_OutOfMemory();
- }
- Py_DECREF(num_obj);
- return CPyTagged_StealFromObject(result);
- }
- CPyTagged CPyTagged_Add(CPyTagged left, CPyTagged right) {
- // TODO: Use clang/gcc extension __builtin_saddll_overflow instead.
- if (likely(CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right))) {
- CPyTagged sum = left + right;
- if (likely(!CPyTagged_IsAddOverflow(sum, left, right))) {
- return sum;
- }
- }
- PyObject *left_obj = CPyTagged_AsObject(left);
- PyObject *right_obj = CPyTagged_AsObject(right);
- PyObject *result = PyNumber_Add(left_obj, right_obj);
- if (result == NULL) {
- CPyError_OutOfMemory();
- }
- Py_DECREF(left_obj);
- Py_DECREF(right_obj);
- return CPyTagged_StealFromObject(result);
- }
- CPyTagged CPyTagged_Subtract(CPyTagged left, CPyTagged right) {
- // TODO: Use clang/gcc extension __builtin_saddll_overflow instead.
- if (likely(CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right))) {
- CPyTagged diff = left - right;
- if (likely(!CPyTagged_IsSubtractOverflow(diff, left, right))) {
- return diff;
- }
- }
- PyObject *left_obj = CPyTagged_AsObject(left);
- PyObject *right_obj = CPyTagged_AsObject(right);
- PyObject *result = PyNumber_Subtract(left_obj, right_obj);
- if (result == NULL) {
- CPyError_OutOfMemory();
- }
- Py_DECREF(left_obj);
- Py_DECREF(right_obj);
- return CPyTagged_StealFromObject(result);
- }
- CPyTagged CPyTagged_Multiply(CPyTagged left, CPyTagged right) {
- // TODO: Consider using some clang/gcc extension
- if (CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right)) {
- if (!CPyTagged_IsMultiplyOverflow(left, right)) {
- return left * CPyTagged_ShortAsSsize_t(right);
- }
- }
- PyObject *left_obj = CPyTagged_AsObject(left);
- PyObject *right_obj = CPyTagged_AsObject(right);
- PyObject *result = PyNumber_Multiply(left_obj, right_obj);
- if (result == NULL) {
- CPyError_OutOfMemory();
- }
- Py_DECREF(left_obj);
- Py_DECREF(right_obj);
- return CPyTagged_StealFromObject(result);
- }
- CPyTagged CPyTagged_FloorDivide(CPyTagged left, CPyTagged right) {
- if (CPyTagged_CheckShort(left)
- && CPyTagged_CheckShort(right)
- && !CPyTagged_MaybeFloorDivideFault(left, right)) {
- Py_ssize_t result = CPyTagged_ShortAsSsize_t(left) / CPyTagged_ShortAsSsize_t(right);
- if (((Py_ssize_t)left < 0) != (((Py_ssize_t)right) < 0)) {
- if (result * right != left) {
- // Round down
- result--;
- }
- }
- return result << 1;
- }
- PyObject *left_obj = CPyTagged_AsObject(left);
- PyObject *right_obj = CPyTagged_AsObject(right);
- PyObject *result = PyNumber_FloorDivide(left_obj, right_obj);
- Py_DECREF(left_obj);
- Py_DECREF(right_obj);
- // Handle exceptions honestly because it could be ZeroDivisionError
- if (result == NULL) {
- return CPY_INT_TAG;
- } else {
- return CPyTagged_StealFromObject(result);
- }
- }
- CPyTagged CPyTagged_Remainder(CPyTagged left, CPyTagged right) {
- if (CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right)
- && !CPyTagged_MaybeRemainderFault(left, right)) {
- Py_ssize_t result = (Py_ssize_t)left % (Py_ssize_t)right;
- if (((Py_ssize_t)right < 0) != ((Py_ssize_t)left < 0) && result != 0) {
- result += right;
- }
- return result;
- }
- PyObject *left_obj = CPyTagged_AsObject(left);
- PyObject *right_obj = CPyTagged_AsObject(right);
- PyObject *result = PyNumber_Remainder(left_obj, right_obj);
- Py_DECREF(left_obj);
- Py_DECREF(right_obj);
- // Handle exceptions honestly because it could be ZeroDivisionError
- if (result == NULL) {
- return CPY_INT_TAG;
- } else {
- return CPyTagged_StealFromObject(result);
- }
- }
- bool CPyTagged_IsEq_(CPyTagged left, CPyTagged right) {
- if (CPyTagged_CheckShort(right)) {
- return false;
- } else {
- PyObject *left_obj = CPyTagged_AsObject(left);
- PyObject *right_obj = CPyTagged_AsObject(right);
- int result = PyObject_RichCompareBool(left_obj, right_obj, Py_EQ);
- Py_DECREF(left_obj);
- Py_DECREF(right_obj);
- if (result == -1) {
- CPyError_OutOfMemory();
- }
- return result;
- }
- }
- bool CPyTagged_IsLt_(CPyTagged left, CPyTagged right) {
- PyObject *left_obj = CPyTagged_AsObject(left);
- PyObject *right_obj = CPyTagged_AsObject(right);
- int result = PyObject_RichCompareBool(left_obj, right_obj, Py_LT);
- Py_DECREF(left_obj);
- Py_DECREF(right_obj);
- if (result == -1) {
- CPyError_OutOfMemory();
- }
- return result;
- }
- PyObject *CPyLong_FromStrWithBase(PyObject *o, CPyTagged base) {
- Py_ssize_t base_size_t = CPyTagged_AsSsize_t(base);
- return PyLong_FromUnicodeObject(o, base_size_t);
- }
- PyObject *CPyLong_FromStr(PyObject *o) {
- CPyTagged base = CPyTagged_FromSsize_t(10);
- return CPyLong_FromStrWithBase(o, base);
- }
- CPyTagged CPyTagged_FromFloat(double f) {
- if (f < ((double)CPY_TAGGED_MAX + 1.0) && f > (CPY_TAGGED_MIN - 1.0)) {
- return (Py_ssize_t)f << 1;
- }
- PyObject *o = PyLong_FromDouble(f);
- if (o == NULL)
- return CPY_INT_TAG;
- return CPyTagged_StealFromObject(o);
- }
- PyObject *CPyBool_Str(bool b) {
- return PyObject_Str(b ? Py_True : Py_False);
- }
- static void CPyLong_NormalizeUnsigned(PyLongObject *v) {
- Py_ssize_t i = CPY_LONG_SIZE_UNSIGNED(v);
- while (i > 0 && CPY_LONG_DIGIT(v, i - 1) == 0)
- i--;
- CPyLong_SetUnsignedSize(v, i);
- }
- // Bitwise op '&', '|' or '^' using the generic (slow) API
- static CPyTagged GenericBitwiseOp(CPyTagged a, CPyTagged b, char op) {
- PyObject *aobj = CPyTagged_AsObject(a);
- PyObject *bobj = CPyTagged_AsObject(b);
- PyObject *r;
- if (op == '&') {
- r = PyNumber_And(aobj, bobj);
- } else if (op == '|') {
- r = PyNumber_Or(aobj, bobj);
- } else {
- r = PyNumber_Xor(aobj, bobj);
- }
- if (unlikely(r == NULL)) {
- CPyError_OutOfMemory();
- }
- Py_DECREF(aobj);
- Py_DECREF(bobj);
- return CPyTagged_StealFromObject(r);
- }
- // Return pointer to digits of a PyLong object. If it's a short
- // integer, place digits in the buffer buf instead to avoid memory
- // allocation (it's assumed to be big enough). Return the number of
- // digits in *size. *size is negative if the integer is negative.
- static digit *GetIntDigits(CPyTagged n, Py_ssize_t *size, digit *buf) {
- if (CPyTagged_CheckShort(n)) {
- Py_ssize_t val = CPyTagged_ShortAsSsize_t(n);
- bool neg = val < 0;
- int len = 1;
- if (neg) {
- val = -val;
- }
- buf[0] = val & PyLong_MASK;
- if (val > (Py_ssize_t)PyLong_MASK) {
- val >>= PyLong_SHIFT;
- buf[1] = val & PyLong_MASK;
- if (val > (Py_ssize_t)PyLong_MASK) {
- buf[2] = val >> PyLong_SHIFT;
- len = 3;
- } else {
- len = 2;
- }
- }
- *size = neg ? -len : len;
- return buf;
- } else {
- PyLongObject *obj = (PyLongObject *)CPyTagged_LongAsObject(n);
- *size = CPY_LONG_SIZE_SIGNED(obj);
- return &CPY_LONG_DIGIT(obj, 0);
- }
- }
- // Shared implementation of bitwise '&', '|' and '^' (specified by op) for at least
- // one long operand. This is somewhat optimized for performance.
- static CPyTagged BitwiseLongOp(CPyTagged a, CPyTagged b, char op) {
- // Directly access the digits, as there is no fast C API function for this.
- digit abuf[3];
- digit bbuf[3];
- Py_ssize_t asize;
- Py_ssize_t bsize;
- digit *adigits = GetIntDigits(a, &asize, abuf);
- digit *bdigits = GetIntDigits(b, &bsize, bbuf);
- PyLongObject *r;
- if (unlikely(asize < 0 || bsize < 0)) {
- // Negative operand. This is slower, but bitwise ops on them are pretty rare.
- return GenericBitwiseOp(a, b, op);
- }
- // Optimized implementation for two non-negative integers.
- // Swap a and b as needed to ensure a is no longer than b.
- if (asize > bsize) {
- digit *tmp = adigits;
- adigits = bdigits;
- bdigits = tmp;
- Py_ssize_t tmp_size = asize;
- asize = bsize;
- bsize = tmp_size;
- }
- r = _PyLong_New(op == '&' ? asize : bsize);
- if (unlikely(r == NULL)) {
- CPyError_OutOfMemory();
- }
- Py_ssize_t i;
- if (op == '&') {
- for (i = 0; i < asize; i++) {
- CPY_LONG_DIGIT(r, i) = adigits[i] & bdigits[i];
- }
- } else {
- if (op == '|') {
- for (i = 0; i < asize; i++) {
- CPY_LONG_DIGIT(r, i) = adigits[i] | bdigits[i];
- }
- } else {
- for (i = 0; i < asize; i++) {
- CPY_LONG_DIGIT(r, i) = adigits[i] ^ bdigits[i];
- }
- }
- for (; i < bsize; i++) {
- CPY_LONG_DIGIT(r, i) = bdigits[i];
- }
- }
- CPyLong_NormalizeUnsigned(r);
- return CPyTagged_StealFromObject((PyObject *)r);
- }
- // Bitwise '&'
- CPyTagged CPyTagged_And(CPyTagged left, CPyTagged right) {
- if (likely(CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right))) {
- return left & right;
- }
- return BitwiseLongOp(left, right, '&');
- }
- // Bitwise '|'
- CPyTagged CPyTagged_Or(CPyTagged left, CPyTagged right) {
- if (likely(CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right))) {
- return left | right;
- }
- return BitwiseLongOp(left, right, '|');
- }
- // Bitwise '^'
- CPyTagged CPyTagged_Xor(CPyTagged left, CPyTagged right) {
- if (likely(CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right))) {
- return left ^ right;
- }
- return BitwiseLongOp(left, right, '^');
- }
- // Bitwise '~'
- CPyTagged CPyTagged_Invert(CPyTagged num) {
- if (likely(CPyTagged_CheckShort(num) && num != CPY_TAGGED_ABS_MIN)) {
- return ~num & ~CPY_INT_TAG;
- } else {
- PyObject *obj = CPyTagged_AsObject(num);
- PyObject *result = PyNumber_Invert(obj);
- if (unlikely(result == NULL)) {
- CPyError_OutOfMemory();
- }
- Py_DECREF(obj);
- return CPyTagged_StealFromObject(result);
- }
- }
- // Bitwise '>>'
- CPyTagged CPyTagged_Rshift(CPyTagged left, CPyTagged right) {
- if (likely(CPyTagged_CheckShort(left)
- && CPyTagged_CheckShort(right)
- && (Py_ssize_t)right >= 0)) {
- CPyTagged count = CPyTagged_ShortAsSsize_t(right);
- if (unlikely(count >= CPY_INT_BITS)) {
- if ((Py_ssize_t)left >= 0) {
- return 0;
- } else {
- return CPyTagged_ShortFromInt(-1);
- }
- }
- return ((Py_ssize_t)left >> count) & ~CPY_INT_TAG;
- } else {
- // Long integer or negative shift -- use generic op
- PyObject *lobj = CPyTagged_AsObject(left);
- PyObject *robj = CPyTagged_AsObject(right);
- PyObject *result = PyNumber_Rshift(lobj, robj);
- Py_DECREF(lobj);
- Py_DECREF(robj);
- if (result == NULL) {
- // Propagate error (could be negative shift count)
- return CPY_INT_TAG;
- }
- return CPyTagged_StealFromObject(result);
- }
- }
- static inline bool IsShortLshiftOverflow(Py_ssize_t short_int, Py_ssize_t shift) {
- return ((Py_ssize_t)(short_int << shift) >> shift) != short_int;
- }
- // Bitwise '<<'
- CPyTagged CPyTagged_Lshift(CPyTagged left, CPyTagged right) {
- if (likely(CPyTagged_CheckShort(left)
- && CPyTagged_CheckShort(right)
- && (Py_ssize_t)right >= 0
- && right < CPY_INT_BITS * 2)) {
- CPyTagged shift = CPyTagged_ShortAsSsize_t(right);
- if (!IsShortLshiftOverflow(left, shift))
- // Short integers, no overflow
- return left << shift;
- }
- // Long integer or out of range shift -- use generic op
- PyObject *lobj = CPyTagged_AsObject(left);
- PyObject *robj = CPyTagged_AsObject(right);
- PyObject *result = PyNumber_Lshift(lobj, robj);
- Py_DECREF(lobj);
- Py_DECREF(robj);
- if (result == NULL) {
- // Propagate error (could be negative shift count)
- return CPY_INT_TAG;
- }
- return CPyTagged_StealFromObject(result);
- }
- int64_t CPyLong_AsInt64(PyObject *o) {
- if (likely(PyLong_Check(o))) {
- PyLongObject *lobj = (PyLongObject *)o;
- Py_ssize_t size = Py_SIZE(lobj);
- if (likely(size == 1)) {
- // Fast path
- return CPY_LONG_DIGIT(lobj, 0);
- } else if (likely(size == 0)) {
- return 0;
- }
- }
- // Slow path
- int overflow;
- int64_t result = PyLong_AsLongLongAndOverflow(o, &overflow);
- if (result == -1) {
- if (PyErr_Occurred()) {
- return CPY_LL_INT_ERROR;
- } else if (overflow) {
- PyErr_SetString(PyExc_OverflowError, "int too large to convert to i64");
- return CPY_LL_INT_ERROR;
- }
- }
- return result;
- }
- int64_t CPyInt64_Divide(int64_t x, int64_t y) {
- if (y == 0) {
- PyErr_SetString(PyExc_ZeroDivisionError, "integer division or modulo by zero");
- return CPY_LL_INT_ERROR;
- }
- if (y == -1 && x == INT64_MIN) {
- PyErr_SetString(PyExc_OverflowError, "integer division overflow");
- return CPY_LL_INT_ERROR;
- }
- int64_t d = x / y;
- // Adjust for Python semantics
- if (((x < 0) != (y < 0)) && d * y != x) {
- d--;
- }
- return d;
- }
- int64_t CPyInt64_Remainder(int64_t x, int64_t y) {
- if (y == 0) {
- PyErr_SetString(PyExc_ZeroDivisionError, "integer division or modulo by zero");
- return CPY_LL_INT_ERROR;
- }
- // Edge case: avoid core dump
- if (y == -1 && x == INT64_MIN) {
- return 0;
- }
- int64_t d = x % y;
- // Adjust for Python semantics
- if (((x < 0) != (y < 0)) && d != 0) {
- d += y;
- }
- return d;
- }
- int32_t CPyLong_AsInt32(PyObject *o) {
- if (likely(PyLong_Check(o))) {
- #if CPY_3_12_FEATURES
- PyLongObject *lobj = (PyLongObject *)o;
- size_t tag = CPY_LONG_TAG(lobj);
- if (likely(tag == (1 << CPY_NON_SIZE_BITS))) {
- // Fast path
- return CPY_LONG_DIGIT(lobj, 0);
- } else if (likely(tag == CPY_SIGN_ZERO)) {
- return 0;
- }
- #else
- PyLongObject *lobj = (PyLongObject *)o;
- Py_ssize_t size = lobj->ob_base.ob_size;
- if (likely(size == 1)) {
- // Fast path
- return CPY_LONG_DIGIT(lobj, 0);
- } else if (likely(size == 0)) {
- return 0;
- }
- #endif
- }
- // Slow path
- int overflow;
- long result = PyLong_AsLongAndOverflow(o, &overflow);
- if (result > 0x7fffffffLL || result < -0x80000000LL) {
- overflow = 1;
- result = -1;
- }
- if (result == -1) {
- if (PyErr_Occurred()) {
- return CPY_LL_INT_ERROR;
- } else if (overflow) {
- PyErr_SetString(PyExc_OverflowError, "int too large to convert to i32");
- return CPY_LL_INT_ERROR;
- }
- }
- return result;
- }
- int32_t CPyInt32_Divide(int32_t x, int32_t y) {
- if (y == 0) {
- PyErr_SetString(PyExc_ZeroDivisionError, "integer division or modulo by zero");
- return CPY_LL_INT_ERROR;
- }
- if (y == -1 && x == INT32_MIN) {
- PyErr_SetString(PyExc_OverflowError, "integer division overflow");
- return CPY_LL_INT_ERROR;
- }
- int32_t d = x / y;
- // Adjust for Python semantics
- if (((x < 0) != (y < 0)) && d * y != x) {
- d--;
- }
- return d;
- }
- int32_t CPyInt32_Remainder(int32_t x, int32_t y) {
- if (y == 0) {
- PyErr_SetString(PyExc_ZeroDivisionError, "integer division or modulo by zero");
- return CPY_LL_INT_ERROR;
- }
- // Edge case: avoid core dump
- if (y == -1 && x == INT32_MIN) {
- return 0;
- }
- int32_t d = x % y;
- // Adjust for Python semantics
- if (((x < 0) != (y < 0)) && d != 0) {
- d += y;
- }
- return d;
- }
- void CPyInt32_Overflow() {
- PyErr_SetString(PyExc_OverflowError, "int too large to convert to i32");
- }
- int16_t CPyLong_AsInt16(PyObject *o) {
- if (likely(PyLong_Check(o))) {
- #if CPY_3_12_FEATURES
- PyLongObject *lobj = (PyLongObject *)o;
- size_t tag = CPY_LONG_TAG(lobj);
- if (likely(tag == (1 << CPY_NON_SIZE_BITS))) {
- // Fast path
- digit x = CPY_LONG_DIGIT(lobj, 0);
- if (x < 0x8000)
- return x;
- } else if (likely(tag == CPY_SIGN_ZERO)) {
- return 0;
- }
- #else
- PyLongObject *lobj = (PyLongObject *)o;
- Py_ssize_t size = lobj->ob_base.ob_size;
- if (likely(size == 1)) {
- // Fast path
- digit x = lobj->ob_digit[0];
- if (x < 0x8000)
- return x;
- } else if (likely(size == 0)) {
- return 0;
- }
- #endif
- }
- // Slow path
- int overflow;
- long result = PyLong_AsLongAndOverflow(o, &overflow);
- if (result > 0x7fff || result < -0x8000) {
- overflow = 1;
- result = -1;
- }
- if (result == -1) {
- if (PyErr_Occurred()) {
- return CPY_LL_INT_ERROR;
- } else if (overflow) {
- PyErr_SetString(PyExc_OverflowError, "int too large to convert to i16");
- return CPY_LL_INT_ERROR;
- }
- }
- return result;
- }
- int16_t CPyInt16_Divide(int16_t x, int16_t y) {
- if (y == 0) {
- PyErr_SetString(PyExc_ZeroDivisionError, "integer division or modulo by zero");
- return CPY_LL_INT_ERROR;
- }
- if (y == -1 && x == INT16_MIN) {
- PyErr_SetString(PyExc_OverflowError, "integer division overflow");
- return CPY_LL_INT_ERROR;
- }
- int16_t d = x / y;
- // Adjust for Python semantics
- if (((x < 0) != (y < 0)) && d * y != x) {
- d--;
- }
- return d;
- }
- int16_t CPyInt16_Remainder(int16_t x, int16_t y) {
- if (y == 0) {
- PyErr_SetString(PyExc_ZeroDivisionError, "integer division or modulo by zero");
- return CPY_LL_INT_ERROR;
- }
- // Edge case: avoid core dump
- if (y == -1 && x == INT16_MIN) {
- return 0;
- }
- int16_t d = x % y;
- // Adjust for Python semantics
- if (((x < 0) != (y < 0)) && d != 0) {
- d += y;
- }
- return d;
- }
- void CPyInt16_Overflow() {
- PyErr_SetString(PyExc_OverflowError, "int too large to convert to i16");
- }
- uint8_t CPyLong_AsUInt8(PyObject *o) {
- if (likely(PyLong_Check(o))) {
- #if CPY_3_12_FEATURES
- PyLongObject *lobj = (PyLongObject *)o;
- size_t tag = CPY_LONG_TAG(lobj);
- if (likely(tag == (1 << CPY_NON_SIZE_BITS))) {
- // Fast path
- digit x = CPY_LONG_DIGIT(lobj, 0);
- if (x < 256)
- return x;
- } else if (likely(tag == CPY_SIGN_ZERO)) {
- return 0;
- }
- #else
- PyLongObject *lobj = (PyLongObject *)o;
- Py_ssize_t size = lobj->ob_base.ob_size;
- if (likely(size == 1)) {
- // Fast path
- digit x = lobj->ob_digit[0];
- if (x < 256)
- return x;
- } else if (likely(size == 0)) {
- return 0;
- }
- #endif
- }
- // Slow path
- int overflow;
- long result = PyLong_AsLongAndOverflow(o, &overflow);
- if (result < 0 || result >= 256) {
- overflow = 1;
- result = -1;
- }
- if (result == -1) {
- if (PyErr_Occurred()) {
- return CPY_LL_UINT_ERROR;
- } else if (overflow) {
- PyErr_SetString(PyExc_OverflowError, "int too large or small to convert to u8");
- return CPY_LL_UINT_ERROR;
- }
- }
- return result;
- }
- void CPyUInt8_Overflow() {
- PyErr_SetString(PyExc_OverflowError, "int too large or small to convert to u8");
- }
- double CPyTagged_TrueDivide(CPyTagged x, CPyTagged y) {
- if (unlikely(y == 0)) {
- PyErr_SetString(PyExc_ZeroDivisionError, "division by zero");
- return CPY_FLOAT_ERROR;
- }
- if (likely(!CPyTagged_CheckLong(x) && !CPyTagged_CheckLong(y))) {
- return (double)((Py_ssize_t)x >> 1) / (double)((Py_ssize_t)y >> 1);
- } else {
- PyObject *xo = CPyTagged_AsObject(x);
- PyObject *yo = CPyTagged_AsObject(y);
- PyObject *result = PyNumber_TrueDivide(xo, yo);
- if (result == NULL) {
- return CPY_FLOAT_ERROR;
- }
- return PyFloat_AsDouble(result);
- }
- return 1.0;
- }
|