Skip to content

gh-98831: add variable stack effect support to cases generator #101309

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

Merged
merged 4 commits into from
Jan 25, 2023
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
7 changes: 4 additions & 3 deletions Python/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -8655,12 +8655,13 @@ opcode_metadata_is_sane(cfg_builder *g) {
for (int i = 0; i < b->b_iused; i++) {
struct instr *instr = &b->b_instr[i];
int opcode = instr->i_opcode;
int oparg = instr->i_oparg;
assert(opcode <= MAX_REAL_OPCODE);
int pushed = _PyOpcode_opcode_metadata[opcode].n_pushed;
int popped = _PyOpcode_opcode_metadata[opcode].n_popped;
int pushed = _PyOpcode_opcode_metadata(opcode, oparg).n_pushed;
int popped = _PyOpcode_opcode_metadata(opcode, oparg).n_popped;
assert((pushed < 0) == (popped < 0));
if (pushed >= 0) {
assert(_PyOpcode_opcode_metadata[opcode].valid_entry);
assert(_PyOpcode_opcode_metadata(opcode, oparg).valid_entry);
int effect = stack_effect(opcode, instr->i_oparg, -1);
if (effect != pushed - popped) {
fprintf(stderr,
Expand Down
32 changes: 19 additions & 13 deletions Python/opcode_metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@
// Do not edit!
enum Direction { DIR_NONE, DIR_READ, DIR_WRITE };
enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC0, INSTR_FMT_IBC000, INSTR_FMT_IBIB, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC000 };
static const struct {
struct opcode_metadata {
short n_popped;
short n_pushed;
enum Direction dir_op1;
enum Direction dir_op2;
enum Direction dir_op3;
bool valid_entry;
enum InstructionFormat instr_format;
} _PyOpcode_opcode_metadata[256] = {
};

static struct opcode_metadata
_PyOpcode_opcode_metadata(int opcode, int oparg) {
struct opcode_metadata metadata[256] = {
[NOP] = { 0, 0, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX },
[RESUME] = { 0, 0, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[LOAD_CLOSURE] = { 0, 1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
Expand Down Expand Up @@ -45,8 +49,8 @@ static const struct {
[BINARY_SUBSCR_TUPLE_INT] = { 2, 1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 },
[BINARY_SUBSCR_DICT] = { 2, 1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 },
[BINARY_SUBSCR_GETITEM] = { 2, 1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 },
[LIST_APPEND] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[SET_ADD] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[LIST_APPEND] = { (oparg-1)+2, (oparg-1)+1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[SET_ADD] = { (oparg-1)+2, (oparg-1)+1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[STORE_SUBSCR] = { 3, 0, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC },
[STORE_SUBSCR_LIST_INT] = { 3, 0, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC },
[STORE_SUBSCR_DICT] = { 3, 0, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC },
Expand Down Expand Up @@ -89,15 +93,15 @@ static const struct {
[LOAD_DEREF] = { 0, 1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[STORE_DEREF] = { 1, 0, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[COPY_FREE_VARS] = { 0, 0, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[BUILD_STRING] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[BUILD_TUPLE] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[BUILD_LIST] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[LIST_EXTEND] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[SET_UPDATE] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[BUILD_SET] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[BUILD_MAP] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[BUILD_STRING] = { oparg, 1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[BUILD_TUPLE] = { oparg, 1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[BUILD_LIST] = { oparg, 1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[LIST_EXTEND] = { (oparg-1)+2, (oparg-1)+1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[SET_UPDATE] = { (oparg-1)+2, (oparg-1)+1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[BUILD_SET] = { oparg, 1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[BUILD_MAP] = { oparg*2, 1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[SETUP_ANNOTATIONS] = { 0, 0, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX },
[BUILD_CONST_KEY_MAP] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[BUILD_CONST_KEY_MAP] = { oparg+1, 1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[DICT_UPDATE] = { 1, 0, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[DICT_MERGE] = { 1, 0, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[MAP_ADD] = { 2, 0, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
Expand Down Expand Up @@ -180,4 +184,6 @@ static const struct {
[SWAP] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[EXTENDED_ARG] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[CACHE] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX },
};
};
return metadata[opcode];
}
18 changes: 12 additions & 6 deletions Tools/cases_generator/generate_cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,7 @@ def write_metadata(self) -> None:
# Write variable definition
self.out.emit("enum Direction { DIR_NONE, DIR_READ, DIR_WRITE };")
self.out.emit(f"enum InstructionFormat {{ {', '.join(format_enums)} }};")
self.out.emit("static const struct {")
self.out.emit("struct opcode_metadata {")
with self.out.indent():
self.out.emit("short n_popped;")
self.out.emit("short n_pushed;")
Expand All @@ -774,7 +774,10 @@ def write_metadata(self) -> None:
self.out.emit("enum Direction dir_op3;")
self.out.emit("bool valid_entry;")
self.out.emit("enum InstructionFormat instr_format;")
self.out.emit("} _PyOpcode_opcode_metadata[256] = {")
self.out.emit("};")
self.out.emit("\nstatic struct opcode_metadata")
self.out.emit("_PyOpcode_opcode_metadata(int opcode, int oparg) {")
self.out.emit(" struct opcode_metadata metadata[256] = {")

# Write metadata for each instruction
for thing in self.everything:
Expand All @@ -790,7 +793,9 @@ def write_metadata(self) -> None:
typing.assert_never(thing)

# Write end of array
self.out.emit("};")
self.out.emit(" };")
self.out.emit(" return metadata[opcode];")
self.out.emit("}")

def write_metadata_for_inst(self, instr: Instruction) -> None:
"""Write metadata for a single instruction."""
Expand All @@ -801,9 +806,10 @@ def write_metadata_for_inst(self, instr: Instruction) -> None:
else:
n_popped, sym_popped = list_effect_size(instr.input_effects)
n_pushed, sym_pushed = list_effect_size(instr.output_effects)
if sym_popped or sym_pushed:
# TODO: Record symbolic effects (how?)
n_popped = n_pushed = -1
if sym_popped:
n_popped = f"{sym_popped}+{n_popped}" if n_popped else sym_popped
if sym_pushed:
n_pushed = f"{sym_pushed}+{n_pushed}" if n_pushed else sym_pushed
if instr.register:
directions: list[str] = []
directions.extend("DIR_READ" for _ in instr.input_effects)
Expand Down