]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Remove unnecessary LIST_TO_TUPLE conversions (GH-126558)
authorBrandt Bucher <brandtbucher@microsoft.com>
Wed, 8 Jan 2025 17:00:11 +0000 (09:00 -0800)
committerGitHub <noreply@github.com>
Wed, 8 Jan 2025 17:00:11 +0000 (09:00 -0800)
Lib/test/test_peepholer.py
Python/flowgraph.c

index c7da151dce3b37bf5036a270daca461b0efa113c..b5b2b350e77a3b3ca548e26fb18beb69b778aab1 100644 (file)
@@ -1193,5 +1193,56 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase):
                         ]
                         self.cfg_optimization_test(insts, expected_insts, consts=list(range(5)))
 
+    def test_list_to_tuple_get_iter(self):
+        # for _ in (*foo, *bar) -> for _ in [*foo, *bar]
+        INTRINSIC_LIST_TO_TUPLE = 6
+        insts = [
+            ("BUILD_LIST", 0, 1),
+            ("LOAD_FAST", 0, 2),
+            ("LIST_EXTEND", 1, 3),
+            ("LOAD_FAST", 1, 4),
+            ("LIST_EXTEND", 1, 5),
+            ("CALL_INTRINSIC_1", INTRINSIC_LIST_TO_TUPLE, 6),
+            ("GET_ITER", None, 7),
+            top := self.Label(),
+            ("FOR_ITER", end := self.Label(), 8),
+            ("STORE_FAST", 2, 9),
+            ("JUMP", top, 10),
+            end,
+            ("END_FOR", None, 11),
+            ("POP_TOP", None, 12),
+            ("LOAD_CONST", 0, 13),
+            ("RETURN_VALUE", None, 14),
+        ]
+        expected_insts = [
+            ("BUILD_LIST", 0, 1),
+            ("LOAD_FAST", 0, 2),
+            ("LIST_EXTEND", 1, 3),
+            ("LOAD_FAST", 1, 4),
+            ("LIST_EXTEND", 1, 5),
+            ("NOP", None, 6),  # ("CALL_INTRINSIC_1", INTRINSIC_LIST_TO_TUPLE, 6),
+            ("GET_ITER", None, 7),
+            top := self.Label(),
+            ("FOR_ITER", end := self.Label(), 8),
+            ("STORE_FAST", 2, 9),
+            ("JUMP", top, 10),
+            end,
+            ("END_FOR", None, 11),
+            ("POP_TOP", None, 12),
+            ("LOAD_CONST", 0, 13),
+            ("RETURN_VALUE", None, 14),
+        ]
+        self.cfg_optimization_test(insts, expected_insts, consts=[None])
+
+    def test_list_to_tuple_get_iter_is_safe(self):
+        a, b = [], []
+        for item in (*(items := [0, 1, 2, 3]),):
+            a.append(item)
+            b.append(items.pop())
+        self.assertEqual(a, [0, 1, 2, 3])
+        self.assertEqual(b, [3, 2, 1, 0])
+        self.assertEqual(items, [])
+
+
 if __name__ == "__main__":
     unittest.main()
index 017216aadd1f01d9287374e96a603c19c2197247..24561c1ee04db9715858fdb1742a874f61f9ec77 100644 (file)
@@ -4,6 +4,7 @@
 #include "Python.h"
 #include "pycore_flowgraph.h"
 #include "pycore_compile.h"
+#include "pycore_intrinsics.h"
 #include "pycore_pymem.h"         // _PyMem_IsPtrFreed()
 
 #include "pycore_opcode_utils.h"
@@ -1874,6 +1875,12 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts)
                     continue;
                 }
                 break;
+            case CALL_INTRINSIC_1:
+                // for _ in (*foo, *bar) -> for _ in [*foo, *bar]
+                if (oparg == INTRINSIC_LIST_TO_TUPLE && nextop == GET_ITER) {
+                    INSTR_SET_OP0(inst, NOP);
+                }
+                break;
         }
     }