Skip to content

Commit 7b15873

Browse files
gh-135474: Specialize arithmetic only on compact ints (GH-135479)
Specialize arithmetic only on compact ints. This also makes int operations non-escaping in the JIT and in tier 1.
1 parent c8319a3 commit 7b15873

File tree

12 files changed

+81
-155
lines changed

12 files changed

+81
-155
lines changed

Doc/howto/perf_profiling.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ Then we can use ``perf report`` to analyze the data:
9292
| | | |
9393
| | | |--51.67%--_PyEval_EvalFrameDefault
9494
| | | | |
95-
| | | | |--11.52%--_PyLong_Add
95+
| | | | |--11.52%--_PyCompactLong_Add
9696
| | | | | |
9797
| | | | | |--2.97%--_PyObject_Malloc
9898
...
@@ -142,7 +142,7 @@ Instead, if we run the same experiment with ``perf`` support enabled we get:
142142
| | | |
143143
| | | |--51.81%--_PyEval_EvalFrameDefault
144144
| | | | |
145-
| | | | |--13.77%--_PyLong_Add
145+
| | | | |--13.77%--_PyCompactLong_Add
146146
| | | | | |
147147
| | | | | |--3.26%--_PyObject_Malloc
148148

Include/internal/pycore_long.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,9 @@ PyAPI_DATA(PyObject*) _PyLong_Rshift(PyObject *, int64_t);
112112
// Export for 'math' shared extension
113113
PyAPI_DATA(PyObject*) _PyLong_Lshift(PyObject *, int64_t);
114114

115-
PyAPI_FUNC(PyObject*) _PyLong_Add(PyLongObject *left, PyLongObject *right);
116-
PyAPI_FUNC(PyObject*) _PyLong_Multiply(PyLongObject *left, PyLongObject *right);
117-
PyAPI_FUNC(PyObject*) _PyLong_Subtract(PyLongObject *left, PyLongObject *right);
115+
PyAPI_FUNC(PyObject*) _PyCompactLong_Add(PyLongObject *left, PyLongObject *right);
116+
PyAPI_FUNC(PyObject*) _PyCompactLong_Multiply(PyLongObject *left, PyLongObject *right);
117+
PyAPI_FUNC(PyObject*) _PyCompactLong_Subtract(PyLongObject *left, PyLongObject *right);
118118

119119
// Export for 'binascii' shared extension.
120120
PyAPI_DATA(unsigned char) _PyLong_DigitValue[256];

Include/internal/pycore_opcode_metadata.h

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_uop_metadata.h

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Specialize integer operations only on compact integers. This is a CPython internal change.

Objects/longobject.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3772,9 +3772,11 @@ long_add(PyLongObject *a, PyLongObject *b)
37723772
}
37733773

37743774
PyObject *
3775-
_PyLong_Add(PyLongObject *a, PyLongObject *b)
3775+
_PyCompactLong_Add(PyLongObject *a, PyLongObject *b)
37763776
{
3777-
return (PyObject*)long_add(a, b);
3777+
assert(_PyLong_BothAreCompact(a, b));
3778+
stwodigits z = medium_value(a) + medium_value(b);
3779+
return (PyObject *)_PyLong_FromSTwoDigits(z);
37783780
}
37793781

37803782
static PyObject *
@@ -3815,9 +3817,10 @@ long_sub(PyLongObject *a, PyLongObject *b)
38153817
}
38163818

38173819
PyObject *
3818-
_PyLong_Subtract(PyLongObject *a, PyLongObject *b)
3820+
_PyCompactLong_Subtract(PyLongObject *a, PyLongObject *b)
38193821
{
3820-
return (PyObject*)long_sub(a, b);
3822+
assert(_PyLong_BothAreCompact(a, b));
3823+
return (PyObject *)_PyLong_FromSTwoDigits(medium_value(a) - medium_value(b));
38213824
}
38223825

38233826
static PyObject *
@@ -4262,9 +4265,11 @@ long_mul(PyLongObject *a, PyLongObject *b)
42624265
}
42634266

42644267
PyObject *
4265-
_PyLong_Multiply(PyLongObject *a, PyLongObject *b)
4268+
_PyCompactLong_Multiply(PyLongObject *a, PyLongObject *b)
42664269
{
4267-
return (PyObject*)long_mul(a, b);
4270+
assert(_PyLong_BothAreCompact(a, b));
4271+
stwodigits v = medium_value(a) * medium_value(b);
4272+
return (PyObject *)_PyLong_FromSTwoDigits(v);
42684273
}
42694274

42704275
static PyObject *

