]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
GH-131798: Optimize away type(x) in the JIT when the result is known (GH-135194)
authorTomas R. <tomas.roun8@gmail.com>
Fri, 6 Jun 2025 23:44:43 +0000 (01:44 +0200)
committerGitHub <noreply@github.com>
Fri, 6 Jun 2025 23:44:43 +0000 (16:44 -0700)
Lib/test/test_capi/test_opt.py
Misc/NEWS.d/next/Core_and_Builtins/2025-06-05-21-58-30.gh-issue-131798.nt5Ab7.rst [new file with mode: 0644]
Python/optimizer_bytecodes.c
Python/optimizer_cases.c.h

index a292ebcc7f4aed987bfa9c82f97166d0b3e01ef6..ee8d261685d4632176fc339b07dcff0324ac09ee 100644 (file)
@@ -1778,11 +1778,12 @@ class TestUopsOptimization(unittest.TestCase):
         self.assertNotIn("_GUARD_TOS_UNICODE", uops)
         self.assertIn("_BINARY_OP_ADD_UNICODE", uops)
 
-    def test_call_type_1(self):
+    def test_call_type_1_guards_removed(self):
         def testfunc(n):
             x = 0
             for _ in range(n):
-                x += type(42) is int
+                foo = eval('42')
+                x += type(foo) is int
             return x
 
         res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
@@ -1793,6 +1794,25 @@ class TestUopsOptimization(unittest.TestCase):
         self.assertNotIn("_GUARD_NOS_NULL", uops)
         self.assertNotIn("_GUARD_CALLABLE_TYPE_1", uops)
 
+    def test_call_type_1_known_type(self):
+        def testfunc(n):
+            x = 0
+            for _ in range(n):
+                x += type(42) 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)
+        # 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
+        # remove_unneeded_uops.
+        self.assertNotIn("_CALL_TYPE_1", 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)
+
     def test_call_type_1_result_is_const(self):
         def testfunc(n):
             x = 0
@@ -1806,7 +1826,6 @@ class TestUopsOptimization(unittest.TestCase):
         self.assertEqual(res, TIER2_THRESHOLD)
         self.assertIsNotNone(ex)
         uops = get_opnames(ex)
-        self.assertIn("_CALL_TYPE_1", uops)
         self.assertNotIn("_GUARD_IS_NOT_NONE_POP", uops)
 
     def test_call_str_1(self):
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-05-21-58-30.gh-issue-131798.nt5Ab7.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-05-21-58-30.gh-issue-131798.nt5Ab7.rst
new file mode 100644 (file)
index 0000000..e4b5f61
--- /dev/null
@@ -0,0 +1,2 @@
+Optimize away ``_CALL_TYPE_1`` in the JIT when the return type is known.
+Patch by Tomas Roun
index b4220e2c627ecbd0bba1ee1060b3910567d92dc4..12efaacd8f0dfcc6e2fe4b845fdefc1d472c774c 100644 (file)
@@ -937,8 +937,11 @@ dummy_func(void) {
     }
 
     op(_CALL_TYPE_1, (unused, unused, arg -- res)) {
-        if (sym_has_type(arg)) {
-            res = sym_new_const(ctx, (PyObject *)sym_get_type(arg));
+        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,
+                       (uintptr_t)type);
         }
         else {
             res = sym_new_not_null(ctx);
index 960c683800455ea2eddf642107012e64f6f16318..1a2d49973ee91625ee7d9a43f0ba44d6c50dc000 100644 (file)
             JitOptSymbol *arg;
             JitOptSymbol *res;
             arg = stack_pointer[-1];
-            if (sym_has_type(arg)) {
-                res = sym_new_const(ctx, (PyObject *)sym_get_type(arg));
+            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,
+                       (uintptr_t)type);
             }
             else {
                 res = sym_new_not_null(ctx);