mirror of
https://github.com/python/cpython.git
synced 2025-12-23 09:19:18 +00:00
GH-131513: Cases generator: Allow dead inputs to be reassigned (GH-131515)
This commit is contained in:
parent
b70d45ab22
commit
d3f6063af1
4 changed files with 71 additions and 17 deletions
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue