Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GH-98831: Simple input-output stack effects #99120

Merged
merged 22 commits into from
Nov 8, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 37 additions & 67 deletions Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ do { \
#define DISPATCH() ((void)0)

#define inst(name) case name:
#define instr(name, arg) case name:
#define family(name) static int family_##name

#define NAME_ERROR_MSG \
Expand Down Expand Up @@ -103,58 +104,46 @@ dummy_func(
and that all operation that succeed call DISPATCH() ! */

// BEGIN BYTECODES //
// stack effect: ( -- )
inst(NOP) {
instr(NOP, (--)) {
}

// stack effect: ( -- )
inst(RESUME) {
instr(RESUME, (--)) {
assert(tstate->cframe == &cframe);
assert(frame == cframe.current_frame);
if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) {
goto handle_eval_breaker;
}
}

// stack effect: ( -- __0)
inst(LOAD_CLOSURE) {
instr(LOAD_CLOSURE, (-- value)) {
/* We keep LOAD_CLOSURE so that the bytecode stays more readable. */
PyObject *value = GETLOCAL(oparg);
value = GETLOCAL(oparg);
if (value == NULL) {
goto unbound_local_error;
}
Py_INCREF(value);
PUSH(value);
}

// stack effect: ( -- __0)
inst(LOAD_FAST_CHECK) {
PyObject *value = GETLOCAL(oparg);
instr(LOAD_FAST_CHECK, (-- value)) {
value = GETLOCAL(oparg);
if (value == NULL) {
goto unbound_local_error;
}
Py_INCREF(value);
PUSH(value);
}

// stack effect: ( -- __0)
inst(LOAD_FAST) {
PyObject *value = GETLOCAL(oparg);
instr(LOAD_FAST, (-- value)) {
value = GETLOCAL(oparg);
assert(value != NULL);
Py_INCREF(value);
PUSH(value);
}

// stack effect: ( -- __0)
inst(LOAD_CONST) {
PyObject *value = GETITEM(consts, oparg);
instr(LOAD_CONST, (-- value)) {
value = GETITEM(consts, oparg);
Py_INCREF(value);
PUSH(value);
}

// stack effect: (__0 -- )
inst(STORE_FAST) {
PyObject *value = POP();
instr(STORE_FAST, (value --)) {
SETLOCAL(oparg, value);
}

Expand Down Expand Up @@ -220,9 +209,7 @@ dummy_func(
PUSH(value);
}

// stack effect: (__0 -- )
inst(POP_TOP) {
PyObject *value = POP();
instr(POP_TOP, (value --)) {
Py_DECREF(value);
}

Expand All @@ -232,76 +219,59 @@ dummy_func(
BASIC_PUSH(NULL);
}

// stack effect: (__0, __1 -- )
inst(END_FOR) {
PyObject *value = POP();
Py_DECREF(value);
value = POP();
Py_DECREF(value);
instr(END_FOR, (value1, value2 --)) {
Py_DECREF(value1);
Py_DECREF(value2);
}

// stack effect: ( -- )
inst(UNARY_POSITIVE) {
PyObject *value = TOP();
PyObject *res = PyNumber_Positive(value);
instr(UNARY_POSITIVE, (value -- res)) {
res = PyNumber_Positive(value);
Py_DECREF(value);
SET_TOP(res);
if (res == NULL)
if (res == NULL) {
goto error;
}
}

// stack effect: ( -- )
inst(UNARY_NEGATIVE) {
PyObject *value = TOP();
PyObject *res = PyNumber_Negative(value);
instr(UNARY_NEGATIVE, (value -- res)) {
res = PyNumber_Negative(value);
Py_DECREF(value);
SET_TOP(res);
if (res == NULL)
if (res == NULL) {
goto error;
}
}

// stack effect: ( -- )
inst(UNARY_NOT) {
PyObject *value = TOP();
instr(UNARY_NOT, (value -- res)) {
int err = PyObject_IsTrue(value);
Py_DECREF(value);
if (err == 0) {
Py_INCREF(Py_True);
SET_TOP(Py_True);
DISPATCH();
res = Py_True;
}
else if (err > 0) {
Py_INCREF(Py_False);
SET_TOP(Py_False);
DISPATCH();
res = Py_False;
}
STACK_SHRINK(1);
goto error;
else {
goto error;
}
Py_INCREF(res);
}

// stack effect: ( -- )
inst(UNARY_INVERT) {
PyObject *value = TOP();
PyObject *res = PyNumber_Invert(value);
instr(UNARY_INVERT, (value -- res)) {
res = PyNumber_Invert(value);
Py_DECREF(value);
SET_TOP(res);
if (res == NULL)
if (res == NULL) {
goto error;
}
}

// stack effect: (__0 -- )
inst(BINARY_OP_MULTIPLY_INT) {
instr(BINARY_OP_MULTIPLY_INT, (left, right -- prod)) {
// TODO: Don't pop from the stack before DEOPF_IF() calls.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you generate peeks at the beginning of the instruction and pops at the end just before the pushes?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's why this is still a draft PR. :-)

assert(cframe.use_tracing == 0);
PyObject *left = SECOND();
PyObject *right = TOP();
DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);
DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP);
STAT_INC(BINARY_OP, hit);
PyObject *prod = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right);
SET_SECOND(prod);
_Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
_Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);
STACK_SHRINK(1);
if (prod == NULL) {
goto error;
}
Expand Down
77 changes: 44 additions & 33 deletions Python/generated_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions Tools/cases_generator/generate_cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ def write_cases(f: io.TextIOBase, instrs: list[InstDef]):
for instr in instrs:
assert isinstance(instr, InstDef)
f.write(f"\n{indent}TARGET({instr.name}) {{\n")
for input in reversed(instr.inputs or ()):
f.write(f"{indent} PyObject *{input} = POP();\n")
for output in instr.outputs or ():
f.write(f"{indent} PyObject *{output};\n")
if instr.name in predictions:
f.write(f"{indent} PREDICTED({instr.name});\n")
# input = ", ".join(instr.inputs)
Expand All @@ -96,6 +100,8 @@ def write_cases(f: io.TextIOBase, instrs: list[InstDef]):
# Write the body
for line in blocklines:
f.write(line)
for output in instr.outputs or ():
f.write(f"{indent} PUSH({output});\n")
assert instr.block
if not always_exits(instr.block):
f.write(f"{indent} DISPATCH();\n")
Expand Down
2 changes: 1 addition & 1 deletion Tools/cases_generator/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def inst_header(self):
# inst(NAME) | inst(NAME, (inputs -- outputs))
# TODO: Error out when there is something unexpected.
# TODO: Make INST a keyword in the lexer.
if (tkn := self.expect(lx.IDENTIFIER)) and tkn.text == "inst":
if (tkn := self.expect(lx.IDENTIFIER)) and tkn.text in ("inst", "instr"):
if (self.expect(lx.LPAREN)
and (tkn := self.expect(lx.IDENTIFIER))):
name = tkn.text
Expand Down