int_ops.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. // Int primitive operations (tagged arbitrary-precision integers)
  2. //
  3. // These are registered in mypyc.primitives.int_ops.
  4. #include <Python.h>
  5. #include "CPy.h"
  6. #ifndef _WIN32
  7. // On 64-bit Linux and macOS, ssize_t and long are both 64 bits, and
  8. // PyLong_FromLong is faster than PyLong_FromSsize_t, so use the faster one
  9. #define CPyLong_FromSsize_t PyLong_FromLong
  10. #else
  11. // On 64-bit Windows, ssize_t is 64 bits but long is 32 bits, so we
  12. // can't use the above trick
  13. #define CPyLong_FromSsize_t PyLong_FromSsize_t
  14. #endif
  15. CPyTagged CPyTagged_FromSsize_t(Py_ssize_t value) {
  16. // We use a Python object if the value shifted left by 1 is too
  17. // large for Py_ssize_t
  18. if (unlikely(CPyTagged_TooBig(value))) {
  19. PyObject *object = PyLong_FromSsize_t(value);
  20. return ((CPyTagged)object) | CPY_INT_TAG;
  21. } else {
  22. return value << 1;
  23. }
  24. }
  25. CPyTagged CPyTagged_FromVoidPtr(void *ptr) {
  26. if ((uintptr_t)ptr > PY_SSIZE_T_MAX) {
  27. PyObject *object = PyLong_FromVoidPtr(ptr);
  28. return ((CPyTagged)object) | CPY_INT_TAG;
  29. } else {
  30. return CPyTagged_FromSsize_t((Py_ssize_t)ptr);
  31. }
  32. }
  33. CPyTagged CPyTagged_FromInt64(int64_t value) {
  34. if (unlikely(CPyTagged_TooBigInt64(value))) {
  35. PyObject *object = PyLong_FromLongLong(value);
  36. return ((CPyTagged)object) | CPY_INT_TAG;
  37. } else {
  38. return value << 1;
  39. }
  40. }
  41. CPyTagged CPyTagged_FromObject(PyObject *object) {
  42. int overflow;
  43. // The overflow check knows about CPyTagged's width
  44. Py_ssize_t value = CPyLong_AsSsize_tAndOverflow(object, &overflow);
  45. if (unlikely(overflow != 0)) {
  46. Py_INCREF(object);
  47. return ((CPyTagged)object) | CPY_INT_TAG;
  48. } else {
  49. return value << 1;
  50. }
  51. }
  52. CPyTagged CPyTagged_StealFromObject(PyObject *object) {
  53. int overflow;
  54. // The overflow check knows about CPyTagged's width
  55. Py_ssize_t value = CPyLong_AsSsize_tAndOverflow(object, &overflow);
  56. if (unlikely(overflow != 0)) {
  57. return ((CPyTagged)object) | CPY_INT_TAG;
  58. } else {
  59. Py_DECREF(object);
  60. return value << 1;
  61. }
  62. }
  63. CPyTagged CPyTagged_BorrowFromObject(PyObject *object) {
  64. int overflow;
  65. // The overflow check knows about CPyTagged's width
  66. Py_ssize_t value = CPyLong_AsSsize_tAndOverflow(object, &overflow);
  67. if (unlikely(overflow != 0)) {
  68. return ((CPyTagged)object) | CPY_INT_TAG;
  69. } else {
  70. return value << 1;
  71. }
  72. }
  73. PyObject *CPyTagged_AsObject(CPyTagged x) {
  74. PyObject *value;
  75. if (unlikely(CPyTagged_CheckLong(x))) {
  76. value = CPyTagged_LongAsObject(x);
  77. Py_INCREF(value);
  78. } else {
  79. value = CPyLong_FromSsize_t(CPyTagged_ShortAsSsize_t(x));
  80. if (value == NULL) {
  81. CPyError_OutOfMemory();
  82. }
  83. }
  84. return value;
  85. }
  86. PyObject *CPyTagged_StealAsObject(CPyTagged x) {
  87. PyObject *value;
  88. if (unlikely(CPyTagged_CheckLong(x))) {
  89. value = CPyTagged_LongAsObject(x);
  90. } else {
  91. value = CPyLong_FromSsize_t(CPyTagged_ShortAsSsize_t(x));
  92. if (value == NULL) {
  93. CPyError_OutOfMemory();
  94. }
  95. }
  96. return value;
  97. }
  98. Py_ssize_t CPyTagged_AsSsize_t(CPyTagged x) {
  99. if (likely(CPyTagged_CheckShort(x))) {
  100. return CPyTagged_ShortAsSsize_t(x);
  101. } else {
  102. return PyLong_AsSsize_t(CPyTagged_LongAsObject(x));
  103. }
  104. }
  105. CPy_NOINLINE
  106. void CPyTagged_IncRef(CPyTagged x) {
  107. if (unlikely(CPyTagged_CheckLong(x))) {
  108. Py_INCREF(CPyTagged_LongAsObject(x));
  109. }
  110. }
  111. CPy_NOINLINE
  112. void CPyTagged_DecRef(CPyTagged x) {
  113. if (unlikely(CPyTagged_CheckLong(x))) {
  114. Py_DECREF(CPyTagged_LongAsObject(x));
  115. }
  116. }
  117. CPy_NOINLINE
  118. void CPyTagged_XDecRef(CPyTagged x) {
  119. if (unlikely(CPyTagged_CheckLong(x))) {
  120. Py_XDECREF(CPyTagged_LongAsObject(x));
  121. }
  122. }
  123. CPyTagged CPyTagged_Negate(CPyTagged num) {
  124. if (CPyTagged_CheckShort(num)
  125. && num != (CPyTagged) ((Py_ssize_t)1 << (CPY_INT_BITS - 1))) {
  126. // The only possibility of an overflow error happening when negating a short is if we
  127. // attempt to negate the most negative number.
  128. return -num;
  129. }
  130. PyObject *num_obj = CPyTagged_AsObject(num);
  131. PyObject *result = PyNumber_Negative(num_obj);
  132. if (result == NULL) {
  133. CPyError_OutOfMemory();
  134. }
  135. Py_DECREF(num_obj);
  136. return CPyTagged_StealFromObject(result);
  137. }
  138. CPyTagged CPyTagged_Add(CPyTagged left, CPyTagged right) {
  139. // TODO: Use clang/gcc extension __builtin_saddll_overflow instead.
  140. if (likely(CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right))) {
  141. CPyTagged sum = left + right;
  142. if (likely(!CPyTagged_IsAddOverflow(sum, left, right))) {
  143. return sum;
  144. }
  145. }
  146. PyObject *left_obj = CPyTagged_AsObject(left);
  147. PyObject *right_obj = CPyTagged_AsObject(right);
  148. PyObject *result = PyNumber_Add(left_obj, right_obj);
  149. if (result == NULL) {
  150. CPyError_OutOfMemory();
  151. }
  152. Py_DECREF(left_obj);
  153. Py_DECREF(right_obj);
  154. return CPyTagged_StealFromObject(result);
  155. }
  156. CPyTagged CPyTagged_Subtract(CPyTagged left, CPyTagged right) {
  157. // TODO: Use clang/gcc extension __builtin_saddll_overflow instead.
  158. if (likely(CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right))) {
  159. CPyTagged diff = left - right;
  160. if (likely(!CPyTagged_IsSubtractOverflow(diff, left, right))) {
  161. return diff;
  162. }
  163. }
  164. PyObject *left_obj = CPyTagged_AsObject(left);
  165. PyObject *right_obj = CPyTagged_AsObject(right);
  166. PyObject *result = PyNumber_Subtract(left_obj, right_obj);
  167. if (result == NULL) {
  168. CPyError_OutOfMemory();
  169. }
  170. Py_DECREF(left_obj);
  171. Py_DECREF(right_obj);
  172. return CPyTagged_StealFromObject(result);
  173. }
  174. CPyTagged CPyTagged_Multiply(CPyTagged left, CPyTagged right) {
  175. // TODO: Consider using some clang/gcc extension
  176. if (CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right)) {
  177. if (!CPyTagged_IsMultiplyOverflow(left, right)) {
  178. return left * CPyTagged_ShortAsSsize_t(right);
  179. }
  180. }
  181. PyObject *left_obj = CPyTagged_AsObject(left);
  182. PyObject *right_obj = CPyTagged_AsObject(right);
  183. PyObject *result = PyNumber_Multiply(left_obj, right_obj);
  184. if (result == NULL) {
  185. CPyError_OutOfMemory();
  186. }
  187. Py_DECREF(left_obj);
  188. Py_DECREF(right_obj);
  189. return CPyTagged_StealFromObject(result);
  190. }
  191. CPyTagged CPyTagged_FloorDivide(CPyTagged left, CPyTagged right) {
  192. if (CPyTagged_CheckShort(left)
  193. && CPyTagged_CheckShort(right)
  194. && !CPyTagged_MaybeFloorDivideFault(left, right)) {
  195. Py_ssize_t result = CPyTagged_ShortAsSsize_t(left) / CPyTagged_ShortAsSsize_t(right);
  196. if (((Py_ssize_t)left < 0) != (((Py_ssize_t)right) < 0)) {
  197. if (result * right != left) {
  198. // Round down
  199. result--;
  200. }
  201. }
  202. return result << 1;
  203. }
  204. PyObject *left_obj = CPyTagged_AsObject(left);
  205. PyObject *right_obj = CPyTagged_AsObject(right);
  206. PyObject *result = PyNumber_FloorDivide(left_obj, right_obj);
  207. Py_DECREF(left_obj);
  208. Py_DECREF(right_obj);
  209. // Handle exceptions honestly because it could be ZeroDivisionError
  210. if (result == NULL) {
  211. return CPY_INT_TAG;
  212. } else {
  213. return CPyTagged_StealFromObject(result);
  214. }
  215. }
  216. CPyTagged CPyTagged_Remainder(CPyTagged left, CPyTagged right) {
  217. if (CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right)
  218. && !CPyTagged_MaybeRemainderFault(left, right)) {
  219. Py_ssize_t result = (Py_ssize_t)left % (Py_ssize_t)right;
  220. if (((Py_ssize_t)right < 0) != ((Py_ssize_t)left < 0) && result != 0) {
  221. result += right;
  222. }
  223. return result;
  224. }
  225. PyObject *left_obj = CPyTagged_AsObject(left);
  226. PyObject *right_obj = CPyTagged_AsObject(right);
  227. PyObject *result = PyNumber_Remainder(left_obj, right_obj);
  228. Py_DECREF(left_obj);
  229. Py_DECREF(right_obj);
  230. // Handle exceptions honestly because it could be ZeroDivisionError
  231. if (result == NULL) {
  232. return CPY_INT_TAG;
  233. } else {
  234. return CPyTagged_StealFromObject(result);
  235. }
  236. }
  237. bool CPyTagged_IsEq_(CPyTagged left, CPyTagged right) {
  238. if (CPyTagged_CheckShort(right)) {
  239. return false;
  240. } else {
  241. PyObject *left_obj = CPyTagged_AsObject(left);
  242. PyObject *right_obj = CPyTagged_AsObject(right);
  243. int result = PyObject_RichCompareBool(left_obj, right_obj, Py_EQ);
  244. Py_DECREF(left_obj);
  245. Py_DECREF(right_obj);
  246. if (result == -1) {
  247. CPyError_OutOfMemory();
  248. }
  249. return result;
  250. }
  251. }
  252. bool CPyTagged_IsLt_(CPyTagged left, CPyTagged right) {
  253. PyObject *left_obj = CPyTagged_AsObject(left);
  254. PyObject *right_obj = CPyTagged_AsObject(right);
  255. int result = PyObject_RichCompareBool(left_obj, right_obj, Py_LT);
  256. Py_DECREF(left_obj);
  257. Py_DECREF(right_obj);
  258. if (result == -1) {
  259. CPyError_OutOfMemory();
  260. }
  261. return result;
  262. }
  263. PyObject *CPyLong_FromStrWithBase(PyObject *o, CPyTagged base) {
  264. Py_ssize_t base_size_t = CPyTagged_AsSsize_t(base);
  265. return PyLong_FromUnicodeObject(o, base_size_t);
  266. }
  267. PyObject *CPyLong_FromStr(PyObject *o) {
  268. CPyTagged base = CPyTagged_FromSsize_t(10);
  269. return CPyLong_FromStrWithBase(o, base);
  270. }
  271. CPyTagged CPyTagged_FromFloat(double f) {
  272. if (f < ((double)CPY_TAGGED_MAX + 1.0) && f > (CPY_TAGGED_MIN - 1.0)) {
  273. return (Py_ssize_t)f << 1;
  274. }
  275. PyObject *o = PyLong_FromDouble(f);
  276. if (o == NULL)
  277. return CPY_INT_TAG;
  278. return CPyTagged_StealFromObject(o);
  279. }
  280. PyObject *CPyBool_Str(bool b) {
  281. return PyObject_Str(b ? Py_True : Py_False);
  282. }
  283. static void CPyLong_NormalizeUnsigned(PyLongObject *v) {
  284. Py_ssize_t i = v->ob_base.ob_size;
  285. while (i > 0 && v->ob_digit[i - 1] == 0)
  286. i--;
  287. v->ob_base.ob_size = i;
  288. }
  289. // Bitwise op '&', '|' or '^' using the generic (slow) API
  290. static CPyTagged GenericBitwiseOp(CPyTagged a, CPyTagged b, char op) {
  291. PyObject *aobj = CPyTagged_AsObject(a);
  292. PyObject *bobj = CPyTagged_AsObject(b);
  293. PyObject *r;
  294. if (op == '&') {
  295. r = PyNumber_And(aobj, bobj);
  296. } else if (op == '|') {
  297. r = PyNumber_Or(aobj, bobj);
  298. } else {
  299. r = PyNumber_Xor(aobj, bobj);
  300. }
  301. if (unlikely(r == NULL)) {
  302. CPyError_OutOfMemory();
  303. }
  304. Py_DECREF(aobj);
  305. Py_DECREF(bobj);
  306. return CPyTagged_StealFromObject(r);
  307. }
  308. // Return pointer to digits of a PyLong object. If it's a short
  309. // integer, place digits in the buffer buf instead to avoid memory
  310. // allocation (it's assumed to be big enough). Return the number of
  311. // digits in *size. *size is negative if the integer is negative.
  312. static digit *GetIntDigits(CPyTagged n, Py_ssize_t *size, digit *buf) {
  313. if (CPyTagged_CheckShort(n)) {
  314. Py_ssize_t val = CPyTagged_ShortAsSsize_t(n);
  315. bool neg = val < 0;
  316. int len = 1;
  317. if (neg) {
  318. val = -val;
  319. }
  320. buf[0] = val & PyLong_MASK;
  321. if (val > (Py_ssize_t)PyLong_MASK) {
  322. val >>= PyLong_SHIFT;
  323. buf[1] = val & PyLong_MASK;
  324. if (val > (Py_ssize_t)PyLong_MASK) {
  325. buf[2] = val >> PyLong_SHIFT;
  326. len = 3;
  327. } else {
  328. len = 2;
  329. }
  330. }
  331. *size = neg ? -len : len;
  332. return buf;
  333. } else {
  334. PyLongObject *obj = (PyLongObject *)CPyTagged_LongAsObject(n);
  335. *size = obj->ob_base.ob_size;
  336. return obj->ob_digit;
  337. }
  338. }
  339. // Shared implementation of bitwise '&', '|' and '^' (specified by op) for at least
  340. // one long operand. This is somewhat optimized for performance.
  341. static CPyTagged BitwiseLongOp(CPyTagged a, CPyTagged b, char op) {
  342. // Directly access the digits, as there is no fast C API function for this.
  343. digit abuf[3];
  344. digit bbuf[3];
  345. Py_ssize_t asize;
  346. Py_ssize_t bsize;
  347. digit *adigits = GetIntDigits(a, &asize, abuf);
  348. digit *bdigits = GetIntDigits(b, &bsize, bbuf);
  349. PyLongObject *r;
  350. if (unlikely(asize < 0 || bsize < 0)) {
  351. // Negative operand. This is slower, but bitwise ops on them are pretty rare.
  352. return GenericBitwiseOp(a, b, op);
  353. }
  354. // Optimized implementation for two non-negative integers.
  355. // Swap a and b as needed to ensure a is no longer than b.
  356. if (asize > bsize) {
  357. digit *tmp = adigits;
  358. adigits = bdigits;
  359. bdigits = tmp;
  360. Py_ssize_t tmp_size = asize;
  361. asize = bsize;
  362. bsize = tmp_size;
  363. }
  364. r = _PyLong_New(op == '&' ? asize : bsize);
  365. if (unlikely(r == NULL)) {
  366. CPyError_OutOfMemory();
  367. }
  368. Py_ssize_t i;
  369. if (op == '&') {
  370. for (i = 0; i < asize; i++) {
  371. r->ob_digit[i] = adigits[i] & bdigits[i];
  372. }
  373. } else {
  374. if (op == '|') {
  375. for (i = 0; i < asize; i++) {
  376. r->ob_digit[i] = adigits[i] | bdigits[i];
  377. }
  378. } else {
  379. for (i = 0; i < asize; i++) {
  380. r->ob_digit[i] = adigits[i] ^ bdigits[i];
  381. }
  382. }
  383. for (; i < bsize; i++) {
  384. r->ob_digit[i] = bdigits[i];
  385. }
  386. }
  387. CPyLong_NormalizeUnsigned(r);
  388. return CPyTagged_StealFromObject((PyObject *)r);
  389. }
  390. // Bitwise '&'
  391. CPyTagged CPyTagged_And(CPyTagged left, CPyTagged right) {
  392. if (likely(CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right))) {
  393. return left & right;
  394. }
  395. return BitwiseLongOp(left, right, '&');
  396. }
  397. // Bitwise '|'
  398. CPyTagged CPyTagged_Or(CPyTagged left, CPyTagged right) {
  399. if (likely(CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right))) {
  400. return left | right;
  401. }
  402. return BitwiseLongOp(left, right, '|');
  403. }
  404. // Bitwise '^'
  405. CPyTagged CPyTagged_Xor(CPyTagged left, CPyTagged right) {
  406. if (likely(CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right))) {
  407. return left ^ right;
  408. }
  409. return BitwiseLongOp(left, right, '^');
  410. }
  411. // Bitwise '~'
  412. CPyTagged CPyTagged_Invert(CPyTagged num) {
  413. if (likely(CPyTagged_CheckShort(num) && num != CPY_TAGGED_ABS_MIN)) {
  414. return ~num & ~CPY_INT_TAG;
  415. } else {
  416. PyObject *obj = CPyTagged_AsObject(num);
  417. PyObject *result = PyNumber_Invert(obj);
  418. if (unlikely(result == NULL)) {
  419. CPyError_OutOfMemory();
  420. }
  421. Py_DECREF(obj);
  422. return CPyTagged_StealFromObject(result);
  423. }
  424. }
  425. // Bitwise '>>'
  426. CPyTagged CPyTagged_Rshift(CPyTagged left, CPyTagged right) {
  427. if (likely(CPyTagged_CheckShort(left)
  428. && CPyTagged_CheckShort(right)
  429. && (Py_ssize_t)right >= 0)) {
  430. CPyTagged count = CPyTagged_ShortAsSsize_t(right);
  431. if (unlikely(count >= CPY_INT_BITS)) {
  432. if ((Py_ssize_t)left >= 0) {
  433. return 0;
  434. } else {
  435. return CPyTagged_ShortFromInt(-1);
  436. }
  437. }
  438. return ((Py_ssize_t)left >> count) & ~CPY_INT_TAG;
  439. } else {
  440. // Long integer or negative shift -- use generic op
  441. PyObject *lobj = CPyTagged_AsObject(left);
  442. PyObject *robj = CPyTagged_AsObject(right);
  443. PyObject *result = PyNumber_Rshift(lobj, robj);
  444. Py_DECREF(lobj);
  445. Py_DECREF(robj);
  446. if (result == NULL) {
  447. // Propagate error (could be negative shift count)
  448. return CPY_INT_TAG;
  449. }
  450. return CPyTagged_StealFromObject(result);
  451. }
  452. }
  453. static inline bool IsShortLshiftOverflow(Py_ssize_t short_int, Py_ssize_t shift) {
  454. return ((Py_ssize_t)(short_int << shift) >> shift) != short_int;
  455. }
  456. // Bitwise '<<'
  457. CPyTagged CPyTagged_Lshift(CPyTagged left, CPyTagged right) {
  458. if (likely(CPyTagged_CheckShort(left)
  459. && CPyTagged_CheckShort(right)
  460. && (Py_ssize_t)right >= 0
  461. && right < CPY_INT_BITS * 2)) {
  462. CPyTagged shift = CPyTagged_ShortAsSsize_t(right);
  463. if (!IsShortLshiftOverflow(left, shift))
  464. // Short integers, no overflow
  465. return left << shift;
  466. }
  467. // Long integer or out of range shift -- use generic op
  468. PyObject *lobj = CPyTagged_AsObject(left);
  469. PyObject *robj = CPyTagged_AsObject(right);
  470. PyObject *result = PyNumber_Lshift(lobj, robj);
  471. Py_DECREF(lobj);
  472. Py_DECREF(robj);
  473. if (result == NULL) {
  474. // Propagate error (could be negative shift count)
  475. return CPY_INT_TAG;
  476. }
  477. return CPyTagged_StealFromObject(result);
  478. }
  479. int64_t CPyLong_AsInt64(PyObject *o) {
  480. if (likely(PyLong_Check(o))) {
  481. PyLongObject *lobj = (PyLongObject *)o;
  482. Py_ssize_t size = Py_SIZE(lobj);
  483. if (likely(size == 1)) {
  484. // Fast path
  485. return lobj->ob_digit[0];
  486. } else if (likely(size == 0)) {
  487. return 0;
  488. }
  489. }
  490. // Slow path
  491. int overflow;
  492. int64_t result = PyLong_AsLongLongAndOverflow(o, &overflow);
  493. if (result == -1) {
  494. if (PyErr_Occurred()) {
  495. return CPY_LL_INT_ERROR;
  496. } else if (overflow) {
  497. PyErr_SetString(PyExc_OverflowError, "int too large to convert to i64");
  498. return CPY_LL_INT_ERROR;
  499. }
  500. }
  501. return result;
  502. }
  503. int64_t CPyInt64_Divide(int64_t x, int64_t y) {
  504. if (y == 0) {
  505. PyErr_SetString(PyExc_ZeroDivisionError, "integer division or modulo by zero");
  506. return CPY_LL_INT_ERROR;
  507. }
  508. if (y == -1 && x == INT64_MIN) {
  509. PyErr_SetString(PyExc_OverflowError, "integer division overflow");
  510. return CPY_LL_INT_ERROR;
  511. }
  512. int64_t d = x / y;
  513. // Adjust for Python semantics
  514. if (((x < 0) != (y < 0)) && d * y != x) {
  515. d--;
  516. }
  517. return d;
  518. }
  519. int64_t CPyInt64_Remainder(int64_t x, int64_t y) {
  520. if (y == 0) {
  521. PyErr_SetString(PyExc_ZeroDivisionError, "integer division or modulo by zero");
  522. return CPY_LL_INT_ERROR;
  523. }
  524. // Edge case: avoid core dump
  525. if (y == -1 && x == INT64_MIN) {
  526. return 0;
  527. }
  528. int64_t d = x % y;
  529. // Adjust for Python semantics
  530. if (((x < 0) != (y < 0)) && d != 0) {
  531. d += y;
  532. }
  533. return d;
  534. }
  535. int32_t CPyLong_AsInt32(PyObject *o) {
  536. if (likely(PyLong_Check(o))) {
  537. PyLongObject *lobj = (PyLongObject *)o;
  538. Py_ssize_t size = lobj->ob_base.ob_size;
  539. if (likely(size == 1)) {
  540. // Fast path
  541. return lobj->ob_digit[0];
  542. } else if (likely(size == 0)) {
  543. return 0;
  544. }
  545. }
  546. // Slow path
  547. int overflow;
  548. long result = PyLong_AsLongAndOverflow(o, &overflow);
  549. if (result > 0x7fffffffLL || result < -0x80000000LL) {
  550. overflow = 1;
  551. result = -1;
  552. }
  553. if (result == -1) {
  554. if (PyErr_Occurred()) {
  555. return CPY_LL_INT_ERROR;
  556. } else if (overflow) {
  557. PyErr_SetString(PyExc_OverflowError, "int too large to convert to i32");
  558. return CPY_LL_INT_ERROR;
  559. }
  560. }
  561. return result;
  562. }
  563. int32_t CPyInt32_Divide(int32_t x, int32_t y) {
  564. if (y == 0) {
  565. PyErr_SetString(PyExc_ZeroDivisionError, "integer division or modulo by zero");
  566. return CPY_LL_INT_ERROR;
  567. }
  568. if (y == -1 && x == INT32_MIN) {
  569. PyErr_SetString(PyExc_OverflowError, "integer division overflow");
  570. return CPY_LL_INT_ERROR;
  571. }
  572. int32_t d = x / y;
  573. // Adjust for Python semantics
  574. if (((x < 0) != (y < 0)) && d * y != x) {
  575. d--;
  576. }
  577. return d;
  578. }
  579. int32_t CPyInt32_Remainder(int32_t x, int32_t y) {
  580. if (y == 0) {
  581. PyErr_SetString(PyExc_ZeroDivisionError, "integer division or modulo by zero");
  582. return CPY_LL_INT_ERROR;
  583. }
  584. // Edge case: avoid core dump
  585. if (y == -1 && x == INT32_MIN) {
  586. return 0;
  587. }
  588. int32_t d = x % y;
  589. // Adjust for Python semantics
  590. if (((x < 0) != (y < 0)) && d != 0) {
  591. d += y;
  592. }
  593. return d;
  594. }
  595. void CPyInt32_Overflow() {
  596. PyErr_SetString(PyExc_OverflowError, "int too large to convert to i32");
  597. }
  598. double CPyTagged_TrueDivide(CPyTagged x, CPyTagged y) {
  599. if (unlikely(y == 0)) {
  600. PyErr_SetString(PyExc_ZeroDivisionError, "division by zero");
  601. return CPY_FLOAT_ERROR;
  602. }
  603. if (likely(!CPyTagged_CheckLong(x) && !CPyTagged_CheckLong(y))) {
  604. return (double)((Py_ssize_t)x >> 1) / (double)((Py_ssize_t)y >> 1);
  605. } else {
  606. PyObject *xo = CPyTagged_AsObject(x);
  607. PyObject *yo = CPyTagged_AsObject(y);
  608. PyObject *result = PyNumber_TrueDivide(xo, yo);
  609. if (result == NULL) {
  610. return CPY_FLOAT_ERROR;
  611. }
  612. return PyFloat_AsDouble(result);
  613. }
  614. return 1.0;
  615. }