Skip to content

Commit 964bb34

Browse files
committed
rework
1 parent befeded commit 964bb34

File tree

5 files changed

+351
-220
lines changed

5 files changed

+351
-220
lines changed

Python/bytecodes.c

Lines changed: 63 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -708,60 +708,102 @@ dummy_func(
708708
macro(BINARY_OP_SUBTRACT_INT) =
709709
_GUARD_TOS_INT + _GUARD_NOS_INT + unused/5 + _BINARY_OP_SUBTRACT_INT + _POP_TOP_INT + _POP_TOP_INT;
710710

711-
// Inplace compact int ops: mutate the uniquely-referenced operand
712-
// when the result is a non-small medium int. For small int results,
713-
// return the cached singleton. Deopt on overflow. Tier 2 only.
711+
// Inplace compact int ops: try to mutate the uniquely-referenced
712+
// operand. If TARGET is immortal (small int at runtime) or the
713+
// result doesn't fit, fall back to _PyCompactLong_*. Tier 2 only.
714714
tier2 op(_BINARY_OP_ADD_INT_INPLACE, (left, right -- res, l, r)) {
715715
INT_INPLACE_OP(left, right, left, +);
716-
EXIT_IF(_int_inplace_status == 2);
717-
res = _int_inplace_status == 1 ? _int_inplace_smallref : left;
718-
l = _int_inplace_status == 0 ? PyStackRef_NULL : left;
716+
if (_int_inplace_ok) {
717+
res = left;
718+
l = PyStackRef_NULL;
719+
}
720+
else {
721+
res = _PyCompactLong_Add((PyLongObject *)PyStackRef_AsPyObjectBorrow(left),
722+
(PyLongObject *)PyStackRef_AsPyObjectBorrow(right));
723+
EXIT_IF(PyStackRef_IsNull(res));
724+
l = left;
725+
}
719726
r = right;
720727
INPUTS_DEAD();
721728
}
722729

723730
tier2 op(_BINARY_OP_SUBTRACT_INT_INPLACE, (left, right -- res, l, r)) {
724731
INT_INPLACE_OP(left, right, left, -);
725-
EXIT_IF(_int_inplace_status == 2);
726-
res = _int_inplace_status == 1 ? _int_inplace_smallref : left;
727-
l = _int_inplace_status == 0 ? PyStackRef_NULL : left;
732+
if (_int_inplace_ok) {
733+
res = left;
734+
l = PyStackRef_NULL;
735+
}
736+
else {
737+
res = _PyCompactLong_Subtract((PyLongObject *)PyStackRef_AsPyObjectBorrow(left),
738+
(PyLongObject *)PyStackRef_AsPyObjectBorrow(right));
739+
EXIT_IF(PyStackRef_IsNull(res));
740+
l = left;
741+
}
728742
r = right;
729743
INPUTS_DEAD();
730744
}
731745

732746
tier2 op(_BINARY_OP_MULTIPLY_INT_INPLACE, (left, right -- res, l, r)) {
733747
INT_INPLACE_OP(left, right, left, *);
734-
EXIT_IF(_int_inplace_status == 2);
735-
res = _int_inplace_status == 1 ? _int_inplace_smallref : left;
736-
l = _int_inplace_status == 0 ? PyStackRef_NULL : left;
748+
if (_int_inplace_ok) {
749+
res = left;
750+
l = PyStackRef_NULL;
751+
}
752+
else {
753+
res = _PyCompactLong_Multiply((PyLongObject *)PyStackRef_AsPyObjectBorrow(left),
754+
(PyLongObject *)PyStackRef_AsPyObjectBorrow(right));
755+
EXIT_IF(PyStackRef_IsNull(res));
756+
l = left;
757+
}
737758
r = right;
738759
INPUTS_DEAD();
739760
}
740761

741762
tier2 op(_BINARY_OP_ADD_INT_INPLACE_RIGHT, (left, right -- res, l, r)) {
742763
INT_INPLACE_OP(left, right, right, +);
743-
EXIT_IF(_int_inplace_status == 2);
744-
res = _int_inplace_status == 1 ? _int_inplace_smallref : right;
764+
if (_int_inplace_ok) {
765+
res = right;
766+
r = PyStackRef_NULL;
767+
}
768+
else {
769+
res = _PyCompactLong_Add((PyLongObject *)PyStackRef_AsPyObjectBorrow(left),
770+
(PyLongObject *)PyStackRef_AsPyObjectBorrow(right));
771+
EXIT_IF(PyStackRef_IsNull(res));
772+
r = right;
773+
}
745774
l = left;
746-
r = _int_inplace_status == 0 ? PyStackRef_NULL : right;
747775
INPUTS_DEAD();
748776
}
749777

750778
tier2 op(_BINARY_OP_SUBTRACT_INT_INPLACE_RIGHT, (left, right -- res, l, r)) {
751779
INT_INPLACE_OP(left, right, right, -);
752-
EXIT_IF(_int_inplace_status == 2);
753-
res = _int_inplace_status == 1 ? _int_inplace_smallref : right;
780+
if (_int_inplace_ok) {
781+
res = right;
782+
r = PyStackRef_NULL;
783+
}
784+
else {
785+
res = _PyCompactLong_Subtract((PyLongObject *)PyStackRef_AsPyObjectBorrow(left),
786+
(PyLongObject *)PyStackRef_AsPyObjectBorrow(right));
787+
EXIT_IF(PyStackRef_IsNull(res));
788+
r = right;
789+
}
754790
l = left;
755-
r = _int_inplace_status == 0 ? PyStackRef_NULL : right;
756791
INPUTS_DEAD();
757792
}
758793

759794
tier2 op(_BINARY_OP_MULTIPLY_INT_INPLACE_RIGHT, (left, right -- res, l, r)) {
760795
INT_INPLACE_OP(left, right, right, *);
761-
EXIT_IF(_int_inplace_status == 2);
762-
res = _int_inplace_status == 1 ? _int_inplace_smallref : right;
796+
if (_int_inplace_ok) {
797+
res = right;
798+
r = PyStackRef_NULL;
799+
}
800+
else {
801+
res = _PyCompactLong_Multiply((PyLongObject *)PyStackRef_AsPyObjectBorrow(left),
802+
(PyLongObject *)PyStackRef_AsPyObjectBorrow(right));
803+
EXIT_IF(PyStackRef_IsNull(res));
804+
r = right;
805+
}
763806
l = left;
764-
r = _int_inplace_status == 0 ? PyStackRef_NULL : right;
765807
INPUTS_DEAD();
766808
}
767809

Python/ceval_macros.h

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -564,52 +564,49 @@ gen_try_set_executing(PyGenObject *gen)
564564
} while (0)
565565

