https://github.com/python/cpython/commit/a9d56e38a08ec198a2289d8fff65444b39dd4a32
commit: a9d56e38a08ec198a2289d8fff65444b39dd4a32
branch: main
author: Mark Shannon <[email protected]>
committer: markshannon <[email protected]>
date: 2024-08-01T09:27:26+01:00
summary:
GH-122155: Track local variables between pops and pushes in cases generator
(GH-122286)
files:
M Include/internal/pycore_opcode_metadata.h
M Lib/test/test_generated_cases.py
M Python/bytecodes.c
M Python/executor_cases.c.h
M Python/generated_cases.c.h
M Python/optimizer_cases.c.h
M Tools/cases_generator/analyzer.py
M Tools/cases_generator/generators_common.py
M Tools/cases_generator/optimizer_generator.py
M Tools/cases_generator/parsing.py
M Tools/cases_generator/stack.py
M Tools/cases_generator/tier1_generator.py
M Tools/cases_generator/tier2_generator.py
diff --git a/Include/internal/pycore_opcode_metadata.h
b/Include/internal/pycore_opcode_metadata.h
index eaba280f1bf1cd..464d3500890e53 100644
--- a/Include/internal/pycore_opcode_metadata.h
+++ b/Include/internal/pycore_opcode_metadata.h
@@ -903,7 +903,7 @@ int _PyOpcode_num_pushed(int opcode, int oparg) {
case UNARY_NOT:
return 1;
case UNPACK_EX:
- return 1 + (oparg >> 8) + (oparg & 0xFF);
+ return 1 + (oparg & 0xFF) + (oparg >> 8);
case UNPACK_SEQUENCE:
return oparg;
case UNPACK_SEQUENCE_LIST:
diff --git a/Lib/test/test_generated_cases.py b/Lib/test/test_generated_cases.py
index a4cbdecdc9db11..beafa544aaacb7 100644
--- a/Lib/test/test_generated_cases.py
+++ b/Lib/test/test_generated_cases.py
@@ -31,7 +31,7 @@ def skip_if_different_mount_drives():
with test_tools.imports_under_tool("cases_generator"):
from analyzer import StackItem
import parser
- from stack import Stack
+ from stack import Local, Stack
import tier1_generator
import optimizer_generator
@@ -60,9 +60,9 @@ def test_effect_sizes(self):
stack.pop(y)
stack.pop(x)
for out in outputs:
- stack.push(out)
- self.assertEqual(stack.base_offset.to_c(), "-1 - oparg*2 - oparg")
- self.assertEqual(stack.top_offset.to_c(), "1 - oparg*2 - oparg +
oparg*4")
+ stack.push(Local.local(out))
+ self.assertEqual(stack.base_offset.to_c(), "-1 - oparg - oparg*2")
+ self.assertEqual(stack.top_offset.to_c(), "1 - oparg - oparg*2 +
oparg*4")
class TestGeneratedCases(unittest.TestCase):
@@ -602,7 +602,11 @@ def test_array_error_if(self):
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP);
- if (oparg == 0) { stack_pointer += -1 - oparg; goto somewhere; }
+ if (oparg == 0) {
+ stack_pointer += -1 - oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto somewhere;
+ }
stack_pointer += -1 - oparg;
assert(WITHIN_STACK_BOUNDS());
DISPATCH();
@@ -908,7 +912,6 @@ def test_used_unused_used(self):
next_instr += 1;
INSTRUCTION_STATS(TEST);
_PyStackRef w;
- _PyStackRef x;
_PyStackRef y;
// FIRST
w = stack_pointer[-1];
@@ -916,11 +919,10 @@ def test_used_unused_used(self):
use(w);
}
// SECOND
- x = w;
{
}
// THIRD
- y = x;
+ y = w;
{
use(y);
}
@@ -1024,6 +1026,7 @@ def test_pop_on_error_peeks(self):
}
op(THIRD, (j, k --)) {
+ j,k; // Mark j and k as used
ERROR_IF(cond, error);
}
@@ -1054,6 +1057,7 @@ def test_pop_on_error_peeks(self):
k = b;
j = a;
{
+ j,k; // Mark j and k as used
if (cond) goto pop_2_error;
}
stack_pointer += -2;
@@ -1063,6 +1067,51 @@ def test_pop_on_error_peeks(self):
"""
self.run_cases_test(input, output)
+ def test_push_then_error(self):
+
+ input = """
+ op(FIRST, ( -- a)) {
+ a = 1;
+ }
+
+ op(SECOND, (a -- a, b)) {
+ b = 1;
+ ERROR_IF(cond, error);
+ }
+
+ macro(TEST) = FIRST + SECOND;
+ """
+
+ output = """
+ TARGET(TEST) {
+ frame->instr_ptr = next_instr;
+ next_instr += 1;
+ INSTRUCTION_STATS(TEST);
+ _PyStackRef a;
+ _PyStackRef b;
+ // FIRST
+ {
+ a = 1;
+ }
+ // SECOND
+ {
+ b = 1;
+ if (cond) {
+ stack_pointer[0] = a;
+ stack_pointer += 1;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
+ }
+ stack_pointer[0] = a;
+ stack_pointer[1] = b;
+ stack_pointer += 2;
+ assert(WITHIN_STACK_BOUNDS());
+ DISPATCH();
+ }
+ """
+ self.run_cases_test(input, output)
+
class TestGeneratedAbstractCases(unittest.TestCase):
def setUp(self) -> None:
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index 4afce2cc3bea9d..abfd8039b293a1 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -1357,8 +1357,8 @@ dummy_func(
(void)counter;
}
- op(_UNPACK_SEQUENCE, (seq -- unused[oparg])) {
- _PyStackRef *top = stack_pointer + oparg - 1;
+ op(_UNPACK_SEQUENCE, (seq -- output[oparg])) {
+ _PyStackRef *top = output + oparg;
int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg, -1,
top);
DECREF_INPUTS();
ERROR_IF(res == 0, error);
@@ -1401,9 +1401,8 @@ dummy_func(
DECREF_INPUTS();
}
- inst(UNPACK_EX, (seq -- unused[oparg & 0xFF], unused, unused[oparg >>
8])) {
- int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8);
- _PyStackRef *top = stack_pointer + totalargs - 1;
+ inst(UNPACK_EX, (seq -- left[oparg & 0xFF], unused, right[oparg >>
8])) {
+ _PyStackRef *top = right + (oparg >> 8);
int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg &
0xFF, oparg >> 8, top);
DECREF_INPUTS();
ERROR_IF(res == 0, error);
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h
index 62654035e80f50..f0acc3b6ea2ef4 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -1440,9 +1440,11 @@
case _UNPACK_SEQUENCE: {
_PyStackRef seq;
+ _PyStackRef *output;
oparg = CURRENT_OPARG();
seq = stack_pointer[-1];
- _PyStackRef *top = stack_pointer + oparg - 1;
+ output = &stack_pointer[-1];
+ _PyStackRef *top = output + oparg;
int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg, -1,
top);
PyStackRef_CLOSE(seq);
if (res == 0) JUMP_TO_ERROR();
@@ -1532,14 +1534,15 @@
case _UNPACK_EX: {
_PyStackRef seq;
+ _PyStackRef *right;
oparg = CURRENT_OPARG();
seq = stack_pointer[-1];
- int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8);
- _PyStackRef *top = stack_pointer + totalargs - 1;
+ right = &stack_pointer[(oparg & 0xFF)];
+ _PyStackRef *top = right + (oparg >> 8);
int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg &
0xFF, oparg >> 8, top);
PyStackRef_CLOSE(seq);
if (res == 0) JUMP_TO_ERROR();
- stack_pointer += (oparg >> 8) + (oparg & 0xFF);
+ stack_pointer += (oparg & 0xFF) + (oparg >> 8);
assert(WITHIN_STACK_BOUNDS());
break;
}
@@ -3595,6 +3598,7 @@
args = &stack_pointer[-oparg];
self_or_null = stack_pointer[-1 - oparg];
callable = stack_pointer[-2 - oparg];
+ args = &stack_pointer[-oparg];
if (PyStackRef_TYPE(callable) == &PyMethod_Type &&
PyStackRef_IsNull(self_or_null)) {
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
PyObject *self = ((PyMethodObject *)callable_o)->im_self;
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index 3c643f637ab095..ff8c4eab58f324 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -610,11 +610,19 @@
for (int _i = oparg; --_i >= 0;) {
PyStackRef_CLOSE(values[_i]);
}
- if (true) { stack_pointer += -oparg; goto error; }
+ if (true) {
+ stack_pointer += -oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
}
PyObject *list_o = _PyList_FromArraySteal(values_o, oparg);
STACKREFS_TO_PYOBJECTS_CLEANUP(values_o);
- if (list_o == NULL) { stack_pointer += -oparg; goto error; }
+ if (list_o == NULL) {
+ stack_pointer += -oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
list = PyStackRef_FromPyObjectSteal(list_o);
stack_pointer[-oparg] = list;
stack_pointer += 1 - oparg;
@@ -634,7 +642,11 @@
for (int _i = oparg*2; --_i >= 0;) {
PyStackRef_CLOSE(values[_i]);
}
- if (true) { stack_pointer += -oparg*2; goto error; }
+ if (true) {
+ stack_pointer += -oparg*2;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
}
PyObject *map_o = _PyDict_FromItems(
values_o, 2,
@@ -644,7 +656,11 @@
for (int _i = oparg*2; --_i >= 0;) {
PyStackRef_CLOSE(values[_i]);
}
- if (map_o == NULL) { stack_pointer += -oparg*2; goto error; }
+ if (map_o == NULL) {
+ stack_pointer += -oparg*2;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
map = PyStackRef_FromPyObjectSteal(map_o);
stack_pointer[-oparg*2] = map;
stack_pointer += 1 - oparg*2;
@@ -664,7 +680,11 @@
for (int _i = oparg; --_i >= 0;) {
PyStackRef_CLOSE(values[_i]);
}
- if (true) { stack_pointer += -oparg; goto error; }
+ if (true) {
+ stack_pointer += -oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
}
int err = 0;
for (int i = 0; i < oparg; i++) {
@@ -676,7 +696,11 @@
}
if (err != 0) {
Py_DECREF(set_o);
- if (true) { stack_pointer += -oparg; goto error; }
+ if (true) {
+ stack_pointer += -oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
}
set = PyStackRef_FromPyObjectSteal(set_o);
stack_pointer[-oparg] = set;
@@ -703,7 +727,11 @@
PyStackRef_CLOSE(start);
PyStackRef_CLOSE(stop);
PyStackRef_XCLOSE(step);
- if (slice_o == NULL) { stack_pointer += -2 - ((oparg == 3) ? 1 :
0); goto error; }
+ if (slice_o == NULL) {
+ stack_pointer += -2 - ((oparg == 3) ? 1 : 0);
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
slice = PyStackRef_FromPyObjectSteal(slice_o);
stack_pointer[-2 - ((oparg == 3) ? 1 : 0)] = slice;
stack_pointer += -1 - ((oparg == 3) ? 1 : 0);
@@ -723,14 +751,22 @@
for (int _i = oparg; --_i >= 0;) {
PyStackRef_CLOSE(pieces[_i]);
}
- if (true) { stack_pointer += -oparg; goto error; }
+ if (true) {
+ stack_pointer += -oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
}
PyObject *str_o = _PyUnicode_JoinArray(&_Py_STR(empty), pieces_o,
oparg);
STACKREFS_TO_PYOBJECTS_CLEANUP(pieces_o);
for (int _i = oparg; --_i >= 0;) {
PyStackRef_CLOSE(pieces[_i]);
}
- if (str_o == NULL) { stack_pointer += -oparg; goto error; }
+ if (str_o == NULL) {
+ stack_pointer += -oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
str = PyStackRef_FromPyObjectSteal(str_o);
stack_pointer[-oparg] = str;
stack_pointer += 1 - oparg;
@@ -746,7 +782,11 @@
_PyStackRef tup;
values = &stack_pointer[-oparg];
PyObject *tup_o = _PyTuple_FromStackRefSteal(values, oparg);
- if (tup_o == NULL) { stack_pointer += -oparg; goto error; }
+ if (tup_o == NULL) {
+ stack_pointer += -oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
tup = PyStackRef_FromPyObjectSteal(tup_o);
stack_pointer[-oparg] = tup;
stack_pointer += 1 - oparg;
@@ -780,7 +820,6 @@
self_or_null = stack_pointer[-1 - oparg];
callable = stack_pointer[-2 - oparg];
{
- args = &stack_pointer[-oparg];
uint16_t counter = read_u16(&this_instr[1].cache);
(void)counter;
#if ENABLE_SPECIALIZATION
@@ -795,7 +834,9 @@
}
/* Skip 2 cache entries */
// _MAYBE_EXPAND_METHOD
+ args = &stack_pointer[-oparg];
{
+ args = &stack_pointer[-oparg];
if (PyStackRef_TYPE(callable) == &PyMethod_Type &&
PyStackRef_IsNull(self_or_null)) {
PyObject *callable_o =
PyStackRef_AsPyObjectBorrow(callable);
PyObject *self = ((PyMethodObject *)callable_o)->im_self;
@@ -813,6 +854,7 @@
}
}
// _DO_CALL
+ args = &stack_pointer[-oparg];
self_or_null = maybe_self;
callable = func;
{
@@ -852,7 +894,11 @@
for (int _i = oparg; --_i >= 0;) {
PyStackRef_CLOSE(args[_i]);
}
- if (true) { stack_pointer += -2 - oparg; goto error; }
+ if (true) {
+ stack_pointer += -2 - oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
}
PyObject *res_o = PyObject_Vectorcall(
callable_o, args_o,
@@ -881,7 +927,11 @@
for (int i = 0; i < total_args; i++) {
PyStackRef_CLOSE(args[i]);
}
- if (res_o == NULL) { stack_pointer += -2 - oparg; goto error; }
+ if (res_o == NULL) {
+ stack_pointer += -2 - oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
res = PyStackRef_FromPyObjectSteal(res_o);
}
// _CHECK_PERIODIC
@@ -1190,7 +1240,11 @@
for (int _i = oparg; --_i >= 0;) {
PyStackRef_CLOSE(args[_i]);
}
- if (true) { stack_pointer += -2 - oparg; goto error; }
+ if (true) {
+ stack_pointer += -2 - oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
}
PyObject *res_o = tp->tp_vectorcall((PyObject *)tp, args_o,
total_args, NULL);
STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
@@ -1199,7 +1253,11 @@
PyStackRef_CLOSE(args[i]);
}
PyStackRef_CLOSE(callable);
- if (res_o == NULL) { stack_pointer += -2 - oparg; goto error; }
+ if (res_o == NULL) {
+ stack_pointer += -2 - oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
res = PyStackRef_FromPyObjectSteal(res_o);
}
// _CHECK_PERIODIC
@@ -1247,7 +1305,11 @@
for (int _i = oparg; --_i >= 0;) {
PyStackRef_CLOSE(args[_i]);
}
- if (true) { stack_pointer += -2 - oparg; goto error; }
+ if (true) {
+ stack_pointer += -2 - oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
}
PyObject *res_o = ((PyCFunctionFast)(void(*)(void))cfunc)(
PyCFunction_GET_SELF(callable_o),
@@ -1260,7 +1322,11 @@
PyStackRef_CLOSE(args[i]);
}
PyStackRef_CLOSE(callable);
- if (res_o == NULL) { stack_pointer += -2 - oparg; goto error; }
+ if (res_o == NULL) {
+ stack_pointer += -2 - oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
res = PyStackRef_FromPyObjectSteal(res_o);
}
// _CHECK_PERIODIC
@@ -1310,7 +1376,11 @@
for (int _i = oparg; --_i >= 0;) {
PyStackRef_CLOSE(args[_i]);
}
- if (true) { stack_pointer += -2 - oparg; goto error; }
+ if (true) {
+ stack_pointer += -2 - oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
}
PyObject *res_o = cfunc(PyCFunction_GET_SELF(callable_o),
args_o, total_args, NULL);
STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
@@ -1320,7 +1390,11 @@
PyStackRef_CLOSE(args[i]);
}
PyStackRef_CLOSE(callable);
- if (res_o == NULL) { stack_pointer += -2 - oparg; goto error; }
+ if (res_o == NULL) {
+ stack_pointer += -2 - oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
res = PyStackRef_FromPyObjectSteal(res_o);
}
// _CHECK_PERIODIC
@@ -1370,7 +1444,11 @@
assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
PyStackRef_CLOSE(arg);
PyStackRef_CLOSE(callable);
- if (res_o == NULL) { stack_pointer += -2 - oparg; goto error; }
+ if (res_o == NULL) {
+ stack_pointer += -2 - oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
res = PyStackRef_FromPyObjectSteal(res_o);
}
// _CHECK_PERIODIC
@@ -1467,7 +1545,11 @@
PyStackRef_CLOSE(callargs_st);
PyStackRef_XCLOSE(kwargs_st);
assert(PyStackRef_AsPyObjectBorrow(PEEK(2 + (oparg & 1))) == NULL);
- if (PyStackRef_IsNull(result)) { stack_pointer += -3 - (oparg &
1); goto error; }
+ if (PyStackRef_IsNull(result)) {
+ stack_pointer += -3 - (oparg & 1);
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
stack_pointer[-3 - (oparg & 1)] = result;
stack_pointer += -2 - (oparg & 1);
assert(WITHIN_STACK_BOUNDS());
@@ -1625,7 +1707,11 @@
PyStackRef_CLOSE(args[_i]);
}
PyStackRef_CLOSE(kwnames);
- if (true) { stack_pointer += -3 - oparg; goto error; }
+ if (true) {
+ stack_pointer += -3 - oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
}
PyObject *res_o = PyObject_Vectorcall(
callable_o, args_o,
@@ -1655,7 +1741,11 @@
for (int i = 0; i < total_args; i++) {
PyStackRef_CLOSE(args[i]);
}
- if (res_o == NULL) { stack_pointer += -3 - oparg; goto error; }
+ if (res_o == NULL) {
+ stack_pointer += -3 - oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
res = PyStackRef_FromPyObjectSteal(res_o);
stack_pointer[-3 - oparg] = res;
stack_pointer += -2 - oparg;
@@ -1785,7 +1875,11 @@
for (int _i = oparg; --_i >= 0;) {
PyStackRef_CLOSE(args[_i]);
}
- if (true) { stack_pointer += -2 - oparg; goto error; }
+ if (true) {
+ stack_pointer += -2 - oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
}
PyObject *res_o = cfunc(self, (args_o + 1), nargs);
STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
@@ -1795,7 +1889,11 @@
PyStackRef_CLOSE(args[i]);
}
PyStackRef_CLOSE(callable);
- if (res_o == NULL) { stack_pointer += -2 - oparg; goto error; }
+ if (res_o == NULL) {
+ stack_pointer += -2 - oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
res = PyStackRef_FromPyObjectSteal(res_o);
}
// _CHECK_PERIODIC
@@ -1848,7 +1946,11 @@
for (int _i = oparg; --_i >= 0;) {
PyStackRef_CLOSE(args[_i]);
}
- if (true) { stack_pointer += -2 - oparg; goto error; }
+ if (true) {
+ stack_pointer += -2 - oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
}
PyObject *res_o = cfunc(self, (args_o + 1), nargs, NULL);
STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
@@ -1858,7 +1960,11 @@
PyStackRef_CLOSE(args[i]);
}
PyStackRef_CLOSE(callable);
- if (res_o == NULL) { stack_pointer += -2 - oparg; goto error; }
+ if (res_o == NULL) {
+ stack_pointer += -2 - oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
res = PyStackRef_FromPyObjectSteal(res_o);
}
// _CHECK_PERIODIC
@@ -1912,7 +2018,11 @@
assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
PyStackRef_CLOSE(self_stackref);
PyStackRef_CLOSE(callable);
- if (res_o == NULL) { stack_pointer += -2 - oparg; goto error; }
+ if (res_o == NULL) {
+ stack_pointer += -2 - oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
res = PyStackRef_FromPyObjectSteal(res_o);
}
// _CHECK_PERIODIC
@@ -1969,7 +2079,11 @@
PyStackRef_CLOSE(self_stackref);
PyStackRef_CLOSE(arg_stackref);
PyStackRef_CLOSE(callable);
- if (res_o == NULL) { stack_pointer += -2 - oparg; goto error; }
+ if (res_o == NULL) {
+ stack_pointer += -2 - oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
res = PyStackRef_FromPyObjectSteal(res_o);
}
// _CHECK_PERIODIC
@@ -2022,7 +2136,11 @@
for (int _i = oparg; --_i >= 0;) {
PyStackRef_CLOSE(args[_i]);
}
- if (true) { stack_pointer += -2 - oparg; goto error; }
+ if (true) {
+ stack_pointer += -2 - oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
}
PyObject *res_o = PyObject_Vectorcall(
callable_o, args_o,
@@ -2034,7 +2152,11 @@
for (int i = 0; i < total_args; i++) {
PyStackRef_CLOSE(args[i]);
}
- if (res_o == NULL) { stack_pointer += -2 - oparg; goto error; }
+ if (res_o == NULL) {
+ stack_pointer += -2 - oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
res = PyStackRef_FromPyObjectSteal(res_o);
}
// _CHECK_PERIODIC
@@ -3526,6 +3648,7 @@
self_or_null = stack_pointer[-1 - oparg];
callable = stack_pointer[-2 - oparg];
{
+ args = &stack_pointer[-oparg];
if (PyStackRef_TYPE(callable) == &PyMethod_Type &&
PyStackRef_IsNull(self_or_null)) {
PyObject *callable_o =
PyStackRef_AsPyObjectBorrow(callable);
PyObject *self = ((PyMethodObject *)callable_o)->im_self;
@@ -3543,6 +3666,7 @@
}
}
// _MONITOR_CALL
+ args = &stack_pointer[-oparg];
{
int is_meth = !PyStackRef_IsNull(maybe_self);
PyObject *function = PyStackRef_AsPyObjectBorrow(func);
@@ -3563,6 +3687,7 @@
if (err) goto error;
}
// _DO_CALL
+ args = &stack_pointer[-oparg];
self_or_null = maybe_self;
callable = func;
{
@@ -3602,7 +3727,11 @@
for (int _i = oparg; --_i >= 0;) {
PyStackRef_CLOSE(args[_i]);
}
- if (true) { stack_pointer += -2 - oparg; goto error; }
+ if (true) {
+ stack_pointer += -2 - oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
}
PyObject *res_o = PyObject_Vectorcall(
callable_o, args_o,
@@ -3631,7 +3760,11 @@
for (int i = 0; i < total_args; i++) {
PyStackRef_CLOSE(args[i]);
}
- if (res_o == NULL) { stack_pointer += -2 - oparg; goto error; }
+ if (res_o == NULL) {
+ stack_pointer += -2 - oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
res = PyStackRef_FromPyObjectSteal(res_o);
}
// _CHECK_PERIODIC
@@ -5777,7 +5910,11 @@
"bad RAISE_VARARGS oparg");
break;
}
- if (true) { stack_pointer += -oparg; goto error; }
+ if (true) {
+ stack_pointer += -oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ goto error;
+ }
}
TARGET(RERAISE) {
@@ -6834,13 +6971,14 @@
next_instr += 1;
INSTRUCTION_STATS(UNPACK_EX);
_PyStackRef seq;
+ _PyStackRef *right;
seq = stack_pointer[-1];
- int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8);
- _PyStackRef *top = stack_pointer + totalargs - 1;
+ right = &stack_pointer[(oparg & 0xFF)];
+ _PyStackRef *top = right + (oparg >> 8);
int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg &
0xFF, oparg >> 8, top);
PyStackRef_CLOSE(seq);
if (res == 0) goto pop_1_error;
- stack_pointer += (oparg >> 8) + (oparg & 0xFF);
+ stack_pointer += (oparg & 0xFF) + (oparg >> 8);
assert(WITHIN_STACK_BOUNDS());
DISPATCH();
}
@@ -6853,6 +6991,7 @@
_Py_CODEUNIT *this_instr = next_instr - 2;
(void)this_instr;
_PyStackRef seq;
+ _PyStackRef *output;
// _SPECIALIZE_UNPACK_SEQUENCE
seq = stack_pointer[-1];
{
@@ -6872,7 +7011,8 @@
}
// _UNPACK_SEQUENCE
{
- _PyStackRef *top = stack_pointer + oparg - 1;
+ output = &stack_pointer[-1];
+ _PyStackRef *top = output + oparg;
int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg,
-1, top);
PyStackRef_CLOSE(seq);
if (res == 0) goto pop_1_error;
diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h
index 4fa40ff861ba70..b704c9e77319e4 100644
--- a/Python/optimizer_cases.c.h
+++ b/Python/optimizer_cases.c.h
@@ -753,7 +753,7 @@
for (int i = 0; i < totalargs; i++) {
values[i] = sym_new_unknown(ctx);
}
- stack_pointer += (oparg >> 8) + (oparg & 0xFF);
+ stack_pointer += (oparg & 0xFF) + (oparg >> 8);
assert(WITHIN_STACK_BOUNDS());
break;
}
@@ -1607,6 +1607,7 @@
args = &stack_pointer[-oparg];
self_or_null = stack_pointer[-1 - oparg];
callable = stack_pointer[-2 - oparg];
+ args = &stack_pointer[-oparg];
(void)callable;
(void)self_or_null;
(void)args;
diff --git a/Tools/cases_generator/analyzer.py
b/Tools/cases_generator/analyzer.py
index 675dc0b9acaf45..f6625a3f7322d5 100644
--- a/Tools/cases_generator/analyzer.py
+++ b/Tools/cases_generator/analyzer.py
@@ -216,6 +216,7 @@ def is_super(self) -> bool:
@dataclass
class Instruction:
+ where: lexer.Token
name: str
parts: list[Part]
_properties: Properties | None
@@ -690,9 +691,10 @@ def add_op(op: parser.InstDef, uops: dict[str, Uop]) ->
None:
def add_instruction(
- name: str, parts: list[Part], instructions: dict[str, Instruction]
+ where: lexer.Token, name: str, parts: list[Part],
+ instructions: dict[str, Instruction]
) -> None:
- instructions[name] = Instruction(name, parts, None)
+ instructions[name] = Instruction(where, name, parts, None)
def desugar_inst(
@@ -720,7 +722,7 @@ def desugar_inst(
parts.append(uop)
else:
parts[uop_index] = uop
- add_instruction(name, parts, instructions)
+ add_instruction(inst.first_token, name, parts, instructions)
def add_macro(
@@ -741,7 +743,7 @@ def add_macro(
case _:
assert False
assert parts
- add_instruction(macro.name, parts, instructions)
+ add_instruction(macro.first_token, macro.name, parts, instructions)
def add_family(
diff --git a/Tools/cases_generator/generators_common.py
b/Tools/cases_generator/generators_common.py
index 587dc0d03eded5..ab8c99f1e25f97 100644
--- a/Tools/cases_generator/generators_common.py
+++ b/Tools/cases_generator/generators_common.py
@@ -8,7 +8,7 @@
StackItem,
)
from cwriter import CWriter
-from typing import Callable, Mapping, TextIO, Iterator, Tuple
+from typing import Callable, Mapping, TextIO, Iterator
from lexer import Token
from stack import Stack
@@ -25,7 +25,7 @@ def root_relative_path(filename: str) -> str:
return filename
-def type_and_null(var: StackItem) -> Tuple[str, str]:
+def type_and_null(var: StackItem) -> tuple[str, str]:
if var.type:
return var.type, "NULL"
elif var.is_array():
@@ -95,16 +95,23 @@ def replace_error(
c_offset = stack.peek_offset()
try:
offset = -int(c_offset)
- close = ";\n"
except ValueError:
- offset = None
- out.emit(f"{{ stack_pointer += {c_offset}; ")
- close = "; }\n"
- out.emit("goto ")
- if offset:
- out.emit(f"pop_{offset}_")
- out.emit(label)
- out.emit(close)
+ offset = -1
+ if offset > 0:
+ out.emit(f"goto pop_{offset}_")
+ out.emit(label)
+ out.emit(";\n")
+ elif offset == 0:
+ out.emit("goto ")
+ out.emit(label)
+ out.emit(";\n")
+ else:
+ out.emit("{\n")
+ stack.flush_locally(out)
+ out.emit("goto ")
+ out.emit(label)
+ out.emit(";\n")
+ out.emit("}\n")
def replace_error_no_pop(
diff --git a/Tools/cases_generator/optimizer_generator.py
b/Tools/cases_generator/optimizer_generator.py
index 6a66693b93305d..f6c2fea40f0dbb 100644
--- a/Tools/cases_generator/optimizer_generator.py
+++ b/Tools/cases_generator/optimizer_generator.py
@@ -23,7 +23,7 @@
from cwriter import CWriter
from typing import TextIO, Iterator
from lexer import Token
-from stack import Stack, StackError
+from stack import Local, Stack, StackError
DEFAULT_OUTPUT = ROOT / "Python/optimizer_cases.c.h"
DEFAULT_ABSTRACT_INPUT = (ROOT /
"Python/optimizer_bytecodes.c").absolute().as_posix()
@@ -98,19 +98,18 @@ def write_uop(
debug: bool,
skip_inputs: bool,
) -> None:
+ locals: dict[str, Local] = {}
try:
prototype = override if override else uop
is_override = override is not None
out.start_line()
for var in reversed(prototype.stack.inputs):
- res = stack.pop(var, extract_bits=True)
+ code, local = stack.pop(var, extract_bits=True)
if not skip_inputs:
- out.emit(res)
- if not prototype.properties.stores_sp:
- for i, var in enumerate(prototype.stack.outputs):
- res = stack.push(var)
- if not var.peek or is_override:
- out.emit(res)
+ out.emit(code)
+ if local.defined:
+ locals[local.name] = local
+ out.emit(stack.define_output_arrays(prototype.stack.outputs))
if debug:
args = []
for var in prototype.stack.inputs:
@@ -135,10 +134,12 @@ def write_uop(
else:
emit_default(out, uop)
- if prototype.properties.stores_sp:
- for i, var in enumerate(prototype.stack.outputs):
- if not var.peek or is_override:
- out.emit(stack.push(var))
+ for var in prototype.stack.outputs:
+ if var.name in locals:
+ local = locals[var.name]
+ else:
+ local = Local.local(var)
+ out.emit(stack.push(local))
out.start_line()
stack.flush(out, cast_type="_Py_UopsSymbol *", extract_bits=True)
except StackError as ex:
diff --git a/Tools/cases_generator/parsing.py b/Tools/cases_generator/parsing.py
index 8957838f7a90a1..5acad57f395ea6 100644
--- a/Tools/cases_generator/parsing.py
+++ b/Tools/cases_generator/parsing.py
@@ -60,6 +60,11 @@ def tokens(self) -> list[lx.Token]:
end = context.end
return tokens[begin:end]
+ @property
+ def first_token(self) -> lx.Token:
+ context = self.context
+ assert context is not None
+ return context.owner.tokens[context.begin]
@dataclass
class Block(Node):
diff --git a/Tools/cases_generator/stack.py b/Tools/cases_generator/stack.py
index 61dcfd3e30a510..d2d598a120892d 100644
--- a/Tools/cases_generator/stack.py
+++ b/Tools/cases_generator/stack.py
@@ -38,6 +38,43 @@ def var_size(var: StackItem) -> str:
else:
return "1"
+@dataclass
+class Local:
+
+ item: StackItem
+ cached: bool
+ in_memory: bool
+ defined: bool
+
+ @staticmethod
+ def unused(defn: StackItem) -> "Local":
+ return Local(defn, False, defn.is_array(), False)
+
+ @staticmethod
+ def local(defn: StackItem) -> "Local":
+ array = defn.is_array()
+ return Local(defn, not array, array, True)
+
+ @staticmethod
+ def redefinition(var: StackItem, prev: "Local") -> "Local":
+ assert var.is_array() == prev.is_array()
+ return Local(var, prev.cached, prev.in_memory, True)
+
+ @property
+ def size(self) -> str:
+ return self.item.size
+
+ @property
+ def name(self) -> str:
+ return self.item.name
+
+ @property
+ def condition(self) -> str | None:
+ return self.item.condition
+
+ def is_array(self) -> bool:
+ return self.item.is_array()
+
@dataclass
class StackOffset:
"The stack offset of the virtual base of the stack from the physical stack
pointer"
@@ -66,7 +103,11 @@ def __neg__(self) -> "StackOffset":
def simplify(self) -> None:
"Remove matching values from both the popped and pushed list"
- if not self.popped or not self.pushed:
+ if not self.popped:
+ self.pushed.sort()
+ return
+ if not self.pushed:
+ self.popped.sort()
return
# Sort the list so the lexically largest element is last.
popped = sorted(self.popped)
@@ -87,6 +128,8 @@ def simplify(self) -> None:
popped.append(pop)
self.popped.extend(popped)
self.pushed.extend(pushed)
+ self.pushed.sort()
+ self.popped.sort()
def to_c(self) -> str:
self.simplify()
@@ -125,10 +168,10 @@ class Stack:
def __init__(self) -> None:
self.top_offset = StackOffset.empty()
self.base_offset = StackOffset.empty()
- self.variables: list[StackItem] = []
+ self.variables: list[Local] = []
self.defined: set[str] = set()
- def pop(self, var: StackItem, extract_bits: bool = False) -> str:
+ def pop(self, var: StackItem, extract_bits: bool = False) -> tuple[str,
Local]:
self.top_offset.pop(var)
indirect = "&" if var.is_array() else ""
if self.variables:
@@ -141,21 +184,32 @@ def pop(self, var: StackItem, extract_bits: bool = False)
-> str:
if var.name in UNUSED:
if popped.name not in UNUSED and popped.name in self.defined:
raise StackError(f"Value is declared unused, but is
already cached by prior operation")
- return ""
- if popped.name in UNUSED or popped.name not in self.defined:
- self.defined.add(var.name)
+ return "", popped
+ if not var.used:
+ return "", popped
+ self.defined.add(var.name)
+ # Always define array variables as it is free, and their offset
might have changed
+ if var.is_array():
+ return (
+ f"{var.name} =
&stack_pointer[{self.top_offset.to_c()}];\n",
+ Local.redefinition(var, popped)
+ )
+ if not popped.defined:
return (
- f"{var.name} =
{indirect}stack_pointer[{self.top_offset.to_c()}];\n"
+ f"{var.name} = stack_pointer[{self.top_offset.to_c()}];\n",
+ Local.redefinition(var, popped)
)
else:
- self.defined.add(var.name)
if popped.name == var.name:
- return ""
+ return "", popped
else:
- return f"{var.name} = {popped.name};\n"
+ return (
+ f"{var.name} = {popped.name};\n",
+ Local.redefinition(var, popped)
+ )
self.base_offset.pop(var)
if var.name in UNUSED or not var.used:
- return ""
+ return "", Local.unused(var)
self.defined.add(var.name)
cast = f"({var.type})" if (not indirect and var.type) else ""
bits = ".bits" if cast and not extract_bits else ""
@@ -164,61 +218,80 @@ def pop(self, var: StackItem, extract_bits: bool = False)
-> str:
)
if var.condition:
if var.condition == "1":
- return f"{assign}\n"
+ assign = f"{assign}\n"
elif var.condition == "0":
- return ""
+ return "", Local.unused(var)
else:
- return f"if ({var.condition}) {{ {assign} }}\n"
- return f"{assign}\n"
+ assign = f"if ({var.condition}) {{ {assign} }}\n"
+ else:
+ assign = f"{assign}\n"
+ in_memory = var.is_array() or var.peek
+ return assign, Local(var, not var.is_array(), in_memory, True)
- def push(self, var: StackItem) -> str:
+ def push(self, var: Local) -> str:
self.variables.append(var)
- if var.is_array() and var.name not in self.defined and var.name not in
UNUSED:
+ if var.is_array() and not var.defined and var.item.used:
+ assert var.in_memory
+ assert not var.cached
c_offset = self.top_offset.to_c()
- self.top_offset.push(var)
+ self.top_offset.push(var.item)
self.defined.add(var.name)
+ var.defined = True
return f"{var.name} = &stack_pointer[{c_offset}];\n"
else:
- self.top_offset.push(var)
- if var.used:
+ self.top_offset.push(var.item)
+ if var.item.used:
self.defined.add(var.name)
return ""
- def flush(self, out: CWriter, cast_type: str = "uintptr_t", extract_bits:
bool = False) -> None:
+ def define_output_arrays(self, outputs: list[StackItem]) -> str:
+ res = []
+ top_offset = self.top_offset.copy()
+ for var in outputs:
+ if var.is_array() and var.used and not var.peek:
+ c_offset = top_offset.to_c()
+ top_offset.push(var)
+ res.append(f"{var.name} = &stack_pointer[{c_offset}];\n")
+ else:
+ top_offset.push(var)
+ return "\n".join(res)
+
+ @staticmethod
+ def _do_flush(out: CWriter, variables: list[Local], base_offset:
StackOffset, top_offset: StackOffset,
+ cast_type: str = "uintptr_t", extract_bits: bool = False) ->
None:
out.start_line()
- for var in self.variables:
- if not var.peek:
- cast = f"({cast_type})" if var.type else ""
+ for var in variables:
+ if var.cached and not var.in_memory and not var.item.peek and not
var.name in UNUSED:
+ cast = f"({cast_type})" if var.item.type else ""
bits = ".bits" if cast and not extract_bits else ""
- if var.name not in UNUSED and not var.is_array():
- if var.condition:
- if var.condition == "0":
- continue
- elif var.condition != "1":
- out.emit(f"if ({var.condition}) ")
- out.emit(
- f"stack_pointer[{self.base_offset.to_c()}]{bits} =
{cast}{var.name};\n"
- )
- self.base_offset.push(var)
- if self.base_offset.to_c() != self.top_offset.to_c():
- print("base", self.base_offset.to_c(), "top",
self.top_offset.to_c())
+ if var.condition == "0":
+ continue
+ if var.condition and var.condition != "1":
+ out.emit(f"if ({var.condition}) ")
+ out.emit(
+ f"stack_pointer[{base_offset.to_c()}]{bits} =
{cast}{var.name};\n"
+ )
+ base_offset.push(var.item)
+ if base_offset.to_c() != top_offset.to_c():
+ print("base", base_offset, "top", top_offset)
assert False
- number = self.base_offset.to_c()
+ number = base_offset.to_c()
if number != "0":
out.emit(f"stack_pointer += {number};\n")
out.emit("assert(WITHIN_STACK_BOUNDS());\n")
+ out.start_line()
+
+ def flush_locally(self, out: CWriter, cast_type: str = "uintptr_t",
extract_bits: bool = False) -> None:
+ self._do_flush(out, self.variables[:], self.base_offset.copy(),
self.top_offset.copy(), cast_type, extract_bits)
+
+ def flush(self, out: CWriter, cast_type: str = "uintptr_t", extract_bits:
bool = False) -> None:
+ self._do_flush(out, self.variables, self.base_offset, self.top_offset,
cast_type, extract_bits)
self.variables = []
self.base_offset.clear()
self.top_offset.clear()
- out.start_line()
def peek_offset(self) -> str:
- peek = self.base_offset.copy()
- for var in self.variables:
- if not var.peek:
- break
- peek.push(var)
- return peek.to_c()
+ return self.top_offset.to_c()
def as_comment(self) -> str:
return f"/* Variables: {[v.name for v in self.variables]}. Base
offset: {self.base_offset.to_c()}. Top offset: {self.top_offset.to_c()} */"
@@ -236,8 +309,15 @@ def stacks(inst : Instruction | PseudoInstruction) ->
Iterator[StackEffect]:
yield inst.stack
for s in stacks(inst):
+ locals: dict[str, Local] = {}
for var in reversed(s.inputs):
- stack.pop(var)
+ _, local = stack.pop(var)
+ if var.name != "unused":
+ locals[local.name] = local
for var in s.outputs:
- stack.push(var)
+ if var.name in locals:
+ local = locals[var.name]
+ else:
+ local = Local.unused(var)
+ stack.push(local)
return stack
diff --git a/Tools/cases_generator/tier1_generator.py
b/Tools/cases_generator/tier1_generator.py
index 118f4b3a6eaa1c..1cdafbd35caea3 100644
--- a/Tools/cases_generator/tier1_generator.py
+++ b/Tools/cases_generator/tier1_generator.py
@@ -25,7 +25,7 @@
)
from cwriter import CWriter
from typing import TextIO
-from stack import Stack, StackError
+from stack import Local, Stack, StackError, get_stack_effect
DEFAULT_OUTPUT = ROOT / "Python/generated_cases.c.h"
@@ -43,18 +43,12 @@ def declare_variable(var: StackItem, out: CWriter) -> None:
def declare_variables(inst: Instruction, out: CWriter) -> None:
- stack = Stack()
- for part in inst.parts:
- if not isinstance(part, Uop):
- continue
- try:
- for var in reversed(part.stack.inputs):
- stack.pop(var)
- for var in part.stack.outputs:
- stack.push(var)
- except StackError as ex:
- raise analysis_error(ex.args[0], part.body[0]) from None
+ try:
+ stack = get_stack_effect(inst)
+ except StackError as ex:
+ raise analysis_error(ex.args[0], inst.where)
required = set(stack.defined)
+ required.discard("unused")
for part in inst.parts:
if not isinstance(part, Uop):
continue
@@ -80,16 +74,26 @@ def write_uop(
stack.flush(out)
return offset
try:
+ locals: dict[str, Local] = {}
out.start_line()
if braces:
out.emit(f"// {uop.name}\n")
+ peeks: list[Local] = []
for var in reversed(uop.stack.inputs):
- out.emit(stack.pop(var))
+ code, local = stack.pop(var)
+ out.emit(code)
+ if var.peek:
+ peeks.append(local)
+ if local.defined:
+ locals[local.name] = local
+ # Push back the peeks, so that they remain on the logical
+ # stack, but their values are cached.
+ while peeks:
+ stack.push(peeks.pop())
if braces:
out.emit("{\n")
- if not uop.properties.stores_sp:
- for i, var in enumerate(uop.stack.outputs):
- out.emit(stack.push(var))
+ out.emit(stack.define_output_arrays(uop.stack.outputs))
+
for cache in uop.caches:
if cache.name != "unused":
if cache.size == 4:
@@ -105,16 +109,22 @@ def write_uop(
out.emit(f"(void){cache.name};\n")
offset += cache.size
emit_tokens(out, uop, stack, inst)
- if uop.properties.stores_sp:
- for i, var in enumerate(uop.stack.outputs):
- out.emit(stack.push(var))
+ for i, var in enumerate(uop.stack.outputs):
+ if not var.peek:
+ if var.name in locals:
+ local = locals[var.name]
+ elif var.name == "unused":
+ local = Local.unused(var)
+ else:
+ local = Local.local(var)
+ out.emit(stack.push(local))
if braces:
out.start_line()
out.emit("}\n")
# out.emit(stack.as_comment() + "\n")
return offset
except StackError as ex:
- raise analysis_error(ex.args[0], uop.body[0]) from None
+ raise analysis_error(ex.args[0], uop.body[0])
def uses_this(inst: Instruction) -> bool:
diff --git a/Tools/cases_generator/tier2_generator.py
b/Tools/cases_generator/tier2_generator.py
index 88ad0fd797f0cc..18bab2c13e7eb7 100644
--- a/Tools/cases_generator/tier2_generator.py
+++ b/Tools/cases_generator/tier2_generator.py
@@ -25,7 +25,7 @@
from cwriter import CWriter
from typing import TextIO, Iterator
from lexer import Token
-from stack import Stack, StackError
+from stack import Local, Stack, StackError, get_stack_effect
DEFAULT_OUTPUT = ROOT / "Python/executor_cases.c.h"
@@ -53,8 +53,9 @@ def declare_variables(uop: Uop, out: CWriter) -> None:
for var in reversed(uop.stack.inputs):
stack.pop(var)
for var in uop.stack.outputs:
- stack.push(var)
+ stack.push(Local.unused(var))
required = set(stack.defined)
+ required.discard("unused")
for var in reversed(uop.stack.inputs):
declare_variable(var, uop, required, out)
for var in uop.stack.outputs:
@@ -156,6 +157,7 @@ def tier2_replace_oparg(
def write_uop(uop: Uop, out: CWriter, stack: Stack) -> None:
+ locals: dict[str, Local] = {}
try:
out.start_line()
if uop.properties.oparg:
@@ -165,10 +167,11 @@ def write_uop(uop: Uop, out: CWriter, stack: Stack) ->
None:
out.emit(f"oparg = {uop.properties.const_oparg};\n")
out.emit(f"assert(oparg == CURRENT_OPARG());\n")
for var in reversed(uop.stack.inputs):
- out.emit(stack.pop(var))
- if not uop.properties.stores_sp:
- for i, var in enumerate(uop.stack.outputs):
- out.emit(stack.push(var))
+ code, local = stack.pop(var)
+ out.emit(code)
+ if local.defined:
+ locals[local.name] = local
+ out.emit(stack.define_output_arrays(uop.stack.outputs))
for cache in uop.caches:
if cache.name != "unused":
if cache.size == 4:
@@ -178,9 +181,12 @@ def write_uop(uop: Uop, out: CWriter, stack: Stack) ->
None:
cast = f"uint{cache.size*16}_t"
out.emit(f"{type}{cache.name} = ({cast})CURRENT_OPERAND();\n")
emit_tokens(out, uop, stack, None, TIER2_REPLACEMENT_FUNCTIONS)
- if uop.properties.stores_sp:
- for i, var in enumerate(uop.stack.outputs):
- out.emit(stack.push(var))
+ for i, var in enumerate(uop.stack.outputs):
+ if var.name in locals:
+ local = locals[var.name]
+ else:
+ local = Local.local(var)
+ out.emit(stack.push(local))
except StackError as ex:
raise analysis_error(ex.args[0], uop.body[0]) from None
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]