From 285e47c3b2080c81df872f32939beb90fc0f1483 Mon Sep 17 00:00:00 2001 From: Noam Cohen Date: Fri, 6 Jun 2025 01:10:12 +0300 Subject: [PATCH 01/10] optimize `_UNARY_INVERT` --- Python/optimizer_bytecodes.c | 20 ++++++++++++++++++++ Python/optimizer_cases.c.h | 21 ++++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 34250fd4385d34..a164ba97d7c8ca 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -467,6 +467,26 @@ dummy_func(void) { res = sym_new_truthiness(ctx, value, false); } + op(_UNARY_INVERT, (value -- res)) { + if (sym_is_const(ctx, value)) { + PyObject *temp = PyNumber_Invert(sym_get_const(ctx, value)); + if (temp == NULL) { + goto error; + } + if (_Py_IsImmortal(temp)) { + REPLACE_OP(this_instr, _POP_TOP_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)temp); + } + res = sym_new_const(ctx, temp); + Py_DECREF(temp); + } else { + if (sym_matches_type(value, &PyLong_Type) || sym_matches_type(value, &PyBool_Type)) { + res = sym_new_type(ctx, &PyLong_Type); + } else { + res = sym_new_not_null(ctx); + } + } + } + op(_COMPARE_OP, (left, right -- res)) { if (oparg & 16) { res = sym_new_type(ctx, &PyBool_Type); diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index bbd45067103679..2dcada2691eb4d 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -285,8 +285,27 @@ } case _UNARY_INVERT: { + JitOptSymbol *value; JitOptSymbol *res; - res = sym_new_not_null(ctx); + value = stack_pointer[-1]; + if (sym_is_const(ctx, value)) { + PyObject *temp = PyNumber_Invert(sym_get_const(ctx, value)); + if (temp == NULL) { + goto error; + } + if (_Py_IsImmortal(temp)) { + REPLACE_OP(this_instr, _POP_TOP_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)temp); + } + res = sym_new_const(ctx, temp); + stack_pointer[-1] = res; + Py_DECREF(temp); + } else { + if (sym_matches_type(value, &PyLong_Type) || sym_matches_type(value, &PyBool_Type)) { + res = sym_new_type(ctx, &PyLong_Type); + } else { + res = sym_new_not_null(ctx); + } + } stack_pointer[-1] = res; break; } From 54f6df3614d9abce97ca82c107c90dfbd810d109 Mon Sep 17 00:00:00 2001 From: Noam Cohen Date: Fri, 6 Jun 2025 01:10:21 +0300 Subject: [PATCH 02/10] add test cases --- Lib/test/test_capi/test_opt.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index cb6eae484149ee..0c99d09525fa97 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -2219,6 +2219,36 @@ def f(n): self.assertNotIn("_LOAD_ATTR_METHOD_NO_DICT", uops) self.assertNotIn("_LOAD_ATTR_METHOD_LAZY_DICT", uops) + def test_unary_invert_long_type(self): + def testfunc(n): + for _ in range(n): + a = 9397 + x = ~a + ~a + + testfunc(TIER2_THRESHOLD) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + + self.assertNotIn("_GUARD_TOS_INT", uops) + self.assertNotIn("_GUARD_NOS_INT", uops) + + def test_unary_invert_replace(self): + def testfunc(n): + for _ in range(n): + a = -1 + a = ~a + + testfunc(TIER2_THRESHOLD) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + + self.assertNotIn("_UNARY_INVERT", uops) + self.assertIn("_LOAD_CONST_INLINE_BORROW", uops) + def global_identity(x): return x From 94a1907ac32cb261346bbb9c91a86942188a4dc3 Mon Sep 17 00:00:00 2001 From: Noam Cohen Date: Fri, 6 Jun 2025 01:10:27 +0300 Subject: [PATCH 03/10] add news entry --- .../2025-06-06-01-09-44.gh-issue-131798.1SuxO9.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-06-06-01-09-44.gh-issue-131798.1SuxO9.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-06-01-09-44.gh-issue-131798.1SuxO9.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-06-01-09-44.gh-issue-131798.1SuxO9.rst new file mode 100644 index 00000000000000..37a08a2d8e44b0 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-06-01-09-44.gh-issue-131798.1SuxO9.rst @@ -0,0 +1 @@ +Optimize ``_UNARY_INVERT`` From 4b99dac74ffaf2c29c0ed288f9b0f550aaab42a9 Mon Sep 17 00:00:00 2001 From: Noam Cohen Date: Fri, 6 Jun 2025 19:04:16 +0300 Subject: [PATCH 04/10] do not replace const ops --- Lib/test/test_capi/test_opt.py | 15 --------------- Python/optimizer_bytecodes.c | 21 +++++---------------- Python/optimizer_cases.c.h | 22 +++++----------------- 3 files changed, 10 insertions(+), 48 deletions(-) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 0c99d09525fa97..6409b2a14b8626 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -2234,21 +2234,6 @@ def testfunc(n): self.assertNotIn("_GUARD_TOS_INT", uops) self.assertNotIn("_GUARD_NOS_INT", uops) - def test_unary_invert_replace(self): - def testfunc(n): - for _ in range(n): - a = -1 - a = ~a - - testfunc(TIER2_THRESHOLD) - - ex = get_first_executor(testfunc) - self.assertIsNotNone(ex) - uops = get_opnames(ex) - - self.assertNotIn("_UNARY_INVERT", uops) - self.assertIn("_LOAD_CONST_INLINE_BORROW", uops) - def global_identity(x): return x diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index a164ba97d7c8ca..013d851ea5b241 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -468,22 +468,11 @@ dummy_func(void) { } op(_UNARY_INVERT, (value -- res)) { - if (sym_is_const(ctx, value)) { - PyObject *temp = PyNumber_Invert(sym_get_const(ctx, value)); - if (temp == NULL) { - goto error; - } - if (_Py_IsImmortal(temp)) { - REPLACE_OP(this_instr, _POP_TOP_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)temp); - } - res = sym_new_const(ctx, temp); - Py_DECREF(temp); - } else { - if (sym_matches_type(value, &PyLong_Type) || sym_matches_type(value, &PyBool_Type)) { - res = sym_new_type(ctx, &PyLong_Type); - } else { - res = sym_new_not_null(ctx); - } + if (sym_matches_type(value, &PyLong_Type) || sym_matches_type(value, &PyBool_Type)) { + res = sym_new_type(ctx, &PyLong_Type); + } + else { + res = sym_new_not_null(ctx); } } diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 2dcada2691eb4d..3a7ef74ad8bea1 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -288,23 +288,11 @@ JitOptSymbol *value; JitOptSymbol *res; value = stack_pointer[-1]; - if (sym_is_const(ctx, value)) { - PyObject *temp = PyNumber_Invert(sym_get_const(ctx, value)); - if (temp == NULL) { - goto error; - } - if (_Py_IsImmortal(temp)) { - REPLACE_OP(this_instr, _POP_TOP_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)temp); - } - res = sym_new_const(ctx, temp); - stack_pointer[-1] = res; - Py_DECREF(temp); - } else { - if (sym_matches_type(value, &PyLong_Type) || sym_matches_type(value, &PyBool_Type)) { - res = sym_new_type(ctx, &PyLong_Type); - } else { - res = sym_new_not_null(ctx); - } + if (sym_matches_type(value, &PyLong_Type) || sym_matches_type(value, &PyBool_Type)) { + res = sym_new_type(ctx, &PyLong_Type); + } + else { + res = sym_new_not_null(ctx); } stack_pointer[-1] = res; break; From ab7c1c744005ab8e4b09aaee81df67eea05779b3 Mon Sep 17 00:00:00 2001 From: Noam Cohen Date: Sat, 7 Jun 2025 09:48:15 +0300 Subject: [PATCH 05/10] add bool test case --- Lib/test/test_capi/test_opt.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 6409b2a14b8626..55c00f192d2478 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -2234,6 +2234,21 @@ def testfunc(n): self.assertNotIn("_GUARD_TOS_INT", uops) self.assertNotIn("_GUARD_NOS_INT", uops) + def test_unary_invert_bool_type(self): + def testfunc(n): + for _ in range(n): + a = True + x = ~a + ~a + + testfunc(TIER2_THRESHOLD) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + + self.assertNotIn("_GUARD_TOS_INT", uops) + self.assertNotIn("_GUARD_NOS_INT", uops) + def global_identity(x): return x From de5318450ab095b12ebf00b986690006eb0de081 Mon Sep 17 00:00:00 2001 From: Noam Cohen Date: Sat, 7 Jun 2025 09:51:52 +0300 Subject: [PATCH 06/10] better type-check --- Python/optimizer_bytecodes.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 013d851ea5b241..cc52b305757705 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -468,7 +468,8 @@ dummy_func(void) { } op(_UNARY_INVERT, (value -- res)) { - if (sym_matches_type(value, &PyLong_Type) || sym_matches_type(value, &PyBool_Type)) { + PyTypeObject *type = sym_get_type(value); + if (type == &PyLong_Type || type == &PyBool_Type) { res = sym_new_type(ctx, &PyLong_Type); } else { From 95f5ee2ba2e294aec18451720609f0814c849b88 Mon Sep 17 00:00:00 2001 From: Noam Cohen Date: Sat, 7 Jun 2025 09:53:34 +0300 Subject: [PATCH 07/10] fix news entry --- .../2025-06-06-01-09-44.gh-issue-131798.1SuxO9.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-06-01-09-44.gh-issue-131798.1SuxO9.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-06-01-09-44.gh-issue-131798.1SuxO9.rst index 37a08a2d8e44b0..a377526230659f 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-06-01-09-44.gh-issue-131798.1SuxO9.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-06-01-09-44.gh-issue-131798.1SuxO9.rst @@ -1 +1 @@ -Optimize ``_UNARY_INVERT`` +Optimize ``_UNARY_INVERT`` in JIT-compiled code. From 7e831ed6e38dcc6b91a86fa2285863857b49d8c2 Mon Sep 17 00:00:00 2001 From: Noam Cohen Date: Sat, 7 Jun 2025 10:00:01 +0300 Subject: [PATCH 08/10] regen cases --- Python/optimizer_cases.c.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 3a7ef74ad8bea1..70ee2968b27f8c 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -288,7 +288,8 @@ JitOptSymbol *value; JitOptSymbol *res; value = stack_pointer[-1]; - if (sym_matches_type(value, &PyLong_Type) || sym_matches_type(value, &PyBool_Type)) { + PyTypeObject *type = sym_get_type(value); + if (type == &PyLong_Type || type == &PyBool_Type) { res = sym_new_type(ctx, &PyLong_Type); } else { From e8015e3f85b6c2cbe1630ebd439be21317e9ac6d Mon Sep 17 00:00:00 2001 From: Noam Cohen Date: Sat, 7 Jun 2025 10:32:59 +0300 Subject: [PATCH 09/10] ignore warnings --- Lib/test/test_capi/test_opt.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 55c00f192d2478..ee7f879a553114 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -5,6 +5,7 @@ import unittest import gc import os +import warnings import _opcode @@ -2240,7 +2241,9 @@ def testfunc(n): a = True x = ~a + ~a - testfunc(TIER2_THRESHOLD) + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + testfunc(TIER2_THRESHOLD) ex = get_first_executor(testfunc) self.assertIsNotNone(ex) From 934654730c0123db9f8ddd05603e1fb73d15619e Mon Sep 17 00:00:00 2001 From: Noam Cohen Date: Mon, 9 Jun 2025 11:30:45 +0300 Subject: [PATCH 10/10] drop `bool` support --- Lib/test/test_capi/test_opt.py | 18 ------------------ Python/optimizer_bytecodes.c | 3 +-- Python/optimizer_cases.c.h | 3 +-- 3 files changed, 2 insertions(+), 22 deletions(-) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index ee7f879a553114..6409b2a14b8626 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -5,7 +5,6 @@ import unittest import gc import os -import warnings import _opcode @@ -2235,23 +2234,6 @@ def testfunc(n): self.assertNotIn("_GUARD_TOS_INT", uops) self.assertNotIn("_GUARD_NOS_INT", uops) - def test_unary_invert_bool_type(self): - def testfunc(n): - for _ in range(n): - a = True - x = ~a + ~a - - with warnings.catch_warnings(): - warnings.simplefilter("ignore") - testfunc(TIER2_THRESHOLD) - - ex = get_first_executor(testfunc) - self.assertIsNotNone(ex) - uops = get_opnames(ex) - - self.assertNotIn("_GUARD_TOS_INT", uops) - self.assertNotIn("_GUARD_NOS_INT", uops) - def global_identity(x): return x diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index cc52b305757705..6387cc78626ba4 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -468,8 +468,7 @@ dummy_func(void) { } op(_UNARY_INVERT, (value -- res)) { - PyTypeObject *type = sym_get_type(value); - if (type == &PyLong_Type || type == &PyBool_Type) { + if (sym_matches_type(value, &PyLong_Type)) { res = sym_new_type(ctx, &PyLong_Type); } else { diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 70ee2968b27f8c..3a6e59cad71f94 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -288,8 +288,7 @@ JitOptSymbol *value; JitOptSymbol *res; value = stack_pointer[-1]; - PyTypeObject *type = sym_get_type(value); - if (type == &PyLong_Type || type == &PyBool_Type) { + if (sym_matches_type(value, &PyLong_Type)) { res = sym_new_type(ctx, &PyLong_Type); } else {