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.

15 changes: 15 additions & 0 deletions Lib/test/test_capi/test_opt.py
Original file line number Diff line number Diff line change
Expand Up @@ -1841,6 +1841,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
21 changes: 14 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;
Comment thread
Fidget-Spinner marked this conversation as resolved.
Outdated
}

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,15 @@ 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
Copy Markdown
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
Copy Markdown
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
DEAD(null);
PyStackRef_CLOSE(callable);
Comment thread
Fidget-Spinner marked this conversation as resolved.
Outdated
value = PyStackRef_FromPyObjectBorrow(ptr);
a = arg;
}

tier2 op(_LOAD_CONST_UNDER_INLINE, (ptr/4, old -- value, new)) {
new = old;
DEAD(old);
Expand Down
44 changes: 34 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.

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);
Comment thread
Fidget-Spinner marked this conversation as resolved.
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