Skip to content
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
eb67609
JIT: widen int fast path to full int64 range
KRRT7 May 20, 2026
1181bf0
cleanup
KRRT7 May 25, 2026
8624d26
Fix widened JIT int fast paths
KRRT7 May 25, 2026
91854c2
Add widened JIT int boundary tests
KRRT7 May 25, 2026
e0089f7
Merge branch 'main' into jit-wide-int-fastpath
KRRT7 May 25, 2026
160d3cd
fix failing unit tests
KRRT7 May 26, 2026
32d6758
Merge branch 'main' into jit-wide-int-fastpath
KRRT7 May 28, 2026
a67837c
WIP
KRRT7 May 28, 2026
fd45492
Merge branch 'main' into jit-wide-int-fastpath
KRRT7 May 28, 2026
1d667d4
Update Misc/NEWS.d/next/Core_and_Builtins/2026-05-28-15-00-00.gh-issu…
KRRT7 May 28, 2026
41ad8fb
Update pycore_long.h
KRRT7 May 28, 2026
d549674
Restore compact fast path in _PyCompactLong_{Add,Subtract,Multiply}; …
KRRT7 May 28, 2026
094a60a
Split BINARY_OP_ADD/SUBTRACT/MULTIPLY_INT into compact and wide speci…
KRRT7 May 28, 2026
8769659
Update jit_int_benchmark_pyperf.py
KRRT7 May 29, 2026
7775456
Merge branch 'main' into jit-wide-int-fastpath
KRRT7 May 29, 2026
f206055
fix failing tests
KRRT7 May 29, 2026
39ae2f2
Fix wide int guard range and optimizer facts
KRRT7 May 29, 2026
f35d39b
Rename int64 guard helper and drop simple benchmark
KRRT7 May 29, 2026
4d49566
Separate compact int and int64 optimizer facts
KRRT7 May 29, 2026
e6fd6d8
Merge branch 'main' into jit-wide-int-fastpath
KRRT7 May 29, 2026
d4a355c
tier1-merged tier2-split: single BINARY_OP_ADD_INT with optimizer gua…
KRRT7 May 29, 2026
d608803
Port merged design from explore/merged-on-main
KRRT7 May 29, 2026
5e01840
Fix SUBSCR_LIST_INT/STORE_SUBSCR_LIST_INT asserting on wide ints
KRRT7 May 29, 2026
24a0d2a
Update Include/internal/pycore_long.h
KRRT7 May 29, 2026
a4c0ddb
edit based on feedback
KRRT7 May 29, 2026
c7800d9
Merge branch 'main' into jit-wide-int-fastpath
KRRT7 Jun 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions Include/internal/pycore_long.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ _PyLong_BothAreCompact(const PyLongObject* a, const PyLongObject* b) {
static inline bool
_PyLong_IsZero(const PyLongObject *op)
{
assert(op != NULL);
return (op->long_value.lv_tag & SIGN_MASK) == SIGN_ZERO;
}

Expand Down Expand Up @@ -346,6 +347,87 @@ _PyLong_CheckExactAndCompact(PyObject *op)
return PyLong_CheckExact(op) && _PyLong_IsCompact((const PyLongObject *)op);
}

/* A cheap guard used by Tier 2 / JIT integer fast paths.
*
* "Compact" ints are single-digit. Non-compact ints may still fit in int64_t,
* but are limited to a small number of digits (3 for 30-bit digits, 5 for
* 15-bit digits). This is an intentionally cheap filter: callers must still
* do an exact range check during extraction.
*/
#define _PY_LONG_MAX_DIGITS_FOR_INT64 ((64 + PyLong_SHIFT - 1) / PyLong_SHIFT)

static inline int
_PyLong_CheckExactAndMightFitInt64(PyObject *op)
{
if (!PyLong_CheckExact(op)) {
return 0;
}
const PyLongObject *v = (const PyLongObject *)op;
if (_PyLong_IsCompact(v)) {
return 1;
}
Py_ssize_t ndigits = _PyLong_DigitCount(v);
if (ndigits > _PY_LONG_MAX_DIGITS_FOR_INT64) {
return 0;
}
if (ndigits == _PY_LONG_MAX_DIGITS_FOR_INT64) {
unsigned int shift = PyLong_SHIFT * (unsigned int)(ndigits - 1);
uint64_t max_pos_top = (uint64_t)INT64_MAX >> shift;
uint64_t max_neg_top = ((uint64_t)INT64_MAX + 1) >> shift; /* abs(INT64_MIN) */
uint64_t max_top = ((v->long_value.lv_tag & SIGN_MASK) == SIGN_NEGATIVE)
? max_neg_top
: max_pos_top;
return (uint64_t)v->long_value.ob_digit[ndigits - 1] <= max_top;
}
return 1;
}

/* Extract an exact int to int64_t without raising.
*
* Returns true on success and writes to *out; returns false if the value is
* out of int64_t range. Never sets an exception.
*/
static inline bool
_PyLong_TryAsInt64Exact(PyLongObject *v, int64_t *out)
{
assert(PyLong_CheckExact((PyObject *)v));
if (_PyLong_IsCompact(v)) {
*out = (int64_t)_PyLong_CompactValue(v);
return true;
}
Py_ssize_t ndigits = _PyLong_DigitCount(v);
if (ndigits == 0) {
*out = 0;
return true;
}
Comment thread
KRRT7 marked this conversation as resolved.
Outdated
if (ndigits > _PY_LONG_MAX_DIGITS_FOR_INT64) {
return false;
}
uint64_t abs_val = 0;
unsigned int shift = 0;
for (Py_ssize_t i = 0; i < ndigits; i++) {
uint64_t d = (uint64_t)v->long_value.ob_digit[i];
if (shift >= 64) {
return false;
}
if (shift != 0 && (d >> (64 - shift)) != 0) {
return false;
}
Comment thread
KRRT7 marked this conversation as resolved.
Outdated
abs_val |= d << shift;
shift += PyLong_SHIFT;
}
int sign = 1 - (v->long_value.lv_tag & SIGN_MASK);
if (abs_val <= (uint64_t)INT64_MAX) {
*out = sign < 0 ? -(int64_t)abs_val : (int64_t)abs_val;
return true;
}
if (sign < 0 && abs_val == (uint64_t)INT64_MAX + 1) {
*out = INT64_MIN;
Comment thread
KRRT7 marked this conversation as resolved.
return true;
}
return false;
}

#ifdef __cplusplus
}
#endif
Expand Down
8 changes: 4 additions & 4 deletions Include/internal/pycore_opcode_metadata.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading