Skip to content
Merged
2 changes: 1 addition & 1 deletion Include/internal/pycore_opcode_metadata.h

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

19 changes: 10 additions & 9 deletions Include/internal/pycore_uop_ids.h

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

6 changes: 5 additions & 1 deletion Include/internal/pycore_uop_metadata.h

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

18 changes: 17 additions & 1 deletion Lib/test/test_capi/test_opt.py
Original file line number Diff line number Diff line change
Expand Up @@ -1819,9 +1819,10 @@ def testfunc(n):
self.assertIsNotNone(ex)
uops = get_opnames(ex)
# When the result of type(...) is known, _CALL_TYPE_1 is replaced with
# _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW which is optimized away in
# _SWAP_CALL_ONE_LOAD_CONST_INLINE_BORROW which is optimized away in
# remove_unneeded_uops.
self.assertNotIn("_CALL_TYPE_1", uops)
self.assertNotIn("_SWAP_CALL_ONE_LOAD_CONST_INLINE_BORROW", uops)
self.assertNotIn("_POP_CALL_ONE_LOAD_CONST_INLINE_BORROW", uops)
self.assertNotIn("_POP_CALL_LOAD_CONST_INLINE_BORROW", uops)
self.assertNotIn("_POP_TOP_LOAD_CONST_INLINE_BORROW", uops)
Expand All @@ -1841,6 +1842,21 @@ def testfunc(n):
uops = get_opnames(ex)
self.assertNotIn("_GUARD_IS_NOT_NONE_POP", uops)

def test_call_type_1_pop_top(self):
def testfunc(n):
x = 0
for _ in range(n):
foo = eval('42')
x += type(foo) is int
return x

res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
self.assertEqual(res, TIER2_THRESHOLD)
self.assertIsNotNone(ex)
uops = get_opnames(ex)
self.assertIn("_CALL_TYPE_1", uops)
self.assertIn("_POP_TOP_NOP", uops)

def test_call_str_1(self):
def testfunc(n):
x = 0
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Eliminate redundant refcounting from ``_CALL_TYPE_1``. Patch by Tomas Roun
23 changes: 16 additions & 7 deletions Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -4030,25 +4030,23 @@ dummy_func(
DEOPT_IF(callable_o != (PyObject *)&PyType_Type);
}

op(_CALL_TYPE_1, (callable, null, arg -- res)) {
op(_CALL_TYPE_1, (callable, null, arg -- res, a)) {
PyObject *arg_o = PyStackRef_AsPyObjectBorrow(arg);

assert(oparg == 1);
DEAD(null);
DEAD(callable);
(void)callable; // Silence compiler warnings about unused variables
(void)null;
STAT_INC(CALL, hit);
INPUTS_DEAD();
res = PyStackRef_FromPyObjectNew(Py_TYPE(arg_o));
PyStackRef_CLOSE(arg);
a = arg;
}

macro(CALL_TYPE_1) =
unused/1 +
unused/2 +
_GUARD_NOS_NULL +
_GUARD_CALLABLE_TYPE_1 +
_CALL_TYPE_1;
_CALL_TYPE_1 +
POP_TOP;

op(_GUARD_CALLABLE_STR_1, (callable, unused, unused -- callable, unused, unused)) {
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
Expand Down Expand Up @@ -5360,6 +5358,17 @@ dummy_func(
value = PyStackRef_FromPyObjectBorrow(ptr);
}

tier2 op(_SWAP_CALL_ONE_LOAD_CONST_INLINE_BORROW, (ptr/4, callable, null, arg -- value, a)) {
PyStackRef_CLOSE(arg);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be here, right? Because we're leaving arg on the stack in a?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Veery late response 😅 but I changed and renamed this op to _SHUFFLE_2_LOAD_CONST_INLINE_BORROW since it's analogous to the recently added _SHUFFLE_3_LOAD_CONST_INLINE_BORROW. This also resolves the issue with closing the ref! :)

(void)null; // Silence compiler warnings about unused variables
(void)callable;
DEAD(null);
DEAD(callable);
assert(_Py_IsImmortal(PyStackRef_AsPyObjectBorrow(callable)));
value = PyStackRef_FromPyObjectBorrow(ptr);
a = arg;
}

tier2 op(_LOAD_CONST_UNDER_INLINE, (ptr/4, old -- value, new)) {
new = old;
DEAD(old);
Expand Down
39 changes: 29 additions & 10 deletions Python/executor_cases.c.h

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

11 changes: 8 additions & 3 deletions Python/generated_cases.c.h

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

6 changes: 6 additions & 0 deletions Python/optimizer_analysis.c
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,9 @@ const uint16_t op_without_push[MAX_UOP_ID + 1] = {
[_POP_TOP_LOAD_CONST_INLINE] = _POP_TOP,
[_POP_TOP_LOAD_CONST_INLINE_BORROW] = _POP_TOP,
[_POP_TWO_LOAD_CONST_INLINE_BORROW] = _POP_TWO,
[_POP_CALL_ONE_LOAD_CONST_INLINE_BORROW] = _POP_CALL_ONE,
[_POP_CALL_TWO_LOAD_CONST_INLINE_BORROW] = _POP_CALL_TWO,
[_SWAP_CALL_ONE_LOAD_CONST_INLINE_BORROW] = _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW,
};

const bool op_skip[MAX_UOP_ID + 1] = {
Expand All @@ -578,6 +580,10 @@ const bool op_skip[MAX_UOP_ID + 1] = {

const uint16_t op_without_pop[MAX_UOP_ID + 1] = {
[_POP_TOP] = _NOP,
[_POP_TOP_NOP] = _NOP,
[_POP_TOP_INT] = _NOP,
[_POP_TOP_FLOAT] = _NOP,
[_POP_TOP_UNICODE] = _NOP,
[_POP_TOP_LOAD_CONST_INLINE] = _LOAD_CONST_INLINE,
[_POP_TOP_LOAD_CONST_INLINE_BORROW] = _LOAD_CONST_INLINE_BORROW,
[_POP_TWO] = _POP_TOP,
Expand Down
10 changes: 8 additions & 2 deletions Python/optimizer_bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,11 @@ dummy_func(void) {
value = PyJitRef_Borrow(sym_new_const(ctx, ptr));
}

op(_SWAP_CALL_ONE_LOAD_CONST_INLINE_BORROW, (ptr/4, unused, unused, arg -- value, a)) {
value = PyJitRef_Borrow(sym_new_const(ctx, ptr));
a = arg;
}

op(_POP_TOP, (value -- )) {
PyTypeObject *typ = sym_get_type(value);
if (PyJitRef_IsBorrowed(value) ||
Expand Down Expand Up @@ -969,16 +974,17 @@ dummy_func(void) {
next = sym_new_type(ctx, &PyLong_Type);
}

op(_CALL_TYPE_1, (unused, unused, arg -- res)) {
op(_CALL_TYPE_1, (unused, unused, arg -- res, a)) {
PyObject* type = (PyObject *)sym_get_type(arg);
if (type) {
res = sym_new_const(ctx, type);
REPLACE_OP(this_instr, _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW, 0,
REPLACE_OP(this_instr, _SWAP_CALL_ONE_LOAD_CONST_INLINE_BORROW, 0,
(uintptr_t)type);
}
else {
res = sym_new_not_null(ctx);
}
a = arg;
}

op(_CALL_STR_1, (unused, unused, arg -- res)) {
Expand Down
22 changes: 20 additions & 2 deletions Python/optimizer_cases.c.h

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

Loading