Skip to content

gh-131798: JIT: replace _CHECK_METHOD_VERSION with _CHECK_FUNCTION_VERSION_INLINE #135022

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions Lib/test/test_capi/test_opt.py
Original file line number Diff line number Diff line change
Expand Up @@ -1381,6 +1381,21 @@ def testfunc(n):
# Removed guard
self.assertNotIn("_CHECK_FUNCTION_EXACT_ARGS", uops)

def test_method_guards_removed_or_reduced(self):
def testfunc(n):
result = 0
for i in range(n):
result += test_bound_method(i)
return result
res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
self.assertEqual(res, sum(range(TIER2_THRESHOLD)))
self.assertIsNotNone(ex)
uops = get_opnames(ex)
self.assertIn("_PUSH_FRAME", uops)
# Strength reduced version
self.assertIn("_CHECK_FUNCTION_VERSION_INLINE", uops)
self.assertNotIn("_CHECK_METHOD_VERSION", uops)

def test_jit_error_pops(self):
"""
Tests that the correct number of pops are inserted into the
Expand Down Expand Up @@ -2279,5 +2294,12 @@ def f(n):
def global_identity(x):
return x

class TestObject:
def test(self, *args, **kwargs):
return args[0]

test_object = TestObject()
test_bound_method = TestObject.test.__get__(test_object)

Comment on lines +2297 to +2303
Copy link
Member

Choose a reason for hiding this comment

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

Can you move this into test_method_guards_removed_or_reduced? global_identity needs to be at module scope for other reasons that don't apply here.

Also, I think it can be simplified to something like:

class TestObject:
    def test(self, arg):
        return arg

test_bound_method = TestObject().test

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If I'm correct, TestObject().test will just generate _CHECK_FUNCTION_VERSION code, It's a normal function.

Reference the test code here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can you move this into test_method_guards_removed_or_reduced? global_identity needs to be at module scope for other reasons that don't apply here.

BTW, if I push the test object into the test_method_guards_removed_or_reduced. I think the method will not be treated by a const. So we the _CHECK_FUNCTION_VERSION_INLINE is not exist in final opcode.

Copy link
Member

Choose a reason for hiding this comment

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

@Zheaoli is right here. Can you please move this back to global scope? It seems tests are failing as the global method is not being promoted to a constant.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can you please move this back to global scope? It seems tests are failing as the global method is not being promoted to a constant.

Sure

if __name__ == "__main__":
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Optimize ``_CHECK_METHOD_VERSION`` into ``_CHECK_FUNCTION_VERSION_INLINE`` in JIT-compiled code.
10 changes: 10 additions & 0 deletions Python/optimizer_bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,16 @@ dummy_func(void) {
sym_set_type(callable, &PyFunction_Type);
}

op(_CHECK_METHOD_VERSION, (func_version/2, callable, null, unused[oparg] -- callable, null, unused[oparg])) {
if (sym_is_const(ctx, callable) && sym_matches_type(callable, &PyMethod_Type)) {
PyMethodObject *method = (PyMethodObject *)sym_get_const(ctx, callable);
assert(PyMethod_Check(method));
REPLACE_OP(this_instr, _CHECK_FUNCTION_VERSION_INLINE, 0, func_version);
this_instr->operand1 = (uintptr_t)method->im_func;
}
sym_set_type(callable, &PyMethod_Type);
}

op(_CHECK_FUNCTION_EXACT_ARGS, (callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) {
assert(sym_matches_type(callable, &PyFunction_Type));
if (sym_is_const(ctx, callable)) {
Expand Down
10 changes: 10 additions & 0 deletions Python/optimizer_cases.c.h

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

Loading