566566
// Inplace compact int operation. Computes left OP right and attempts to
567-
// store the result in TARGET (which must be uniquely referenced).
568-
// After the macro:
569-
// _int_inplace_ok = 1: TARGET was mutated in place, res = TARGET
570-
// _int_inplace_ok = 0: result is a small int or overflow; caller
571-
// must fall back to _PyCompactLong_* and EXIT_IF
572-
// _int_inplace_status after macro:
573-
// 0 = mutated TARGET in place (res = TARGET)
574-
// 1 = result is a small int stored in _int_inplace_smallref
575-
// 2 = overflow, caller must EXIT_IF
567+
// Inplace compact int operation. TARGET is expected to be uniquely
568+
// referenced at the optimizer level, but at runtime it may be a
569+
// cached small int singleton. We check _Py_IsImmortal on TARGET
570+
// to decide whether inplace mutation is safe.
571+
//
572+
// _int_inplace_ok after macro:
573+
// 1 = mutated TARGET in place (caller should set res = TARGET)
574+
// 0 = TARGET was immortal (small int); caller should use the
575+
// standard _PyCompactLong_* function instead
576576
#define INT_INPLACE_OP(left, right, TARGET, OP) \
577-
int _int_inplace_status = 0; \
578-
_PyStackRef _int_inplace_smallref = PyStackRef_NULL; \
577+
int _int_inplace_ok = 0; \
579578
do { \
579+
PyObject *_target_o = PyStackRef_AsPyObjectBorrow(TARGET); \
580+
if (_Py_IsImmortal(_target_o)) { \
581+
break; \
582+
} \
580583
PyObject *_left_o = PyStackRef_AsPyObjectBorrow(left); \
581584
PyObject *_right_o = PyStackRef_AsPyObjectBorrow(right); \
582585
assert(PyLong_CheckExact(_left_o)); \
583586
assert(PyLong_CheckExact(_right_o)); \
584587
assert(_PyLong_BothAreCompact((PyLongObject *)_left_o, \
585588
(PyLongObject *)_right_o)); \
586-
assert(_PyObject_IsUniquelyReferenced( \
587-
PyStackRef_AsPyObjectBorrow(TARGET))); \
589+
assert(_PyObject_IsUniquelyReferenced(_target_o)); \
588590
STAT_INC(BINARY_OP, hit); \
589591
Py_ssize_t _left_val = _PyLong_CompactValue( \
590592
(PyLongObject *)_left_o); \
591593
Py_ssize_t _right_val = _PyLong_CompactValue( \
592594
(PyLongObject *)_right_o); \
593595
Py_ssize_t _result = _left_val OP _right_val; \
594-
if (_result >= -_PY_NSMALLNEGINTS \
595-
&& _result < _PY_NSMALLPOSINTS) { \
596-
_int_inplace_smallref = PyStackRef_FromPyObjectBorrow( \
597-
_PyLong_GetSmallInt(_result)); \
598-
_int_inplace_status = 1; \
599-
} \
600-
else if ((twodigits)((stwodigits)_result) + PyLong_MASK \
596+
/* Result must fit in a single digit and not be a small int */ \
597+
if (((twodigits)((stwodigits)_result) + PyLong_MASK \
601598
< (twodigits)PyLong_MASK + PyLong_BASE) \
599+
&& (_result < -_PY_NSMALLNEGINTS \
600+
|| _result >= _PY_NSMALLPOSINTS)) \
602601
{ \
603-
PyLongObject *_target = (PyLongObject *) \
604-
PyStackRef_AsPyObjectBorrow(TARGET); \
602+
PyLongObject *_target = (PyLongObject *)_target_o; \
605603
Py_ssize_t _sign = _result < 0 ? -1 : 1; \
606604
digit _abs = (digit)(_result < 0 ? -_result : _result); \
607605
_target->long_value.lv_tag = \
608606
(Py_ssize_t)_sign << _PyLong_NON_SIZE_BITS; \
609607
_target->long_value.ob_digit[0] = _abs; \
608+
_int_inplace_ok = 1; \
610609
} \
611-
else { \
612-
_int_inplace_status = 2; \
613-
} \
610+
/* else: result is small int or overflow — fall back */ \
614611
} while (0)
615612

0 commit comments

Comments
 (0)