Skip to content

Commit df396b5

Browse files
gh-104909: Split BINARY_OP into micro-ops (#104910)
Co-authored-by: Brandt Bucher <[email protected]>
1 parent fbc9d0d commit df396b5

File tree

4 files changed

+785
-631
lines changed

4 files changed

+785
-631
lines changed

Python/bytecodes.c

Lines changed: 68 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -279,73 +279,111 @@ dummy_func(
279279

280280
family(binary_op, INLINE_CACHE_ENTRIES_BINARY_OP) = {
281281
BINARY_OP,
282-
BINARY_OP_ADD_FLOAT,
282+
BINARY_OP_MULTIPLY_INT,
283283
BINARY_OP_ADD_INT,
284-
BINARY_OP_ADD_UNICODE,
285-
// BINARY_OP_INPLACE_ADD_UNICODE, // This is an odd duck.
284+
BINARY_OP_SUBTRACT_INT,
286285
BINARY_OP_MULTIPLY_FLOAT,
287-
BINARY_OP_MULTIPLY_INT,
286+
BINARY_OP_ADD_FLOAT,
288287
BINARY_OP_SUBTRACT_FLOAT,
289-
BINARY_OP_SUBTRACT_INT,
288+
BINARY_OP_ADD_UNICODE,
289+
// BINARY_OP_INPLACE_ADD_UNICODE, // See comments at that opcode.
290290
};
291291

292-
293-
inst(BINARY_OP_MULTIPLY_INT, (unused/1, left, right -- prod)) {
292+
op(_GUARD_BOTH_INT, (left, right -- left, right)) {
294293
DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);
295294
DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP);
295+
}
296+
297+
op(_BINARY_OP_MULTIPLY_INT, (unused/1, left, right -- res)) {
296298
STAT_INC(BINARY_OP, hit);
297-
prod = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right);
299+
res = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right);
298300
_Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
299301
_Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);
300-
ERROR_IF(prod == NULL, error);
302+
ERROR_IF(res == NULL, error);
301303
}
302304

303-
inst(BINARY_OP_MULTIPLY_FLOAT, (unused/1, left, right -- prod)) {
304-
DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP);
305-
DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP);
305+
op(_BINARY_OP_ADD_INT, (unused/1, left, right -- res)) {
306306
STAT_INC(BINARY_OP, hit);
307-
double dprod = ((PyFloatObject *)left)->ob_fval *
308-
((PyFloatObject *)right)->ob_fval;
309-
DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dprod, prod);
307+
res = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right);
308+
_Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
309+
_Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);
310+
ERROR_IF(res == NULL, error);
310311
}
311312

312-
inst(BINARY_OP_SUBTRACT_INT, (unused/1, left, right -- sub)) {
313-
DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);
314-
DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP);
313+
op(_BINARY_OP_SUBTRACT_INT, (unused/1, left, right -- res)) {
315314
STAT_INC(BINARY_OP, hit);
316-
sub = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right);
315+
res = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right);
317316
_Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
318317
_Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);
319-
ERROR_IF(sub == NULL, error);
318+
ERROR_IF(res == NULL, error);
320319
}
321320

322-
inst(BINARY_OP_SUBTRACT_FLOAT, (unused/1, left, right -- sub)) {
321+
macro(BINARY_OP_MULTIPLY_INT) =
322+
_GUARD_BOTH_INT + _BINARY_OP_MULTIPLY_INT;
323+
macro(BINARY_OP_ADD_INT) =
324+
_GUARD_BOTH_INT + _BINARY_OP_ADD_INT;
325+
macro(BINARY_OP_SUBTRACT_INT) =
326+
_GUARD_BOTH_INT + _BINARY_OP_SUBTRACT_INT;
327+
328+
op(_GUARD_BOTH_FLOAT, (left, right -- left, right)) {
323329
DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP);
324330
DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP);
331+
}
332+
333+
op(_BINARY_OP_MULTIPLY_FLOAT, (unused/1, left, right -- res)) {
325334
STAT_INC(BINARY_OP, hit);
326-
double dsub = ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval;
327-
DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dsub, sub);
335+
double dres =
336+
((PyFloatObject *)left)->ob_fval *
337+
((PyFloatObject *)right)->ob_fval;
338+
DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res);
339+
}
340+
341+
op(_BINARY_OP_ADD_FLOAT, (unused/1, left, right -- res)) {
342+
STAT_INC(BINARY_OP, hit);
343+
double dres =
344+
((PyFloatObject *)left)->ob_fval +
345+
((PyFloatObject *)right)->ob_fval;
346+
DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res);
347+
}
348+
349+
op(_BINARY_OP_SUBTRACT_FLOAT, (unused/1, left, right -- res)) {
350+
STAT_INC(BINARY_OP, hit);
351+
double dres =
352+
((PyFloatObject *)left)->ob_fval -
353+
((PyFloatObject *)right)->ob_fval;
354+
DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res);
328355
}
329356