Python/bytecodes.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -582,9 +582,10 @@ dummy_func(
582582
PyObject *right_o = PyStackRef_AsPyObjectBorrow(right);
583583
assert(PyLong_CheckExact(left_o));
584584
assert(PyLong_CheckExact(right_o));
585+
DEOPT_IF(!_PyLong_BothAreCompact((PyLongObject *)left_o, (PyLongObject *)right_o));
585586

586587
STAT_INC(BINARY_OP, hit);
587-
PyObject *res_o = _PyLong_Multiply((PyLongObject *)left_o, (PyLongObject *)right_o);
588+
PyObject *res_o = _PyCompactLong_Multiply((PyLongObject *)left_o, (PyLongObject *)right_o);
588589
PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc);
589590
PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc);
590591
INPUTS_DEAD();
@@ -597,9 +598,10 @@ dummy_func(
597598
PyObject *right_o = PyStackRef_AsPyObjectBorrow(right);
598599
assert(PyLong_CheckExact(left_o));
599600
assert(PyLong_CheckExact(right_o));
601+
DEOPT_IF(!_PyLong_BothAreCompact((PyLongObject *)left_o, (PyLongObject *)right_o));
600602

601603
STAT_INC(BINARY_OP, hit);
602-
PyObject *res_o = _PyLong_Add((PyLongObject *)left_o, (PyLongObject *)right_o);
604+
PyObject *res_o = _PyCompactLong_Add((PyLongObject *)left_o, (PyLongObject *)right_o);
603605
PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc);
604606
PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc);
605607
INPUTS_DEAD();
@@ -612,9 +614,10 @@ dummy_func(
612614
PyObject *right_o = PyStackRef_AsPyObjectBorrow(right);
613615
assert(PyLong_CheckExact(left_o));
614616
assert(PyLong_CheckExact(right_o));
617+
DEOPT_IF(!_PyLong_BothAreCompact((PyLongObject *)left_o, (PyLongObject *)right_o));
615618

616619
STAT_INC(BINARY_OP, hit);
617-
PyObject *res_o = _PyLong_Subtract((PyLongObject *)left_o, (PyLongObject *)right_o);
620+
PyObject *res_o = _PyCompactLong_Subtract((PyLongObject *)left_o, (PyLongObject *)right_o);
618621
PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc);
619622
PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc);
620623
INPUTS_DEAD();

Python/executor_cases.c.h

Lines changed: 15 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/generated_cases.c.h

Lines changed: 18 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/optimizer_bytecodes.c

Lines changed: 3 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -222,60 +222,15 @@ dummy_func(void) {
222222
}
223223

224224
op(_BINARY_OP_ADD_INT, (left, right -- res)) {
225-
if (sym_is_const(ctx, left) && sym_is_const(ctx, right)) {
226-
assert(PyLong_CheckExact(sym_get_const(ctx, left)));
227-
assert(PyLong_CheckExact(sym_get_const(ctx, right)));
228-
PyObject *temp = _PyLong_Add((PyLongObject *)sym_get_const(ctx, left),
229-
(PyLongObject *)sym_get_const(ctx, right));
230-
if (temp == NULL) {
231-
goto error;
232-
}
233-
res = sym_new_const(ctx, temp);
234-
Py_DECREF(temp);
235-
// TODO gh-115506:
236-
// replace opcode with constant propagated one and add tests!
237-
}
238-
else {
239-
res = sym_new_type(ctx, &PyLong_Type);
240-
}
225+
res = sym_new_type(ctx, &PyLong_Type);
241226
}
242227

243228
op(_BINARY_OP_SUBTRACT_INT, (left, right -- res)) {
244-
if (sym_is_const(ctx, left) && sym_is_const(ctx, right)) {
245-
assert(PyLong_CheckExact(sym_get_const(ctx, left)));
246-
assert(PyLong_CheckExact(sym_get_const(ctx, right)));
247-
PyObject *temp = _PyLong_Subtract((PyLongObject *)sym_get_const(ctx, left),
248-
(PyLongObject *)sym_get_const(ctx, right));
249-
if (temp == NULL) {
250-
goto error;
251-
}
252-
res = sym_new_const(ctx, temp);
253-
Py_DECREF(temp);
254-
// TODO gh-115506:
255-
// replace opcode with constant propagated one and add tests!
256-
}
257-
else {
258-
res = sym_new_type(ctx, &PyLong_Type);
259-
}
229+
res = sym_new_type(ctx, &PyLong_Type);
260230
}
261231

262232
op(_BINARY_OP_MULTIPLY_INT, (left, right -- res)) {
263-
if (sym_is_const(ctx, left) && sym_is_const(ctx, right)) {
264-
assert(PyLong_CheckExact(sym_get_const(ctx, left)));
265-
assert(PyLong_CheckExact(sym_get_const(ctx, right)));
266-
PyObject *temp = _PyLong_Multiply((PyLongObject *)sym_get_const(ctx, left),
267-
(PyLongObject *)sym_get_const(ctx, right));
268-
if (temp == NULL) {
269-
goto error;
270-
}
271-
res = sym_new_const(ctx, temp);
272-
Py_DECREF(temp);
273-
// TODO gh-115506:
274-
// replace opcode with constant propagated one and add tests!
275-
}
276-
else {
277-
res = sym_new_type(ctx, &PyLong_Type);
278-
}
233+
res = sym_new_type(ctx, &PyLong_Type);
279234
}
280235

281236
op(_BINARY_OP_ADD_FLOAT, (left, right -- res)) {

0 commit comments

Comments
 (0)