]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
GH-131513: Cases generator: Allow dead inputs to be reassigned (GH-131515)
authorMark Shannon <mark@hotpy.org>
Fri, 21 Mar 2025 11:38:17 +0000 (11:38 +0000)
committerGitHub <noreply@github.com>
Fri, 21 Mar 2025 11:38:17 +0000 (11:38 +0000)
Lib/test/test_generated_cases.py
Tools/cases_generator/analyzer.py
Tools/cases_generator/generators_common.py
Tools/cases_generator/stack.py

index 3eb650bf3e694249a891629483e7a65de9da85e4..405c23ad96c4145df90189cb67e4d4038bf95058 100644 (file)
@@ -1838,6 +1838,50 @@ class TestGeneratedCases(unittest.TestCase):
         """
         self.run_cases_test(input, output)
 
+    def test_reassigning_live_inputs(self):
+        input = """
+        inst(OP, (in -- )) {
+            in = 0;
+            DEAD(in);
+        }
+        """
+        with self.assertRaises(SyntaxError):
+            self.run_cases_test(input, "")
+
+    def test_reassigning_dead_inputs(self):
+        input = """
+        inst(OP, (in -- )) {
+            temp = use(in);
+            DEAD(in);
+            in = temp;
+            PyStackRef_CLOSE(in);
+        }
+        """
+        output = """
+        TARGET(OP) {
+            #if Py_TAIL_CALL_INTERP
+            int opcode = OP;
+            (void)(opcode);
+            #endif
+            frame->instr_ptr = next_instr;
+            next_instr += 1;
+            INSTRUCTION_STATS(OP);
+            _PyStackRef in;
+            in = stack_pointer[-1];
+            _PyFrame_SetStackPointer(frame, stack_pointer);
+            temp = use(in);
+            stack_pointer = _PyFrame_GetStackPointer(frame);
+            in = temp;
+            stack_pointer += -1;
+            assert(WITHIN_STACK_BOUNDS());
+            _PyFrame_SetStackPointer(frame, stack_pointer);
+            PyStackRef_CLOSE(in);
+            stack_pointer = _PyFrame_GetStackPointer(frame);
+            DISPATCH();
+        }
+        """
+        self.run_cases_test(input, output)
+
 
 class TestGeneratedAbstractCases(unittest.TestCase):
     def setUp(self) -> None:
index ac2cfb7b50be405f50fd567e61a1e1be70c43961..491b5d127cf0f5ecadcd9f1e8a27a98954b3f87a 100644 (file)
@@ -177,7 +177,7 @@ class Uop:
     stack: StackEffect
     caches: list[CacheEntry]
     deferred_refs: dict[lexer.Token, str | None]
-    output_stores: list[lexer.Token]
+    local_stores: list[lexer.Token]
     body: list[lexer.Token]
     properties: Properties
     _size: int = -1
@@ -236,7 +236,7 @@ class Label:
         self.properties = properties
 
     size:int = 0
-    output_stores: list[lexer.Token] = []
+    local_stores: list[lexer.Token] = []
     instruction_size = None
 
     def __str__(self) -> str:
@@ -431,7 +431,7 @@ def find_assignment_target(node: parser.InstDef, idx: int) -> list[lexer.Token]:
     return []
 
 
-def find_stores_outputs(node: parser.InstDef) -> list[lexer.Token]:
+def find_variable_stores(node: parser.InstDef) -> list[lexer.Token]:
     res: list[lexer.Token] = []
     outnames = { out.name for out in node.outputs }
     innames = { out.name for out in node.inputs }
@@ -449,9 +449,7 @@ def find_stores_outputs(node: parser.InstDef) -> list[lexer.Token]:
         if len(lhs) != 1 or lhs[0].kind != "IDENTIFIER":
             continue
         name = lhs[0]
-        if name.text in innames:
-            raise analysis_error(f"Cannot assign to input variable '{name.text}'", name)
-        if name.text in outnames:
+        if name.text in outnames or name.text in innames:
             res.append(name)
     return res
 
@@ -877,7 +875,7 @@ def make_uop(
         stack=analyze_stack(op),
         caches=analyze_caches(inputs),
         deferred_refs=analyze_deferred_refs(op),
-        output_stores=find_stores_outputs(op),
+        local_stores=find_variable_stores(op),
         body=op.block.tokens,
         properties=compute_properties(op),
     )
@@ -899,7 +897,7 @@ def make_uop(
             stack=analyze_stack(op),
             caches=analyze_caches(inputs),
             deferred_refs=analyze_deferred_refs(op),
-            output_stores=find_stores_outputs(op),
+            local_stores=find_variable_stores(op),
             body=op.block.tokens,
             properties=properties,
         )
index fc0b468266078d1e151befe8d6991f86682e79c1..cc1ea5c7da5455200d62f29c95a07782d83b2b33 100644 (file)
@@ -262,7 +262,7 @@ class Emitter:
         next(tkn_iter)
         next(tkn_iter)
         for var in storage.inputs:
-            var.defined = False
+            var.kill()
         return True
 
     def kill(
@@ -280,7 +280,7 @@ class Emitter:
         next(tkn_iter)
         for var in storage.inputs:
             if var.name == name:
-                var.defined = False
+                var.kill()
                 break
         else:
             raise analysis_error(
@@ -301,7 +301,7 @@ class Emitter:
                     raise analysis_error(
                         f"Cannot close '{name.text}' when "
                         f"'{live}' is still live", name)
-                var.defined = False
+                var.kill()
                 break
             if var.defined:
                 live = var.name
@@ -526,7 +526,7 @@ class Emitter:
     ) -> tuple[bool, Token, Storage]:
         """ Returns (reachable?, closing '}', stack)."""
         braces = 1
-        out_stores = set(uop.output_stores)
+        local_stores = set(uop.local_stores)
         tkn = next(tkn_iter)
         reload: Token | None = None
         try:
@@ -574,11 +574,19 @@ class Emitter:
                         if not self._replacers[tkn.text](tkn, tkn_iter, uop, storage, inst):
                             reachable = False
                     else:
-                        if tkn in out_stores:
-                            for out in storage.outputs:
-                                if out.name == tkn.text:
-                                    out.defined = True
-                                    out.in_memory = False
+                        if tkn in local_stores:
+                            for var in storage.inputs:
+                                if var.name == tkn.text:
+                                    if var.defined or var.in_memory:
+                                        msg = f"Cannot assign to already defined input variable '{tkn.text}'"
+                                        raise analysis_error(msg, tkn)
+                                    var.defined = True
+                                    var.in_memory = False
+                                    break
+                            for var in storage.outputs:
+                                if var.name == tkn.text:
+                                    var.defined = True
+                                    var.in_memory = False
                                     break
                         if tkn.text.startswith("DISPATCH"):
                             self._print_storage(storage)
index 70fa8abe513953a69bb026c626e355ba9e763db0..67d0418a114977a736d131966dce41035364cfe8 100644 (file)
@@ -63,6 +63,10 @@ class Local:
     def from_memory(defn: StackItem) -> "Local":
         return Local(defn, True, True, True)
 
+    def kill(self) -> None:
+        self.defined = False
+        self.in_memory = False
+
     def copy(self) -> "Local":
         return Local(
             self.item,