From adf36c3ca9116c2ff674f5c5ab5db84066b9575a Mon Sep 17 00:00:00 2001 From: Manjusaka Date: Tue, 8 Apr 2025 21:16:53 +0800 Subject: [PATCH 1/3] gh-131798: Allow the JIT to remove an extra _TO_BOOL_BOOL for _CONTAINS_OP_DICT Signed-off-by: Manjusaka --- Lib/test/test_capi/test_opt.py | 27 +++++++++++++++++++ ...-04-08-21-20-12.gh-issue-131798.Ft9tIF.rst | 2 ++ Python/optimizer_bytecodes.c | 4 +++ Python/optimizer_cases.c.h | 6 ++--- 4 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-04-08-21-20-12.gh-issue-131798.Ft9tIF.rst diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 0e13799ad47381..2f03d9dc483679 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -1629,6 +1629,33 @@ def testfunc(n): self.assertIn("_CONTAINS_OP_SET", uops) self.assertNotIn("_TO_BOOL_BOOL", uops) + def test_to_bool_bool_contains_op_dict(self): + """ + Test that _TO_BOOL_BOOL is removed from code like: + + res = foo in some_dict + if res: + .... + + """ + def testfunc(n): + x = 0 + s = {1: 1, 2: 2, 3: 3} + for _ in range(n): + a = 2 + in_set = a in s + if in_set: + x += 1 + 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("_CONTAINS_OP_DICT", uops) + self.assertNotIn("_TO_BOOL_BOOL", uops) + + def test_remove_guard_for_known_type_str(self): def f(n): for i in range(n): diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-08-21-20-12.gh-issue-131798.Ft9tIF.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-08-21-20-12.gh-issue-131798.Ft9tIF.rst new file mode 100644 index 00000000000000..90c0fb35f946b2 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-08-21-20-12.gh-issue-131798.Ft9tIF.rst @@ -0,0 +1,2 @@ +Allow the JIT to remove an extra ``_TO_BOOL_BOOL`` instruction after +``_CONTAINS_OP_DICT`` by setting the return type to bool. diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index d7b3564db1b90a..909ae884cb8b32 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -481,6 +481,10 @@ dummy_func(void) { res = sym_new_type(ctx, &PyBool_Type); } + op(_CONTAINS_OP_DICT, (left, right -- res)) { + res = sym_new_type(ctx, &PyBool_Type); + } + op(_LOAD_CONST, (-- value)) { PyObject *val = PyTuple_GET_ITEM(co->co_consts, this_instr->oparg); int opcode = _Py_IsImmortal(val) ? _LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE; diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 870c32d74ac913..14e61be8dc95c7 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1292,9 +1292,9 @@ } case _CONTAINS_OP_DICT: { - JitOptSymbol *b; - b = sym_new_not_null(ctx); - stack_pointer[-2] = b; + JitOptSymbol *res; + res = sym_new_type(ctx, &PyBool_Type); + stack_pointer[-2] = res; stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); break; From 266645520a21e4ac8144b63cfd91e21c08b68355 Mon Sep 17 00:00:00 2001 From: Nadeshiko Manju Date: Tue, 8 Apr 2025 21:42:41 +0800 Subject: [PATCH 2/3] Update Lib/test/test_capi/test_opt.py Co-authored-by: Tomas R. --- Lib/test/test_capi/test_opt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 2f03d9dc483679..e6e508ef037fbd 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -1643,7 +1643,7 @@ def testfunc(n): s = {1: 1, 2: 2, 3: 3} for _ in range(n): a = 2 - in_set = a in s + in_dict = a in s if in_set: x += 1 return x From 82121eebc69f395b51054f25281a326e71d8064b Mon Sep 17 00:00:00 2001 From: Manjusaka Date: Tue, 8 Apr 2025 21:43:31 +0800 Subject: [PATCH 3/3] fix review idea Signed-off-by: Manjusaka --- Lib/test/test_capi/test_opt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index e6e508ef037fbd..7e6c7749163dc6 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -1644,7 +1644,7 @@ def testfunc(n): for _ in range(n): a = 2 in_dict = a in s - if in_set: + if in_dict: x += 1 return x