mirror of
https://github.com/python/cpython.git
synced 2025-08-25 03:04:55 +00:00
GH-122155: Track local variables between pops and pushes in cases generator (GH-122286)
This commit is contained in:
parent
46f5a4f9e1
commit
a9d56e38a0
13 changed files with 463 additions and 159 deletions
2
Include/internal/pycore_opcode_metadata.h
generated
2
Include/internal/pycore_opcode_metadata.h
generated
|
@ -903,7 +903,7 @@ int _PyOpcode_num_pushed(int opcode, int oparg) {
|
||||||
case UNARY_NOT:
|
case UNARY_NOT:
|
||||||
return 1;
|
return 1;
|
||||||
case UNPACK_EX:
|
case UNPACK_EX:
|
||||||
return 1 + (oparg >> 8) + (oparg & 0xFF);
|
return 1 + (oparg & 0xFF) + (oparg >> 8);
|
||||||
case UNPACK_SEQUENCE:
|
case UNPACK_SEQUENCE:
|
||||||
return oparg;
|
return oparg;
|
||||||
case UNPACK_SEQUENCE_LIST:
|
case UNPACK_SEQUENCE_LIST:
|
||||||
|
|
|
@ -31,7 +31,7 @@ test_tools.skip_if_missing("cases_generator")
|
||||||
with test_tools.imports_under_tool("cases_generator"):
|
with test_tools.imports_under_tool("cases_generator"):
|
||||||
from analyzer import StackItem
|
from analyzer import StackItem
|
||||||
import parser
|
import parser
|
||||||
from stack import Stack
|
from stack import Local, Stack
|
||||||
import tier1_generator
|
import tier1_generator
|
||||||
import optimizer_generator
|
import optimizer_generator
|
||||||
|
|
||||||
|
@ -60,9 +60,9 @@ class TestEffects(unittest.TestCase):
|
||||||
stack.pop(y)
|
stack.pop(y)
|
||||||
stack.pop(x)
|
stack.pop(x)
|
||||||
for out in outputs:
|
for out in outputs:
|
||||||
stack.push(out)
|
stack.push(Local.local(out))
|
||||||
self.assertEqual(stack.base_offset.to_c(), "-1 - oparg*2 - oparg")
|
self.assertEqual(stack.base_offset.to_c(), "-1 - oparg - oparg*2")
|
||||||
self.assertEqual(stack.top_offset.to_c(), "1 - oparg*2 - oparg + oparg*4")
|
self.assertEqual(stack.top_offset.to_c(), "1 - oparg - oparg*2 + oparg*4")
|
||||||
|
|
||||||
|
|
||||||
class TestGeneratedCases(unittest.TestCase):
|
class TestGeneratedCases(unittest.TestCase):
|
||||||
|
@ -602,7 +602,11 @@ class TestGeneratedCases(unittest.TestCase):
|
||||||
frame->instr_ptr = next_instr;
|
frame->instr_ptr = next_instr;
|
||||||
next_instr += 1;
|
next_instr += 1;
|
||||||
INSTRUCTION_STATS(OP);
|
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;
|
stack_pointer += -1 - oparg;
|
||||||
assert(WITHIN_STACK_BOUNDS());
|
assert(WITHIN_STACK_BOUNDS());
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
|
@ -908,7 +912,6 @@ class TestGeneratedCases(unittest.TestCase):
|
||||||
next_instr += 1;
|
next_instr += 1;
|
||||||
INSTRUCTION_STATS(TEST);
|
INSTRUCTION_STATS(TEST);
|
||||||
_PyStackRef w;
|
_PyStackRef w;
|
||||||
_PyStackRef x;
|
|
||||||
_PyStackRef y;
|
_PyStackRef y;
|
||||||
// FIRST
|
// FIRST
|
||||||
w = stack_pointer[-1];
|
w = stack_pointer[-1];
|
||||||
|
@ -916,11 +919,10 @@ class TestGeneratedCases(unittest.TestCase):
|
||||||
use(w);
|
use(w);
|
||||||
}
|
}
|
||||||
// SECOND
|
// SECOND
|
||||||
x = w;
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
// THIRD
|
// THIRD
|
||||||
y = x;
|
y = w;
|
||||||
{
|
{
|
||||||
use(y);
|
use(y);
|
||||||
}
|
}
|
||||||
|
@ -1024,6 +1026,7 @@ class TestGeneratedCases(unittest.TestCase):
|
||||||
}
|
}
|
||||||
|
|
||||||
op(THIRD, (j, k --)) {
|
op(THIRD, (j, k --)) {
|
||||||
|
j,k; // Mark j and k as used
|
||||||
ERROR_IF(cond, error);
|
ERROR_IF(cond, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1054,6 +1057,7 @@ class TestGeneratedCases(unittest.TestCase):
|
||||||
k = b;
|
k = b;
|
||||||
j = a;
|
j = a;
|
||||||
{
|
{
|
||||||
|
j,k; // Mark j and k as used
|
||||||
if (cond) goto pop_2_error;
|
if (cond) goto pop_2_error;
|
||||||
}
|
}
|
||||||
stack_pointer += -2;
|
stack_pointer += -2;
|
||||||
|
@ -1063,6 +1067,51 @@ class TestGeneratedCases(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
self.run_cases_test(input, output)
|
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):
|
class TestGeneratedAbstractCases(unittest.TestCase):
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
|
|
|
@ -1357,8 +1357,8 @@ dummy_func(
|
||||||
(void)counter;
|
(void)counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
op(_UNPACK_SEQUENCE, (seq -- unused[oparg])) {
|
op(_UNPACK_SEQUENCE, (seq -- output[oparg])) {
|
||||||
_PyStackRef *top = stack_pointer + oparg - 1;
|
_PyStackRef *top = output + oparg;
|
||||||
int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg, -1, top);
|
int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg, -1, top);
|
||||||
DECREF_INPUTS();
|
DECREF_INPUTS();
|
||||||
ERROR_IF(res == 0, error);
|
ERROR_IF(res == 0, error);
|
||||||
|
@ -1401,9 +1401,8 @@ dummy_func(
|
||||||
DECREF_INPUTS();
|
DECREF_INPUTS();
|
||||||
}
|
}
|
||||||
|
|
||||||
inst(UNPACK_EX, (seq -- unused[oparg & 0xFF], unused, unused[oparg >> 8])) {
|
inst(UNPACK_EX, (seq -- left[oparg & 0xFF], unused, right[oparg >> 8])) {
|
||||||
int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8);
|
_PyStackRef *top = right + (oparg >> 8);
|
||||||
_PyStackRef *top = stack_pointer + totalargs - 1;
|
|
||||||
int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg & 0xFF, oparg >> 8, top);
|
int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg & 0xFF, oparg >> 8, top);
|
||||||
DECREF_INPUTS();
|
DECREF_INPUTS();
|
||||||
ERROR_IF(res == 0, error);
|
ERROR_IF(res == 0, error);
|
||||||
|
|
12
Python/executor_cases.c.h
generated
12
Python/executor_cases.c.h
generated
|
@ -1440,9 +1440,11 @@
|
||||||
|
|
||||||
case _UNPACK_SEQUENCE: {
|
case _UNPACK_SEQUENCE: {
|
||||||
_PyStackRef seq;
|
_PyStackRef seq;
|
||||||
|
_PyStackRef *output;
|
||||||
oparg = CURRENT_OPARG();
|
oparg = CURRENT_OPARG();
|
||||||
seq = stack_pointer[-1];
|
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);
|
int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg, -1, top);
|
||||||
PyStackRef_CLOSE(seq);
|
PyStackRef_CLOSE(seq);
|
||||||
if (res == 0) JUMP_TO_ERROR();
|
if (res == 0) JUMP_TO_ERROR();
|
||||||
|
@ -1532,14 +1534,15 @@
|
||||||
|
|
||||||
case _UNPACK_EX: {
|
case _UNPACK_EX: {
|
||||||
_PyStackRef seq;
|
_PyStackRef seq;
|
||||||
|
_PyStackRef *right;
|
||||||
oparg = CURRENT_OPARG();
|
oparg = CURRENT_OPARG();
|
||||||
seq = stack_pointer[-1];
|
seq = stack_pointer[-1];
|
||||||
int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8);
|
right = &stack_pointer[(oparg & 0xFF)];
|
||||||
_PyStackRef *top = stack_pointer + totalargs - 1;
|
_PyStackRef *top = right + (oparg >> 8);
|
||||||
int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg & 0xFF, oparg >> 8, top);
|
int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg & 0xFF, oparg >> 8, top);
|
||||||
PyStackRef_CLOSE(seq);
|
PyStackRef_CLOSE(seq);
|
||||||
if (res == 0) JUMP_TO_ERROR();
|
if (res == 0) JUMP_TO_ERROR();
|
||||||
stack_pointer += (oparg >> 8) + (oparg & 0xFF);
|
stack_pointer += (oparg & 0xFF) + (oparg >> 8);
|
||||||
assert(WITHIN_STACK_BOUNDS());
|
assert(WITHIN_STACK_BOUNDS());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -3595,6 +3598,7 @@
|
||||||
args = &stack_pointer[-oparg];
|
args = &stack_pointer[-oparg];
|
||||||
self_or_null = stack_pointer[-1 - oparg];
|
self_or_null = stack_pointer[-1 - oparg];
|
||||||
callable = stack_pointer[-2 - oparg];
|
callable = stack_pointer[-2 - oparg];
|
||||||
|
args = &stack_pointer[-oparg];
|
||||||
if (PyStackRef_TYPE(callable) == &PyMethod_Type && PyStackRef_IsNull(self_or_null)) {
|
if (PyStackRef_TYPE(callable) == &PyMethod_Type && PyStackRef_IsNull(self_or_null)) {
|
||||||
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
|
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
|
||||||
PyObject *self = ((PyMethodObject *)callable_o)->im_self;
|
PyObject *self = ((PyMethodObject *)callable_o)->im_self;
|
||||||
|
|
216
Python/generated_cases.c.h
generated
216
Python/generated_cases.c.h
generated
|
@ -610,11 +610,19 @@
|
||||||
for (int _i = oparg; --_i >= 0;) {
|
for (int _i = oparg; --_i >= 0;) {
|
||||||
PyStackRef_CLOSE(values[_i]);
|
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);
|
PyObject *list_o = _PyList_FromArraySteal(values_o, oparg);
|
||||||
STACKREFS_TO_PYOBJECTS_CLEANUP(values_o);
|
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);
|
list = PyStackRef_FromPyObjectSteal(list_o);
|
||||||
stack_pointer[-oparg] = list;
|
stack_pointer[-oparg] = list;
|
||||||
stack_pointer += 1 - oparg;
|
stack_pointer += 1 - oparg;
|
||||||
|
@ -634,7 +642,11 @@
|
||||||
for (int _i = oparg*2; --_i >= 0;) {
|
for (int _i = oparg*2; --_i >= 0;) {
|
||||||
PyStackRef_CLOSE(values[_i]);
|
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(
|
PyObject *map_o = _PyDict_FromItems(
|
||||||
values_o, 2,
|
values_o, 2,
|
||||||
|
@ -644,7 +656,11 @@
|
||||||
for (int _i = oparg*2; --_i >= 0;) {
|
for (int _i = oparg*2; --_i >= 0;) {
|
||||||
PyStackRef_CLOSE(values[_i]);
|
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);
|
map = PyStackRef_FromPyObjectSteal(map_o);
|
||||||
stack_pointer[-oparg*2] = map;
|
stack_pointer[-oparg*2] = map;
|
||||||
stack_pointer += 1 - oparg*2;
|
stack_pointer += 1 - oparg*2;
|
||||||
|
@ -664,7 +680,11 @@
|
||||||
for (int _i = oparg; --_i >= 0;) {
|
for (int _i = oparg; --_i >= 0;) {
|
||||||
PyStackRef_CLOSE(values[_i]);
|
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;
|
int err = 0;
|
||||||
for (int i = 0; i < oparg; i++) {
|
for (int i = 0; i < oparg; i++) {
|
||||||
|
@ -676,7 +696,11 @@
|
||||||
}
|
}
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
Py_DECREF(set_o);
|
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);
|
set = PyStackRef_FromPyObjectSteal(set_o);
|
||||||
stack_pointer[-oparg] = set;
|
stack_pointer[-oparg] = set;
|
||||||
|
@ -703,7 +727,11 @@
|
||||||
PyStackRef_CLOSE(start);
|
PyStackRef_CLOSE(start);
|
||||||
PyStackRef_CLOSE(stop);
|
PyStackRef_CLOSE(stop);
|
||||||
PyStackRef_XCLOSE(step);
|
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);
|
slice = PyStackRef_FromPyObjectSteal(slice_o);
|
||||||
stack_pointer[-2 - ((oparg == 3) ? 1 : 0)] = slice;
|
stack_pointer[-2 - ((oparg == 3) ? 1 : 0)] = slice;
|
||||||
stack_pointer += -1 - ((oparg == 3) ? 1 : 0);
|
stack_pointer += -1 - ((oparg == 3) ? 1 : 0);
|
||||||
|
@ -723,14 +751,22 @@
|
||||||
for (int _i = oparg; --_i >= 0;) {
|
for (int _i = oparg; --_i >= 0;) {
|
||||||
PyStackRef_CLOSE(pieces[_i]);
|
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);
|
PyObject *str_o = _PyUnicode_JoinArray(&_Py_STR(empty), pieces_o, oparg);
|
||||||
STACKREFS_TO_PYOBJECTS_CLEANUP(pieces_o);
|
STACKREFS_TO_PYOBJECTS_CLEANUP(pieces_o);
|
||||||
for (int _i = oparg; --_i >= 0;) {
|
for (int _i = oparg; --_i >= 0;) {
|
||||||
PyStackRef_CLOSE(pieces[_i]);
|
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);
|
str = PyStackRef_FromPyObjectSteal(str_o);
|
||||||
stack_pointer[-oparg] = str;
|
stack_pointer[-oparg] = str;
|
||||||
stack_pointer += 1 - oparg;
|
stack_pointer += 1 - oparg;
|
||||||
|
@ -746,7 +782,11 @@
|
||||||
_PyStackRef tup;
|
_PyStackRef tup;
|
||||||
values = &stack_pointer[-oparg];
|
values = &stack_pointer[-oparg];
|
||||||
PyObject *tup_o = _PyTuple_FromStackRefSteal(values, 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);
|
tup = PyStackRef_FromPyObjectSteal(tup_o);
|
||||||
stack_pointer[-oparg] = tup;
|
stack_pointer[-oparg] = tup;
|
||||||
stack_pointer += 1 - oparg;
|
stack_pointer += 1 - oparg;
|
||||||
|
@ -780,7 +820,6 @@
|
||||||
self_or_null = stack_pointer[-1 - oparg];
|
self_or_null = stack_pointer[-1 - oparg];
|
||||||
callable = stack_pointer[-2 - oparg];
|
callable = stack_pointer[-2 - oparg];
|
||||||
{
|
{
|
||||||
args = &stack_pointer[-oparg];
|
|
||||||
uint16_t counter = read_u16(&this_instr[1].cache);
|
uint16_t counter = read_u16(&this_instr[1].cache);
|
||||||
(void)counter;
|
(void)counter;
|
||||||
#if ENABLE_SPECIALIZATION
|
#if ENABLE_SPECIALIZATION
|
||||||
|
@ -795,7 +834,9 @@
|
||||||
}
|
}
|
||||||
/* Skip 2 cache entries */
|
/* Skip 2 cache entries */
|
||||||
// _MAYBE_EXPAND_METHOD
|
// _MAYBE_EXPAND_METHOD
|
||||||
|
args = &stack_pointer[-oparg];
|
||||||
{
|
{
|
||||||
|
args = &stack_pointer[-oparg];
|
||||||
if (PyStackRef_TYPE(callable) == &PyMethod_Type && PyStackRef_IsNull(self_or_null)) {
|
if (PyStackRef_TYPE(callable) == &PyMethod_Type && PyStackRef_IsNull(self_or_null)) {
|
||||||
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
|
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
|
||||||
PyObject *self = ((PyMethodObject *)callable_o)->im_self;
|
PyObject *self = ((PyMethodObject *)callable_o)->im_self;
|
||||||
|
@ -813,6 +854,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// _DO_CALL
|
// _DO_CALL
|
||||||
|
args = &stack_pointer[-oparg];
|
||||||
self_or_null = maybe_self;
|
self_or_null = maybe_self;
|
||||||
callable = func;
|
callable = func;
|
||||||
{
|
{
|
||||||
|
@ -852,7 +894,11 @@
|
||||||
for (int _i = oparg; --_i >= 0;) {
|
for (int _i = oparg; --_i >= 0;) {
|
||||||
PyStackRef_CLOSE(args[_i]);
|
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(
|
PyObject *res_o = PyObject_Vectorcall(
|
||||||
callable_o, args_o,
|
callable_o, args_o,
|
||||||
|
@ -881,7 +927,11 @@
|
||||||
for (int i = 0; i < total_args; i++) {
|
for (int i = 0; i < total_args; i++) {
|
||||||
PyStackRef_CLOSE(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);
|
res = PyStackRef_FromPyObjectSteal(res_o);
|
||||||
}
|
}
|
||||||
// _CHECK_PERIODIC
|
// _CHECK_PERIODIC
|
||||||
|
@ -1190,7 +1240,11 @@
|
||||||
for (int _i = oparg; --_i >= 0;) {
|
for (int _i = oparg; --_i >= 0;) {
|
||||||
PyStackRef_CLOSE(args[_i]);
|
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);
|
PyObject *res_o = tp->tp_vectorcall((PyObject *)tp, args_o, total_args, NULL);
|
||||||
STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
|
STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
|
||||||
|
@ -1199,7 +1253,11 @@
|
||||||
PyStackRef_CLOSE(args[i]);
|
PyStackRef_CLOSE(args[i]);
|
||||||
}
|
}
|
||||||
PyStackRef_CLOSE(callable);
|
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);
|
res = PyStackRef_FromPyObjectSteal(res_o);
|
||||||
}
|
}
|
||||||
// _CHECK_PERIODIC
|
// _CHECK_PERIODIC
|
||||||
|
@ -1247,7 +1305,11 @@
|
||||||
for (int _i = oparg; --_i >= 0;) {
|
for (int _i = oparg; --_i >= 0;) {
|
||||||
PyStackRef_CLOSE(args[_i]);
|
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)(
|
PyObject *res_o = ((PyCFunctionFast)(void(*)(void))cfunc)(
|
||||||
PyCFunction_GET_SELF(callable_o),
|
PyCFunction_GET_SELF(callable_o),
|
||||||
|
@ -1260,7 +1322,11 @@
|
||||||
PyStackRef_CLOSE(args[i]);
|
PyStackRef_CLOSE(args[i]);
|
||||||
}
|
}
|
||||||
PyStackRef_CLOSE(callable);
|
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);
|
res = PyStackRef_FromPyObjectSteal(res_o);
|
||||||
}
|
}
|
||||||
// _CHECK_PERIODIC
|
// _CHECK_PERIODIC
|
||||||
|
@ -1310,7 +1376,11 @@
|
||||||
for (int _i = oparg; --_i >= 0;) {
|
for (int _i = oparg; --_i >= 0;) {
|
||||||
PyStackRef_CLOSE(args[_i]);
|
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);
|
PyObject *res_o = cfunc(PyCFunction_GET_SELF(callable_o), args_o, total_args, NULL);
|
||||||
STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
|
STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
|
||||||
|
@ -1320,7 +1390,11 @@
|
||||||
PyStackRef_CLOSE(args[i]);
|
PyStackRef_CLOSE(args[i]);
|
||||||
}
|
}
|
||||||
PyStackRef_CLOSE(callable);
|
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);
|
res = PyStackRef_FromPyObjectSteal(res_o);
|
||||||
}
|
}
|
||||||
// _CHECK_PERIODIC
|
// _CHECK_PERIODIC
|
||||||
|
@ -1370,7 +1444,11 @@
|
||||||
assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
||||||
PyStackRef_CLOSE(arg);
|
PyStackRef_CLOSE(arg);
|
||||||
PyStackRef_CLOSE(callable);
|
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);
|
res = PyStackRef_FromPyObjectSteal(res_o);
|
||||||
}
|
}
|
||||||
// _CHECK_PERIODIC
|
// _CHECK_PERIODIC
|
||||||
|
@ -1467,7 +1545,11 @@
|
||||||
PyStackRef_CLOSE(callargs_st);
|
PyStackRef_CLOSE(callargs_st);
|
||||||
PyStackRef_XCLOSE(kwargs_st);
|
PyStackRef_XCLOSE(kwargs_st);
|
||||||
assert(PyStackRef_AsPyObjectBorrow(PEEK(2 + (oparg & 1))) == NULL);
|
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[-3 - (oparg & 1)] = result;
|
||||||
stack_pointer += -2 - (oparg & 1);
|
stack_pointer += -2 - (oparg & 1);
|
||||||
assert(WITHIN_STACK_BOUNDS());
|
assert(WITHIN_STACK_BOUNDS());
|
||||||
|
@ -1625,7 +1707,11 @@
|
||||||
PyStackRef_CLOSE(args[_i]);
|
PyStackRef_CLOSE(args[_i]);
|
||||||
}
|
}
|
||||||
PyStackRef_CLOSE(kwnames);
|
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(
|
PyObject *res_o = PyObject_Vectorcall(
|
||||||
callable_o, args_o,
|
callable_o, args_o,
|
||||||
|
@ -1655,7 +1741,11 @@
|
||||||
for (int i = 0; i < total_args; i++) {
|
for (int i = 0; i < total_args; i++) {
|
||||||
PyStackRef_CLOSE(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);
|
res = PyStackRef_FromPyObjectSteal(res_o);
|
||||||
stack_pointer[-3 - oparg] = res;
|
stack_pointer[-3 - oparg] = res;
|
||||||
stack_pointer += -2 - oparg;
|
stack_pointer += -2 - oparg;
|
||||||
|
@ -1785,7 +1875,11 @@
|
||||||
for (int _i = oparg; --_i >= 0;) {
|
for (int _i = oparg; --_i >= 0;) {
|
||||||
PyStackRef_CLOSE(args[_i]);
|
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);
|
PyObject *res_o = cfunc(self, (args_o + 1), nargs);
|
||||||
STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
|
STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
|
||||||
|
@ -1795,7 +1889,11 @@
|
||||||
PyStackRef_CLOSE(args[i]);
|
PyStackRef_CLOSE(args[i]);
|
||||||
}
|
}
|
||||||
PyStackRef_CLOSE(callable);
|
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);
|
res = PyStackRef_FromPyObjectSteal(res_o);
|
||||||
}
|
}
|
||||||
// _CHECK_PERIODIC
|
// _CHECK_PERIODIC
|
||||||
|
@ -1848,7 +1946,11 @@
|
||||||
for (int _i = oparg; --_i >= 0;) {
|
for (int _i = oparg; --_i >= 0;) {
|
||||||
PyStackRef_CLOSE(args[_i]);
|
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);
|
PyObject *res_o = cfunc(self, (args_o + 1), nargs, NULL);
|
||||||
STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
|
STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
|
||||||
|
@ -1858,7 +1960,11 @@
|
||||||
PyStackRef_CLOSE(args[i]);
|
PyStackRef_CLOSE(args[i]);
|
||||||
}
|
}
|
||||||
PyStackRef_CLOSE(callable);
|
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);
|
res = PyStackRef_FromPyObjectSteal(res_o);
|
||||||
}
|
}
|
||||||
// _CHECK_PERIODIC
|
// _CHECK_PERIODIC
|
||||||
|
@ -1912,7 +2018,11 @@
|
||||||
assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
||||||
PyStackRef_CLOSE(self_stackref);
|
PyStackRef_CLOSE(self_stackref);
|
||||||
PyStackRef_CLOSE(callable);
|
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);
|
res = PyStackRef_FromPyObjectSteal(res_o);
|
||||||
}
|
}
|
||||||
// _CHECK_PERIODIC
|
// _CHECK_PERIODIC
|
||||||
|
@ -1969,7 +2079,11 @@
|
||||||
PyStackRef_CLOSE(self_stackref);
|
PyStackRef_CLOSE(self_stackref);
|
||||||
PyStackRef_CLOSE(arg_stackref);
|
PyStackRef_CLOSE(arg_stackref);
|
||||||
PyStackRef_CLOSE(callable);
|
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);
|
res = PyStackRef_FromPyObjectSteal(res_o);
|
||||||
}
|
}
|
||||||
// _CHECK_PERIODIC
|
// _CHECK_PERIODIC
|
||||||
|
@ -2022,7 +2136,11 @@
|
||||||
for (int _i = oparg; --_i >= 0;) {
|
for (int _i = oparg; --_i >= 0;) {
|
||||||
PyStackRef_CLOSE(args[_i]);
|
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(
|
PyObject *res_o = PyObject_Vectorcall(
|
||||||
callable_o, args_o,
|
callable_o, args_o,
|
||||||
|
@ -2034,7 +2152,11 @@
|
||||||
for (int i = 0; i < total_args; i++) {
|
for (int i = 0; i < total_args; i++) {
|
||||||
PyStackRef_CLOSE(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);
|
res = PyStackRef_FromPyObjectSteal(res_o);
|
||||||
}
|
}
|
||||||
// _CHECK_PERIODIC
|
// _CHECK_PERIODIC
|
||||||
|
@ -3526,6 +3648,7 @@
|
||||||
self_or_null = stack_pointer[-1 - oparg];
|
self_or_null = stack_pointer[-1 - oparg];
|
||||||
callable = stack_pointer[-2 - oparg];
|
callable = stack_pointer[-2 - oparg];
|
||||||
{
|
{
|
||||||
|
args = &stack_pointer[-oparg];
|
||||||
if (PyStackRef_TYPE(callable) == &PyMethod_Type && PyStackRef_IsNull(self_or_null)) {
|
if (PyStackRef_TYPE(callable) == &PyMethod_Type && PyStackRef_IsNull(self_or_null)) {
|
||||||
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
|
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
|
||||||
PyObject *self = ((PyMethodObject *)callable_o)->im_self;
|
PyObject *self = ((PyMethodObject *)callable_o)->im_self;
|
||||||
|
@ -3543,6 +3666,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// _MONITOR_CALL
|
// _MONITOR_CALL
|
||||||
|
args = &stack_pointer[-oparg];
|
||||||
{
|
{
|
||||||
int is_meth = !PyStackRef_IsNull(maybe_self);
|
int is_meth = !PyStackRef_IsNull(maybe_self);
|
||||||
PyObject *function = PyStackRef_AsPyObjectBorrow(func);
|
PyObject *function = PyStackRef_AsPyObjectBorrow(func);
|
||||||
|
@ -3563,6 +3687,7 @@
|
||||||
if (err) goto error;
|
if (err) goto error;
|
||||||
}
|
}
|
||||||
// _DO_CALL
|
// _DO_CALL
|
||||||
|
args = &stack_pointer[-oparg];
|
||||||
self_or_null = maybe_self;
|
self_or_null = maybe_self;
|
||||||
callable = func;
|
callable = func;
|
||||||
{
|
{
|
||||||
|
@ -3602,7 +3727,11 @@
|
||||||
for (int _i = oparg; --_i >= 0;) {
|
for (int _i = oparg; --_i >= 0;) {
|
||||||
PyStackRef_CLOSE(args[_i]);
|
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(
|
PyObject *res_o = PyObject_Vectorcall(
|
||||||
callable_o, args_o,
|
callable_o, args_o,
|
||||||
|
@ -3631,7 +3760,11 @@
|
||||||
for (int i = 0; i < total_args; i++) {
|
for (int i = 0; i < total_args; i++) {
|
||||||
PyStackRef_CLOSE(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);
|
res = PyStackRef_FromPyObjectSteal(res_o);
|
||||||
}
|
}
|
||||||
// _CHECK_PERIODIC
|
// _CHECK_PERIODIC
|
||||||
|
@ -5777,7 +5910,11 @@
|
||||||
"bad RAISE_VARARGS oparg");
|
"bad RAISE_VARARGS oparg");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (true) { stack_pointer += -oparg; goto error; }
|
if (true) {
|
||||||
|
stack_pointer += -oparg;
|
||||||
|
assert(WITHIN_STACK_BOUNDS());
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TARGET(RERAISE) {
|
TARGET(RERAISE) {
|
||||||
|
@ -6834,13 +6971,14 @@
|
||||||
next_instr += 1;
|
next_instr += 1;
|
||||||
INSTRUCTION_STATS(UNPACK_EX);
|
INSTRUCTION_STATS(UNPACK_EX);
|
||||||
_PyStackRef seq;
|
_PyStackRef seq;
|
||||||
|
_PyStackRef *right;
|
||||||
seq = stack_pointer[-1];
|
seq = stack_pointer[-1];
|
||||||
int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8);
|
right = &stack_pointer[(oparg & 0xFF)];
|
||||||
_PyStackRef *top = stack_pointer + totalargs - 1;
|
_PyStackRef *top = right + (oparg >> 8);
|
||||||
int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg & 0xFF, oparg >> 8, top);
|
int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg & 0xFF, oparg >> 8, top);
|
||||||
PyStackRef_CLOSE(seq);
|
PyStackRef_CLOSE(seq);
|
||||||
if (res == 0) goto pop_1_error;
|
if (res == 0) goto pop_1_error;
|
||||||
stack_pointer += (oparg >> 8) + (oparg & 0xFF);
|
stack_pointer += (oparg & 0xFF) + (oparg >> 8);
|
||||||
assert(WITHIN_STACK_BOUNDS());
|
assert(WITHIN_STACK_BOUNDS());
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
@ -6853,6 +6991,7 @@
|
||||||
_Py_CODEUNIT *this_instr = next_instr - 2;
|
_Py_CODEUNIT *this_instr = next_instr - 2;
|
||||||
(void)this_instr;
|
(void)this_instr;
|
||||||
_PyStackRef seq;
|
_PyStackRef seq;
|
||||||
|
_PyStackRef *output;
|
||||||
// _SPECIALIZE_UNPACK_SEQUENCE
|
// _SPECIALIZE_UNPACK_SEQUENCE
|
||||||
seq = stack_pointer[-1];
|
seq = stack_pointer[-1];
|
||||||
{
|
{
|
||||||
|
@ -6872,7 +7011,8 @@
|
||||||
}
|
}
|
||||||
// _UNPACK_SEQUENCE
|
// _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);
|
int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg, -1, top);
|
||||||
PyStackRef_CLOSE(seq);
|
PyStackRef_CLOSE(seq);
|
||||||
if (res == 0) goto pop_1_error;
|
if (res == 0) goto pop_1_error;
|
||||||
|
|
3
Python/optimizer_cases.c.h
generated
3
Python/optimizer_cases.c.h
generated
|
@ -753,7 +753,7 @@
|
||||||
for (int i = 0; i < totalargs; i++) {
|
for (int i = 0; i < totalargs; i++) {
|
||||||
values[i] = sym_new_unknown(ctx);
|
values[i] = sym_new_unknown(ctx);
|
||||||
}
|
}
|
||||||
stack_pointer += (oparg >> 8) + (oparg & 0xFF);
|
stack_pointer += (oparg & 0xFF) + (oparg >> 8);
|
||||||
assert(WITHIN_STACK_BOUNDS());
|
assert(WITHIN_STACK_BOUNDS());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1607,6 +1607,7 @@
|
||||||
args = &stack_pointer[-oparg];
|
args = &stack_pointer[-oparg];
|
||||||
self_or_null = stack_pointer[-1 - oparg];
|
self_or_null = stack_pointer[-1 - oparg];
|
||||||
callable = stack_pointer[-2 - oparg];
|
callable = stack_pointer[-2 - oparg];
|
||||||
|
args = &stack_pointer[-oparg];
|
||||||
(void)callable;
|
(void)callable;
|
||||||
(void)self_or_null;
|
(void)self_or_null;
|
||||||
(void)args;
|
(void)args;
|
||||||
|
|
|
@ -216,6 +216,7 @@ Part = Uop | Skip | Flush
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Instruction:
|
class Instruction:
|
||||||
|
where: lexer.Token
|
||||||
name: str
|
name: str
|
||||||
parts: list[Part]
|
parts: list[Part]
|
||||||
_properties: Properties | None
|
_properties: Properties | None
|
||||||
|
@ -690,9 +691,10 @@ def add_op(op: parser.InstDef, uops: dict[str, Uop]) -> None:
|
||||||
|
|
||||||
|
|
||||||
def add_instruction(
|
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:
|
) -> None:
|
||||||
instructions[name] = Instruction(name, parts, None)
|
instructions[name] = Instruction(where, name, parts, None)
|
||||||
|
|
||||||
|
|
||||||
def desugar_inst(
|
def desugar_inst(
|
||||||
|
@ -720,7 +722,7 @@ def desugar_inst(
|
||||||
parts.append(uop)
|
parts.append(uop)
|
||||||
else:
|
else:
|
||||||
parts[uop_index] = uop
|
parts[uop_index] = uop
|
||||||
add_instruction(name, parts, instructions)
|
add_instruction(inst.first_token, name, parts, instructions)
|
||||||
|
|
||||||
|
|
||||||
def add_macro(
|
def add_macro(
|
||||||
|
@ -741,7 +743,7 @@ def add_macro(
|
||||||
case _:
|
case _:
|
||||||
assert False
|
assert False
|
||||||
assert parts
|
assert parts
|
||||||
add_instruction(macro.name, parts, instructions)
|
add_instruction(macro.first_token, macro.name, parts, instructions)
|
||||||
|
|
||||||
|
|
||||||
def add_family(
|
def add_family(
|
||||||
|
|
|
@ -8,7 +8,7 @@ from analyzer import (
|
||||||
StackItem,
|
StackItem,
|
||||||
)
|
)
|
||||||
from cwriter import CWriter
|
from cwriter import CWriter
|
||||||
from typing import Callable, Mapping, TextIO, Iterator, Tuple
|
from typing import Callable, Mapping, TextIO, Iterator
|
||||||
from lexer import Token
|
from lexer import Token
|
||||||
from stack import Stack
|
from stack import Stack
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ def root_relative_path(filename: str) -> str:
|
||||||
return filename
|
return filename
|
||||||
|
|
||||||
|
|
||||||
def type_and_null(var: StackItem) -> Tuple[str, str]:
|
def type_and_null(var: StackItem) -> tuple[str, str]:
|
||||||
if var.type:
|
if var.type:
|
||||||
return var.type, "NULL"
|
return var.type, "NULL"
|
||||||
elif var.is_array():
|
elif var.is_array():
|
||||||
|
@ -95,16 +95,23 @@ def replace_error(
|
||||||
c_offset = stack.peek_offset()
|
c_offset = stack.peek_offset()
|
||||||
try:
|
try:
|
||||||
offset = -int(c_offset)
|
offset = -int(c_offset)
|
||||||
close = ";\n"
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
offset = None
|
offset = -1
|
||||||
out.emit(f"{{ stack_pointer += {c_offset}; ")
|
if offset > 0:
|
||||||
close = "; }\n"
|
out.emit(f"goto pop_{offset}_")
|
||||||
out.emit("goto ")
|
out.emit(label)
|
||||||
if offset:
|
out.emit(";\n")
|
||||||
out.emit(f"pop_{offset}_")
|
elif offset == 0:
|
||||||
out.emit(label)
|
out.emit("goto ")
|
||||||
out.emit(close)
|
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(
|
def replace_error_no_pop(
|
||||||
|
|
|
@ -23,7 +23,7 @@ from generators_common import (
|
||||||
from cwriter import CWriter
|
from cwriter import CWriter
|
||||||
from typing import TextIO, Iterator
|
from typing import TextIO, Iterator
|
||||||
from lexer import Token
|
from lexer import Token
|
||||||
from stack import Stack, StackError
|
from stack import Local, Stack, StackError
|
||||||
|
|
||||||
DEFAULT_OUTPUT = ROOT / "Python/optimizer_cases.c.h"
|
DEFAULT_OUTPUT = ROOT / "Python/optimizer_cases.c.h"
|
||||||
DEFAULT_ABSTRACT_INPUT = (ROOT / "Python/optimizer_bytecodes.c").absolute().as_posix()
|
DEFAULT_ABSTRACT_INPUT = (ROOT / "Python/optimizer_bytecodes.c").absolute().as_posix()
|
||||||
|
@ -98,19 +98,18 @@ def write_uop(
|
||||||
debug: bool,
|
debug: bool,
|
||||||
skip_inputs: bool,
|
skip_inputs: bool,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
locals: dict[str, Local] = {}
|
||||||
try:
|
try:
|
||||||
prototype = override if override else uop
|
prototype = override if override else uop
|
||||||
is_override = override is not None
|
is_override = override is not None
|
||||||
out.start_line()
|
out.start_line()
|
||||||
for var in reversed(prototype.stack.inputs):
|
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:
|
if not skip_inputs:
|
||||||
out.emit(res)
|
out.emit(code)
|
||||||
if not prototype.properties.stores_sp:
|
if local.defined:
|
||||||
for i, var in enumerate(prototype.stack.outputs):
|
locals[local.name] = local
|
||||||
res = stack.push(var)
|
out.emit(stack.define_output_arrays(prototype.stack.outputs))
|
||||||
if not var.peek or is_override:
|
|
||||||
out.emit(res)
|
|
||||||
if debug:
|
if debug:
|
||||||
args = []
|
args = []
|
||||||
for var in prototype.stack.inputs:
|
for var in prototype.stack.inputs:
|
||||||
|
@ -135,10 +134,12 @@ def write_uop(
|
||||||
else:
|
else:
|
||||||
emit_default(out, uop)
|
emit_default(out, uop)
|
||||||
|
|
||||||
if prototype.properties.stores_sp:
|
for var in prototype.stack.outputs:
|
||||||
for i, var in enumerate(prototype.stack.outputs):
|
if var.name in locals:
|
||||||
if not var.peek or is_override:
|
local = locals[var.name]
|
||||||
out.emit(stack.push(var))
|
else:
|
||||||
|
local = Local.local(var)
|
||||||
|
out.emit(stack.push(local))
|
||||||
out.start_line()
|
out.start_line()
|
||||||
stack.flush(out, cast_type="_Py_UopsSymbol *", extract_bits=True)
|
stack.flush(out, cast_type="_Py_UopsSymbol *", extract_bits=True)
|
||||||
except StackError as ex:
|
except StackError as ex:
|
||||||
|
|
|
@ -60,6 +60,11 @@ class Node:
|
||||||
end = context.end
|
end = context.end
|
||||||
return tokens[begin: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
|
@dataclass
|
||||||
class Block(Node):
|
class Block(Node):
|
||||||
|
|
|
@ -38,6 +38,43 @@ def var_size(var: StackItem) -> str:
|
||||||
else:
|
else:
|
||||||
return "1"
|
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
|
@dataclass
|
||||||
class StackOffset:
|
class StackOffset:
|
||||||
"The stack offset of the virtual base of the stack from the physical stack pointer"
|
"The stack offset of the virtual base of the stack from the physical stack pointer"
|
||||||
|
@ -66,7 +103,11 @@ class StackOffset:
|
||||||
|
|
||||||
def simplify(self) -> None:
|
def simplify(self) -> None:
|
||||||
"Remove matching values from both the popped and pushed list"
|
"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
|
return
|
||||||
# Sort the list so the lexically largest element is last.
|
# Sort the list so the lexically largest element is last.
|
||||||
popped = sorted(self.popped)
|
popped = sorted(self.popped)
|
||||||
|
@ -87,6 +128,8 @@ class StackOffset:
|
||||||
popped.append(pop)
|
popped.append(pop)
|
||||||
self.popped.extend(popped)
|
self.popped.extend(popped)
|
||||||
self.pushed.extend(pushed)
|
self.pushed.extend(pushed)
|
||||||
|
self.pushed.sort()
|
||||||
|
self.popped.sort()
|
||||||
|
|
||||||
def to_c(self) -> str:
|
def to_c(self) -> str:
|
||||||
self.simplify()
|
self.simplify()
|
||||||
|
@ -125,10 +168,10 @@ class Stack:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.top_offset = StackOffset.empty()
|
self.top_offset = StackOffset.empty()
|
||||||
self.base_offset = StackOffset.empty()
|
self.base_offset = StackOffset.empty()
|
||||||
self.variables: list[StackItem] = []
|
self.variables: list[Local] = []
|
||||||
self.defined: set[str] = set()
|
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)
|
self.top_offset.pop(var)
|
||||||
indirect = "&" if var.is_array() else ""
|
indirect = "&" if var.is_array() else ""
|
||||||
if self.variables:
|
if self.variables:
|
||||||
|
@ -141,21 +184,32 @@ class Stack:
|
||||||
if var.name in UNUSED:
|
if var.name in UNUSED:
|
||||||
if popped.name not in UNUSED and popped.name in self.defined:
|
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")
|
raise StackError(f"Value is declared unused, but is already cached by prior operation")
|
||||||
return ""
|
return "", popped
|
||||||
if popped.name in UNUSED or popped.name not in self.defined:
|
if not var.used:
|
||||||
self.defined.add(var.name)
|
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 (
|
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)
|
||||||
|
)
|
||||||
|
if not popped.defined:
|
||||||
|
return (
|
||||||
|
f"{var.name} = stack_pointer[{self.top_offset.to_c()}];\n",
|
||||||
|
Local.redefinition(var, popped)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.defined.add(var.name)
|
|
||||||
if popped.name == var.name:
|
if popped.name == var.name:
|
||||||
return ""
|
return "", popped
|
||||||
else:
|
else:
|
||||||
return f"{var.name} = {popped.name};\n"
|
return (
|
||||||
|
f"{var.name} = {popped.name};\n",
|
||||||
|
Local.redefinition(var, popped)
|
||||||
|
)
|
||||||
self.base_offset.pop(var)
|
self.base_offset.pop(var)
|
||||||
if var.name in UNUSED or not var.used:
|
if var.name in UNUSED or not var.used:
|
||||||
return ""
|
return "", Local.unused(var)
|
||||||
self.defined.add(var.name)
|
self.defined.add(var.name)
|
||||||
cast = f"({var.type})" if (not indirect and var.type) else ""
|
cast = f"({var.type})" if (not indirect and var.type) else ""
|
||||||
bits = ".bits" if cast and not extract_bits else ""
|
bits = ".bits" if cast and not extract_bits else ""
|
||||||
|
@ -164,61 +218,80 @@ class Stack:
|
||||||
)
|
)
|
||||||
if var.condition:
|
if var.condition:
|
||||||
if var.condition == "1":
|
if var.condition == "1":
|
||||||
return f"{assign}\n"
|
assign = f"{assign}\n"
|
||||||
elif var.condition == "0":
|
elif var.condition == "0":
|
||||||
return ""
|
return "", Local.unused(var)
|
||||||
else:
|
else:
|
||||||
return f"if ({var.condition}) {{ {assign} }}\n"
|
assign = f"if ({var.condition}) {{ {assign} }}\n"
|
||||||
return f"{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)
|
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()
|
c_offset = self.top_offset.to_c()
|
||||||
self.top_offset.push(var)
|
self.top_offset.push(var.item)
|
||||||
self.defined.add(var.name)
|
self.defined.add(var.name)
|
||||||
|
var.defined = True
|
||||||
return f"{var.name} = &stack_pointer[{c_offset}];\n"
|
return f"{var.name} = &stack_pointer[{c_offset}];\n"
|
||||||
else:
|
else:
|
||||||
self.top_offset.push(var)
|
self.top_offset.push(var.item)
|
||||||
if var.used:
|
if var.item.used:
|
||||||
self.defined.add(var.name)
|
self.defined.add(var.name)
|
||||||
return ""
|
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()
|
out.start_line()
|
||||||
for var in self.variables:
|
for var in variables:
|
||||||
if not var.peek:
|
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.type else ""
|
cast = f"({cast_type})" if var.item.type else ""
|
||||||
bits = ".bits" if cast and not extract_bits else ""
|
bits = ".bits" if cast and not extract_bits else ""
|
||||||
if var.name not in UNUSED and not var.is_array():
|
if var.condition == "0":
|
||||||
if var.condition:
|
continue
|
||||||
if var.condition == "0":
|
if var.condition and var.condition != "1":
|
||||||
continue
|
out.emit(f"if ({var.condition}) ")
|
||||||
elif var.condition != "1":
|
out.emit(
|
||||||
out.emit(f"if ({var.condition}) ")
|
f"stack_pointer[{base_offset.to_c()}]{bits} = {cast}{var.name};\n"
|
||||||
out.emit(
|
)
|
||||||
f"stack_pointer[{self.base_offset.to_c()}]{bits} = {cast}{var.name};\n"
|
base_offset.push(var.item)
|
||||||
)
|
if base_offset.to_c() != top_offset.to_c():
|
||||||
self.base_offset.push(var)
|
print("base", base_offset, "top", top_offset)
|
||||||
if self.base_offset.to_c() != self.top_offset.to_c():
|
|
||||||
print("base", self.base_offset.to_c(), "top", self.top_offset.to_c())
|
|
||||||
assert False
|
assert False
|
||||||
number = self.base_offset.to_c()
|
number = base_offset.to_c()
|
||||||
if number != "0":
|
if number != "0":
|
||||||
out.emit(f"stack_pointer += {number};\n")
|
out.emit(f"stack_pointer += {number};\n")
|
||||||
out.emit("assert(WITHIN_STACK_BOUNDS());\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.variables = []
|
||||||
self.base_offset.clear()
|
self.base_offset.clear()
|
||||||
self.top_offset.clear()
|
self.top_offset.clear()
|
||||||
out.start_line()
|
|
||||||
|
|
||||||
def peek_offset(self) -> str:
|
def peek_offset(self) -> str:
|
||||||
peek = self.base_offset.copy()
|
return self.top_offset.to_c()
|
||||||
for var in self.variables:
|
|
||||||
if not var.peek:
|
|
||||||
break
|
|
||||||
peek.push(var)
|
|
||||||
return peek.to_c()
|
|
||||||
|
|
||||||
def as_comment(self) -> str:
|
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()} */"
|
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 get_stack_effect(inst: Instruction | PseudoInstruction) -> Stack:
|
||||||
yield inst.stack
|
yield inst.stack
|
||||||
|
|
||||||
for s in stacks(inst):
|
for s in stacks(inst):
|
||||||
|
locals: dict[str, Local] = {}
|
||||||
for var in reversed(s.inputs):
|
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:
|
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
|
return stack
|
||||||
|
|
|
@ -25,7 +25,7 @@ from generators_common import (
|
||||||
)
|
)
|
||||||
from cwriter import CWriter
|
from cwriter import CWriter
|
||||||
from typing import TextIO
|
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"
|
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:
|
def declare_variables(inst: Instruction, out: CWriter) -> None:
|
||||||
stack = Stack()
|
try:
|
||||||
for part in inst.parts:
|
stack = get_stack_effect(inst)
|
||||||
if not isinstance(part, Uop):
|
except StackError as ex:
|
||||||
continue
|
raise analysis_error(ex.args[0], inst.where)
|
||||||
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
|
|
||||||
required = set(stack.defined)
|
required = set(stack.defined)
|
||||||
|
required.discard("unused")
|
||||||
for part in inst.parts:
|
for part in inst.parts:
|
||||||
if not isinstance(part, Uop):
|
if not isinstance(part, Uop):
|
||||||
continue
|
continue
|
||||||
|
@ -80,16 +74,26 @@ def write_uop(
|
||||||
stack.flush(out)
|
stack.flush(out)
|
||||||
return offset
|
return offset
|
||||||
try:
|
try:
|
||||||
|
locals: dict[str, Local] = {}
|
||||||
out.start_line()
|
out.start_line()
|
||||||
if braces:
|
if braces:
|
||||||
out.emit(f"// {uop.name}\n")
|
out.emit(f"// {uop.name}\n")
|
||||||
|
peeks: list[Local] = []
|
||||||
for var in reversed(uop.stack.inputs):
|
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:
|
if braces:
|
||||||
out.emit("{\n")
|
out.emit("{\n")
|
||||||
if not uop.properties.stores_sp:
|
out.emit(stack.define_output_arrays(uop.stack.outputs))
|
||||||
for i, var in enumerate(uop.stack.outputs):
|
|
||||||
out.emit(stack.push(var))
|
|
||||||
for cache in uop.caches:
|
for cache in uop.caches:
|
||||||
if cache.name != "unused":
|
if cache.name != "unused":
|
||||||
if cache.size == 4:
|
if cache.size == 4:
|
||||||
|
@ -105,16 +109,22 @@ def write_uop(
|
||||||
out.emit(f"(void){cache.name};\n")
|
out.emit(f"(void){cache.name};\n")
|
||||||
offset += cache.size
|
offset += cache.size
|
||||||
emit_tokens(out, uop, stack, inst)
|
emit_tokens(out, uop, stack, inst)
|
||||||
if uop.properties.stores_sp:
|
for i, var in enumerate(uop.stack.outputs):
|
||||||
for i, var in enumerate(uop.stack.outputs):
|
if not var.peek:
|
||||||
out.emit(stack.push(var))
|
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:
|
if braces:
|
||||||
out.start_line()
|
out.start_line()
|
||||||
out.emit("}\n")
|
out.emit("}\n")
|
||||||
# out.emit(stack.as_comment() + "\n")
|
# out.emit(stack.as_comment() + "\n")
|
||||||
return offset
|
return offset
|
||||||
except StackError as ex:
|
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:
|
def uses_this(inst: Instruction) -> bool:
|
||||||
|
|
|
@ -25,7 +25,7 @@ from generators_common import (
|
||||||
from cwriter import CWriter
|
from cwriter import CWriter
|
||||||
from typing import TextIO, Iterator
|
from typing import TextIO, Iterator
|
||||||
from lexer import Token
|
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"
|
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):
|
for var in reversed(uop.stack.inputs):
|
||||||
stack.pop(var)
|
stack.pop(var)
|
||||||
for var in uop.stack.outputs:
|
for var in uop.stack.outputs:
|
||||||
stack.push(var)
|
stack.push(Local.unused(var))
|
||||||
required = set(stack.defined)
|
required = set(stack.defined)
|
||||||
|
required.discard("unused")
|
||||||
for var in reversed(uop.stack.inputs):
|
for var in reversed(uop.stack.inputs):
|
||||||
declare_variable(var, uop, required, out)
|
declare_variable(var, uop, required, out)
|
||||||
for var in uop.stack.outputs:
|
for var in uop.stack.outputs:
|
||||||
|
@ -156,6 +157,7 @@ TIER2_REPLACEMENT_FUNCTIONS["EXIT_IF"] = tier2_replace_exit_if
|
||||||
|
|
||||||
|
|
||||||
def write_uop(uop: Uop, out: CWriter, stack: Stack) -> None:
|
def write_uop(uop: Uop, out: CWriter, stack: Stack) -> None:
|
||||||
|
locals: dict[str, Local] = {}
|
||||||
try:
|
try:
|
||||||
out.start_line()
|
out.start_line()
|
||||||
if uop.properties.oparg:
|
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"oparg = {uop.properties.const_oparg};\n")
|
||||||
out.emit(f"assert(oparg == CURRENT_OPARG());\n")
|
out.emit(f"assert(oparg == CURRENT_OPARG());\n")
|
||||||
for var in reversed(uop.stack.inputs):
|
for var in reversed(uop.stack.inputs):
|
||||||
out.emit(stack.pop(var))
|
code, local = stack.pop(var)
|
||||||
if not uop.properties.stores_sp:
|
out.emit(code)
|
||||||
for i, var in enumerate(uop.stack.outputs):
|
if local.defined:
|
||||||
out.emit(stack.push(var))
|
locals[local.name] = local
|
||||||
|
out.emit(stack.define_output_arrays(uop.stack.outputs))
|
||||||
for cache in uop.caches:
|
for cache in uop.caches:
|
||||||
if cache.name != "unused":
|
if cache.name != "unused":
|
||||||
if cache.size == 4:
|
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"
|
cast = f"uint{cache.size*16}_t"
|
||||||
out.emit(f"{type}{cache.name} = ({cast})CURRENT_OPERAND();\n")
|
out.emit(f"{type}{cache.name} = ({cast})CURRENT_OPERAND();\n")
|
||||||
emit_tokens(out, uop, stack, None, TIER2_REPLACEMENT_FUNCTIONS)
|
emit_tokens(out, uop, stack, None, TIER2_REPLACEMENT_FUNCTIONS)
|
||||||
if uop.properties.stores_sp:
|
for i, var in enumerate(uop.stack.outputs):
|
||||||
for i, var in enumerate(uop.stack.outputs):
|
if var.name in locals:
|
||||||
out.emit(stack.push(var))
|
local = locals[var.name]
|
||||||
|
else:
|
||||||
|
local = Local.local(var)
|
||||||
|
out.emit(stack.push(local))
|
||||||
except StackError as ex:
|
except StackError as ex:
|
||||||
raise analysis_error(ex.args[0], uop.body[0]) from None
|
raise analysis_error(ex.args[0], uop.body[0]) from None
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue