aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--Include/internal/pycore_uop_metadata.h2
-rw-r--r--Lib/test/test_generated_cases.py23
-rw-r--r--Python/bytecodes.c27
-rw-r--r--Python/executor_cases.c.h39
-rw-r--r--Python/generated_cases.c.h68
-rw-r--r--Python/optimizer_cases.c.h6
-rw-r--r--Tools/cases_generator/generators_common.py3
-rw-r--r--Tools/cases_generator/stack.py36
-rw-r--r--Tools/cases_generator/tier1_generator.py2
9 files changed, 90 insertions, 116 deletions
diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h
index 8fa50ff2c29..ab26543a26f 100644
--- a/Include/internal/pycore_uop_metadata.h
+++ b/Include/internal/pycore_uop_metadata.h
@@ -1081,7 +1081,7 @@ int _PyUop_num_popped(int opcode, int oparg)
case _CALL_KW_NON_PY:
return 3 + oparg;
case _MAKE_CALLARGS_A_TUPLE:
- return 2;
+ return 0;
case _MAKE_FUNCTION:
return 1;
case _SET_FUNCTION_ATTRIBUTE:
diff --git a/Lib/test/test_generated_cases.py b/Lib/test/test_generated_cases.py
index 302e69de285..5b120f28131 100644
--- a/Lib/test/test_generated_cases.py
+++ b/Lib/test/test_generated_cases.py
@@ -1862,13 +1862,28 @@ class TestGeneratedCases(unittest.TestCase):
def test_reassigning_live_inputs(self):
input = """
- inst(OP, (in -- )) {
+ inst(OP, (in -- in)) {
in = 0;
- DEAD(in);
}
"""
- with self.assertRaises(SyntaxError):
- self.run_cases_test(input, "")
+
+ 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];
+ in = 0;
+ stack_pointer[-1] = in;
+ DISPATCH();
+ }
+ """
+ self.run_cases_test(input, output)
def test_reassigning_dead_inputs(self):
input = """
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index e9dced654d1..95786c91371 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -4725,15 +4725,9 @@ dummy_func(
_CALL_KW_NON_PY +
_CHECK_PERIODIC;
- op(_MAKE_CALLARGS_A_TUPLE, (func, unused, callargs, kwargs_in -- func, unused, tuple, kwargs_out)) {
+ op(_MAKE_CALLARGS_A_TUPLE, (func, unused, callargs, kwargs -- func, unused, callargs, kwargs)) {
PyObject *callargs_o = PyStackRef_AsPyObjectBorrow(callargs);
- if (PyTuple_CheckExact(callargs_o)) {
- tuple = callargs;
- kwargs_out = kwargs_in;
- DEAD(kwargs_in);
- DEAD(callargs);
- }
- else {
+ if (!PyTuple_CheckExact(callargs_o)) {
int err = _Py_Check_ArgsIterable(tstate, PyStackRef_AsPyObjectBorrow(func), callargs_o);
if (err < 0) {
ERROR_NO_POP();
@@ -4742,10 +4736,9 @@ dummy_func(
if (tuple_o == NULL) {
ERROR_NO_POP();
}
- kwargs_out = kwargs_in;
- DEAD(kwargs_in);
- PyStackRef_CLOSE(callargs);
- tuple = PyStackRef_FromPyObjectSteal(tuple_o);
+ _PyStackRef temp = callargs;
+ callargs = PyStackRef_FromPyObjectSteal(tuple_o);
+ PyStackRef_CLOSE(temp);
}
}
@@ -4965,11 +4958,11 @@ dummy_func(
macro(BINARY_OP) = _SPECIALIZE_BINARY_OP + unused/4 + _BINARY_OP;
- pure inst(SWAP, (bottom[1], unused[oparg-2], top[1] --
- bottom[1], unused[oparg-2], top[1])) {
- _PyStackRef temp = bottom[0];
- bottom[0] = top[0];
- top[0] = temp;
+ pure inst(SWAP, (bottom, unused[oparg-2], top --
+ bottom, unused[oparg-2], top)) {
+ _PyStackRef temp = bottom;
+ bottom = top;
+ top = temp;
assert(oparg >= 2);
}
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h
index 938a80fe665..9bfb13e2d97 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -6350,20 +6350,12 @@
}
case _MAKE_CALLARGS_A_TUPLE: {
- _PyStackRef kwargs_in;
_PyStackRef callargs;
_PyStackRef func;
- _PyStackRef tuple;
- _PyStackRef kwargs_out;
- kwargs_in = stack_pointer[-1];
callargs = stack_pointer[-2];
func = stack_pointer[-4];
PyObject *callargs_o = PyStackRef_AsPyObjectBorrow(callargs);
- if (PyTuple_CheckExact(callargs_o)) {
- tuple = callargs;
- kwargs_out = kwargs_in;
- }
- else {
+ if (!PyTuple_CheckExact(callargs_o)) {
_PyFrame_SetStackPointer(frame, stack_pointer);
int err = _Py_Check_ArgsIterable(tstate, PyStackRef_AsPyObjectBorrow(func), callargs_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
@@ -6376,17 +6368,14 @@
if (tuple_o == NULL) {
JUMP_TO_ERROR();
}
- kwargs_out = kwargs_in;
- stack_pointer += -2;
- assert(WITHIN_STACK_BOUNDS());
+ _PyStackRef temp = callargs;
+ callargs = PyStackRef_FromPyObjectSteal(tuple_o);
+ stack_pointer[-2] = callargs;
_PyFrame_SetStackPointer(frame, stack_pointer);
- PyStackRef_CLOSE(callargs);
+ PyStackRef_CLOSE(temp);
stack_pointer = _PyFrame_GetStackPointer(frame);
- tuple = PyStackRef_FromPyObjectSteal(tuple_o);
- stack_pointer += 2;
}
- stack_pointer[-2] = tuple;
- stack_pointer[-1] = kwargs_out;
+ stack_pointer[-2] = callargs;
break;
}
@@ -6631,15 +6620,17 @@
}
case _SWAP: {
- _PyStackRef *top;
- _PyStackRef *bottom;
+ _PyStackRef top;
+ _PyStackRef bottom;
oparg = CURRENT_OPARG();
- top = &stack_pointer[-1];
- bottom = &stack_pointer[-2 - (oparg-2)];
- _PyStackRef temp = bottom[0];
- bottom[0] = top[0];
- top[0] = temp;
+ top = stack_pointer[-1];
+ bottom = stack_pointer[-2 - (oparg-2)];
+ _PyStackRef temp = bottom;
+ bottom = top;
+ top = temp;
assert(oparg >= 2);
+ stack_pointer[-2 - (oparg-2)] = bottom;
+ stack_pointer[-1] = top;
break;
}
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index 97bffce8d82..6fe647d6197 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -2330,9 +2330,6 @@
opcode = CALL_FUNCTION_EX;
_PyStackRef func;
_PyStackRef callargs;
- _PyStackRef kwargs_in;
- _PyStackRef tuple;
- _PyStackRef kwargs_out;
_PyStackRef func_st;
_PyStackRef null;
_PyStackRef callargs_st;
@@ -2340,15 +2337,10 @@
_PyStackRef result;
// _MAKE_CALLARGS_A_TUPLE
{
- kwargs_in = stack_pointer[-1];
callargs = stack_pointer[-2];
func = stack_pointer[-4];
PyObject *callargs_o = PyStackRef_AsPyObjectBorrow(callargs);
- if (PyTuple_CheckExact(callargs_o)) {
- tuple = callargs;
- kwargs_out = kwargs_in;
- }
- else {
+ if (!PyTuple_CheckExact(callargs_o)) {
_PyFrame_SetStackPointer(frame, stack_pointer);
int err = _Py_Check_ArgsIterable(tstate, PyStackRef_AsPyObjectBorrow(func), callargs_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
@@ -2361,20 +2353,18 @@
if (tuple_o == NULL) {
JUMP_TO_LABEL(error);
}
- kwargs_out = kwargs_in;
- stack_pointer += -2;
- assert(WITHIN_STACK_BOUNDS());
+ _PyStackRef temp = callargs;
+ callargs = PyStackRef_FromPyObjectSteal(tuple_o);
+ stack_pointer[-2] = callargs;
_PyFrame_SetStackPointer(frame, stack_pointer);
- PyStackRef_CLOSE(callargs);
+ PyStackRef_CLOSE(temp);
stack_pointer = _PyFrame_GetStackPointer(frame);
- tuple = PyStackRef_FromPyObjectSteal(tuple_o);
- stack_pointer += 2;
}
}
// _DO_CALL_FUNCTION_EX
{
- kwargs_st = kwargs_out;
- callargs_st = tuple;
+ kwargs_st = stack_pointer[-1];
+ callargs_st = callargs;
null = stack_pointer[-3];
func_st = func;
(void)null;
@@ -2390,7 +2380,6 @@
PyObject *arg = PyTuple_GET_SIZE(callargs) > 0 ?
PyTuple_GET_ITEM(callargs, 0) : &_PyInstrumentation_MISSING;
stack_pointer[-2] = callargs_st;
- stack_pointer[-1] = kwargs_st;
_PyFrame_SetStackPointer(frame, stack_pointer);
int err = _Py_call_instrumentation_2args(
tstate, PY_MONITORING_EVENT_CALL,
@@ -2456,7 +2445,6 @@
PyObject *kwargs = PyStackRef_AsPyObjectBorrow(kwargs_st);
assert(kwargs == NULL || PyDict_CheckExact(kwargs));
stack_pointer[-2] = callargs_st;
- stack_pointer[-1] = kwargs_st;
_PyFrame_SetStackPointer(frame, stack_pointer);
result_o = PyObject_Call(func, callargs, kwargs);
stack_pointer = _PyFrame_GetStackPointer(frame);
@@ -6289,9 +6277,6 @@
opcode = INSTRUMENTED_CALL_FUNCTION_EX;
_PyStackRef func;
_PyStackRef callargs;
- _PyStackRef kwargs_in;
- _PyStackRef tuple;
- _PyStackRef kwargs_out;
_PyStackRef func_st;
_PyStackRef null;
_PyStackRef callargs_st;
@@ -6299,15 +6284,10 @@
_PyStackRef result;
// _MAKE_CALLARGS_A_TUPLE
{
- kwargs_in = stack_pointer[-1];
callargs = stack_pointer[-2];
func = stack_pointer[-4];
PyObject *callargs_o = PyStackRef_AsPyObjectBorrow(callargs);
- if (PyTuple_CheckExact(callargs_o)) {
- tuple = callargs;
- kwargs_out = kwargs_in;
- }
- else {
+ if (!PyTuple_CheckExact(callargs_o)) {
_PyFrame_SetStackPointer(frame, stack_pointer);
int err = _Py_Check_ArgsIterable(tstate, PyStackRef_AsPyObjectBorrow(func), callargs_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
@@ -6320,20 +6300,18 @@
if (tuple_o == NULL) {
JUMP_TO_LABEL(error);
}
- kwargs_out = kwargs_in;
- stack_pointer += -2;
- assert(WITHIN_STACK_BOUNDS());
+ _PyStackRef temp = callargs;
+ callargs = PyStackRef_FromPyObjectSteal(tuple_o);
+ stack_pointer[-2] = callargs;
_PyFrame_SetStackPointer(frame, stack_pointer);
- PyStackRef_CLOSE(callargs);
+ PyStackRef_CLOSE(temp);
stack_pointer = _PyFrame_GetStackPointer(frame);
- tuple = PyStackRef_FromPyObjectSteal(tuple_o);
- stack_pointer += 2;
}
}
// _DO_CALL_FUNCTION_EX
{
- kwargs_st = kwargs_out;
- callargs_st = tuple;
+ kwargs_st = stack_pointer[-1];
+ callargs_st = callargs;
null = stack_pointer[-3];
func_st = func;
(void)null;
@@ -6349,7 +6327,6 @@
PyObject *arg = PyTuple_GET_SIZE(callargs) > 0 ?
PyTuple_GET_ITEM(callargs, 0) : &_PyInstrumentation_MISSING;
stack_pointer[-2] = callargs_st;
- stack_pointer[-1] = kwargs_st;
_PyFrame_SetStackPointer(frame, stack_pointer);
int err = _Py_call_instrumentation_2args(
tstate, PY_MONITORING_EVENT_CALL,
@@ -6415,7 +6392,6 @@
PyObject *kwargs = PyStackRef_AsPyObjectBorrow(kwargs_st);
assert(kwargs == NULL || PyDict_CheckExact(kwargs));
stack_pointer[-2] = callargs_st;
- stack_pointer[-1] = kwargs_st;
_PyFrame_SetStackPointer(frame, stack_pointer);
result_o = PyObject_Call(func, callargs, kwargs);
stack_pointer = _PyFrame_GetStackPointer(frame);
@@ -11358,14 +11334,16 @@
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(SWAP);
- _PyStackRef *bottom;
- _PyStackRef *top;
- top = &stack_pointer[-1];
- bottom = &stack_pointer[-2 - (oparg-2)];
- _PyStackRef temp = bottom[0];
- bottom[0] = top[0];
- top[0] = temp;
+ _PyStackRef bottom;
+ _PyStackRef top;
+ top = stack_pointer[-1];
+ bottom = stack_pointer[-2 - (oparg-2)];
+ _PyStackRef temp = bottom;
+ bottom = top;
+ top = temp;
assert(oparg >= 2);
+ stack_pointer[-2 - (oparg-2)] = bottom;
+ stack_pointer[-1] = top;
DISPATCH();
}
diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h
index 0c617137a88..6a20cef9062 100644
--- a/Python/optimizer_cases.c.h
+++ b/Python/optimizer_cases.c.h
@@ -2047,12 +2047,6 @@
}
case _MAKE_CALLARGS_A_TUPLE: {
- JitOptSymbol *tuple;
- JitOptSymbol *kwargs_out;
- tuple = sym_new_not_null(ctx);
- kwargs_out = sym_new_not_null(ctx);
- stack_pointer[-2] = tuple;
- stack_pointer[-1] = kwargs_out;
break;
}
diff --git a/Tools/cases_generator/generators_common.py b/Tools/cases_generator/generators_common.py
index ca6104705fb..9ba0767cba3 100644
--- a/Tools/cases_generator/generators_common.py
+++ b/Tools/cases_generator/generators_common.py
@@ -500,9 +500,6 @@ class Emitter:
if tkn in local_stores:
for var in storage.inputs:
if var.name == tkn.text:
- if var.in_local or var.in_memory():
- msg = f"Cannot assign to already defined input variable '{tkn.text}'"
- raise analysis_error(msg, tkn)
var.in_local = True
var.memory_offset = None
break
diff --git a/Tools/cases_generator/stack.py b/Tools/cases_generator/stack.py
index 14d06948ba1..ff1e2ea74db 100644
--- a/Tools/cases_generator/stack.py
+++ b/Tools/cases_generator/stack.py
@@ -283,7 +283,7 @@ class Stack:
self.base_offset = self.logical_sp
def push(self, var: Local) -> None:
- assert(var not in self.variables)
+ assert(var not in self.variables), var
self.variables.append(var)
self.logical_sp = self.logical_sp.push(var.item)
@@ -325,6 +325,7 @@ class Stack:
var_offset = var_offset.push(var.item)
def flush(self, out: CWriter) -> None:
+ self._print(out)
self.save_variables(out)
self._save_physical_sp(out)
out.start_line()
@@ -432,12 +433,14 @@ class Storage:
stack: Stack
inputs: list[Local]
outputs: list[Local]
+ peeks: int
check_liveness: bool
spilled: int = 0
@staticmethod
def needs_defining(var: Local) -> bool:
return (
+ not var.item.peek and
not var.in_local and
not var.is_array() and
var.name != "unused"
@@ -454,7 +457,7 @@ class Storage:
)
def clear_inputs(self, reason:str) -> None:
- while self.inputs:
+ while len(self.inputs) > self.peeks:
tos = self.inputs.pop()
if self.is_live(tos) and self.check_liveness:
raise StackError(
@@ -464,14 +467,14 @@ class Storage:
def clear_dead_inputs(self) -> None:
live = ""
- while self.inputs:
+ while len(self.inputs) > self.peeks:
tos = self.inputs[-1]
if self.is_live(tos):
live = tos.name
break
self.inputs.pop()
self.stack.drop(tos.item, self.check_liveness)
- for var in self.inputs:
+ for var in self.inputs[self.peeks:]:
if not self.is_live(var):
raise StackError(
f"Input '{var.name}' is not live, but '{live}' is"
@@ -493,8 +496,8 @@ class Storage:
f"Expected '{undefined}' to be defined before '{out.name}'"
else:
undefined = out.name
- while self.outputs and not self.needs_defining(self.outputs[0]):
- out = self.outputs.pop(0)
+ while len(self.outputs) > self.peeks and not self.needs_defining(self.outputs[0]):
+ out = self.outputs.pop(self.peeks)
self.stack.push(out)
def locals_cached(self) -> bool:
@@ -541,12 +544,9 @@ class Storage:
local = stack.pop(input, out)
if input.peek:
peeks.append(local)
- else:
- inputs.append(local)
+ inputs.append(local)
inputs.reverse()
peeks.reverse()
- for peek in peeks:
- stack.push(peek)
offset = stack.logical_sp - stack.physical_sp
for ouput in uop.stack.outputs:
if ouput.is_array() and ouput.used and not ouput.peek:
@@ -555,8 +555,8 @@ class Storage:
offset = offset.push(ouput)
for var in inputs:
stack.push(var)
- outputs = [ Local.undefined(var) for var in uop.stack.outputs if not var.peek ]
- return Storage(stack, inputs, outputs, check_liveness)
+ outputs = peeks + [ Local.undefined(var) for var in uop.stack.outputs if not var.peek ]
+ return Storage(stack, inputs, outputs, len(peeks), check_liveness)
@staticmethod
def copy_list(arg: list[Local]) -> list[Local]:
@@ -568,7 +568,7 @@ class Storage:
inputs = [ variables[var.name] for var in self.inputs]
assert [v.name for v in inputs] == [v.name for v in self.inputs], (inputs, self.inputs)
return Storage(
- new_stack, inputs, self.copy_list(self.outputs),
+ new_stack, inputs, self.copy_list(self.outputs), self.peeks,
self.check_liveness, self.spilled
)
@@ -602,6 +602,8 @@ class Storage:
other.clear_dead_inputs()
if len(self.inputs) != len(other.inputs) and self.check_liveness:
diff = self.inputs[-1] if len(self.inputs) > len(other.inputs) else other.inputs[-1]
+ self._print(out)
+ other._print(out)
raise StackError(f"Unmergeable inputs. Differing state of '{diff.name}'")
for var, other_var in zip(self.inputs, other.inputs):
if var.in_local != other_var.in_local:
@@ -624,11 +626,11 @@ class Storage:
if self.spilled:
raise StackError(f"Unbalanced stack spills")
self.clear_inputs("at the end of the micro-op")
- if self.inputs and self.check_liveness:
+ if len(self.inputs) > self.peeks and self.check_liveness:
raise StackError(f"Input variable '{self.inputs[-1].name}' is still live")
self._push_defined_outputs()
if self.outputs:
- for out in self.outputs:
+ for out in self.outputs[self.peeks:]:
if self.needs_defining(out):
raise StackError(f"Output variable '{self.outputs[0].name}' is not defined")
self.stack.push(out)
@@ -641,6 +643,10 @@ class Storage:
outputs = ", ".join([var.compact_str() for var in self.outputs])
return f"{stack_comment[:-2]}{next_line}inputs: {inputs} outputs: {outputs}*/"
+ def _print(self, out: CWriter) -> None:
+ if PRINT_STACKS:
+ out.emit(self.as_comment() + "\n")
+
def close_inputs(self, out: CWriter) -> None:
tmp_defined = False
diff --git a/Tools/cases_generator/tier1_generator.py b/Tools/cases_generator/tier1_generator.py
index 5a49c239ed1..32dc346d5e8 100644
--- a/Tools/cases_generator/tier1_generator.py
+++ b/Tools/cases_generator/tier1_generator.py
@@ -204,7 +204,7 @@ def generate_tier1_labels(
# Emit tail-callable labels as function defintions
for name, label in analysis.labels.items():
emitter.emit(f"LABEL({name})\n")
- storage = Storage(Stack(), [], [], False)
+ storage = Storage(Stack(), [], [], 0, False)
if label.spilled:
storage.spilled = 1
emitter.emit_tokens(label, storage, None)