Skip to content

Commit

Permalink
Simple input-output stack effects
Browse files Browse the repository at this point in the history
No arrays; no conitionals; no types; no cache effects.
  • Loading branch information
gvanrossum committed Nov 5, 2022
1 parent 12078e7 commit cc86e73
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 85 deletions.
87 changes: 29 additions & 58 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,59 +219,43 @@ 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)
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)
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);
inst(UNARY_INVERT, (value -- res)) {
res = PyNumber_Invert(value);
Py_DECREF(value);
SET_TOP(res);
if (res == NULL)
goto error;
}
Expand Down
60 changes: 34 additions & 26 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 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

0 comments on commit cc86e73

Please sign in to comment.