330-
inst(BINARY_OP_ADD_UNICODE, (unused/1, left, right -- res)) {
357+
macro(BINARY_OP_MULTIPLY_FLOAT) =
358+
_GUARD_BOTH_FLOAT + _BINARY_OP_MULTIPLY_FLOAT;
359+
macro(BINARY_OP_ADD_FLOAT) =
360+
_GUARD_BOTH_FLOAT + _BINARY_OP_ADD_FLOAT;
361+
macro(BINARY_OP_SUBTRACT_FLOAT) =
362+
_GUARD_BOTH_FLOAT + _BINARY_OP_SUBTRACT_FLOAT;
363+
364+
op(_GUARD_BOTH_UNICODE, (left, right -- left, right)) {
331365
DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP);
332-
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
366+
DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP);
367+
}
368+
369+
op(_BINARY_OP_ADD_UNICODE, (unused/1, left, right -- res)) {
333370
STAT_INC(BINARY_OP, hit);
334371
res = PyUnicode_Concat(left, right);
335372
_Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc);
336373
_Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc);
337374
ERROR_IF(res == NULL, error);
338375
}
339376

377+
macro(BINARY_OP_ADD_UNICODE) =
378+
_GUARD_BOTH_UNICODE + _BINARY_OP_ADD_UNICODE;
379+
340380
// This is a subtle one. It's a super-instruction for
341381
// BINARY_OP_ADD_UNICODE followed by STORE_FAST
342382
// where the store goes into the left argument.
343383
// So the inputs are the same as for all BINARY_OP
344384
// specializations, but there is no output.
345385
// At the end we just skip over the STORE_FAST.
346-
inst(BINARY_OP_INPLACE_ADD_UNICODE, (left, right --)) {
347-
DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP);
348-
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
386+
op(_BINARY_OP_INPLACE_ADD_UNICODE, (left, right --)) {
349387
_Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP];
350388
assert(true_next.op.code == STORE_FAST ||
351389
true_next.op.code == STORE_FAST__LOAD_FAST);
@@ -372,24 +410,8 @@ dummy_func(
372410
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP + 1);
373411
}
374412

375-
inst(BINARY_OP_ADD_FLOAT, (unused/1, left, right -- sum)) {
376-
DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP);
377-
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
378-
STAT_INC(BINARY_OP, hit);
379-
double dsum = ((PyFloatObject *)left)->ob_fval +
380-
((PyFloatObject *)right)->ob_fval;
381-
DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dsum, sum);
382-
}
383-
384-
inst(BINARY_OP_ADD_INT, (unused/1, left, right -- sum)) {
385-
DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);
386-
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
387-
STAT_INC(BINARY_OP, hit);
388-
sum = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right);
389-
_Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
390-
_Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);
391-
ERROR_IF(sum == NULL, error);
392-
}
413+
macro(BINARY_OP_INPLACE_ADD_UNICODE) =
414+
_GUARD_BOTH_UNICODE + _BINARY_OP_INPLACE_ADD_UNICODE;
393415

394416
family(binary_subscr, INLINE_CACHE_ENTRIES_BINARY_SUBSCR) = {
395417
BINARY_SUBSCR,

0 commit comments

Comments
 (0)