Skip to content

Commit 62c67b0

Browse files
committed
Fix code generated for super instructions
1 parent 43e7796 commit 62c67b0

File tree

2 files changed

+91
-58
lines changed

2 files changed

+91
-58
lines changed

Python/generated_cases.c.h

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Tools/cases_generator/generate_cases.py

Lines changed: 64 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
# TODO: Reuse C generation framework from deepfreeze.py?
66

77
import argparse
8-
import io
98
import os
109
import re
1110
import sys
11+
from typing import TextIO, cast
1212

1313
import parser
1414
from parser import InstDef # TODO: Use parser.InstDef
@@ -20,13 +20,13 @@
2020
arg_parser.add_argument("-q", "--quiet", action="store_true")
2121

2222

23-
def eopen(filename: str, mode: str = "r"):
23+
def eopen(filename: str, mode: str = "r") -> TextIO:
2424
if filename == "-":
2525
if "r" in mode:
2626
return sys.stdin
2727
else:
2828
return sys.stdout
29-
return open(filename, mode)
29+
return cast(TextIO, open(filename, mode))
3030

3131

3232
def parse_cases(
@@ -67,66 +67,73 @@ def always_exits(block: parser.Block) -> bool:
6767
return line.startswith(("goto ", "return ", "DISPATCH", "GO_TO_", "Py_UNREACHABLE()"))
6868

6969

70-
def write_cases(f: io.TextIOBase, instrs: list[InstDef], supers: list[parser.Super]):
70+
def write_instr(instr: InstDef, predictions: set[str], indent: str, f: TextIO, dedent: int = 0):
71+
assert instr.block
72+
if dedent < 0:
73+
indent += " " * -dedent
74+
# TODO: Is it better to count forward or backward?
75+
for i, input in enumerate(reversed(instr.inputs or ()), 1):
76+
f.write(f"{indent} PyObject *{input} = PEEK({i});\n")
77+
for output in instr.outputs or ():
78+
f.write(f"{indent} PyObject *{output};\n")
79+
# input = ", ".join(instr.inputs)
80+
# output = ", ".join(instr.outputs)
81+
# f.write(f"{indent} // {input} -- {output}\n")
82+
assert instr.block is not None
83+
blocklines = instr.block.to_text(dedent=dedent).splitlines(True)
84+
# Remove blank lines from ends
85+
while blocklines and not blocklines[0].strip():
86+
blocklines.pop(0)
87+
while blocklines and not blocklines[-1].strip():
88+
blocklines.pop()
89+
# Remove leading '{' and trailing '}'
90+
assert blocklines and blocklines[0].strip() == "{"
91+
assert blocklines and blocklines[-1].strip() == "}"
92+
blocklines.pop()
93+
blocklines.pop(0)
94+
# Remove trailing blank lines
95+
while blocklines and not blocklines[-1].strip():
96+
blocklines.pop()
97+
# Write the body
98+
ninputs = len(instr.inputs or ())
99+
for line in blocklines:
100+
if m := re.match(r"(\s*)ERROR_IF\(([^,]+), (\w+)\);\s*$", line):
101+
space, cond, label = m.groups()
102+
# ERROR_IF() must remove the inputs from the stack.
103+
# The code block is responsible for DECREF()ing them.
104+
if ninputs:
105+
f.write(f"{space}if ({cond}) {{ STACK_SHRINK({ninputs}); goto {label}; }}\n")
106+
else:
107+
f.write(f"{space}if ({cond}) {{ goto {label}; }}\n")
108+
else:
109+
f.write(line)
110+
noutputs = len(instr.outputs or ())
111+
diff = noutputs - ninputs
112+
if diff > 0:
113+
f.write(f"{indent} STACK_GROW({diff});\n")
114+
elif diff < 0:
115+
f.write(f"{indent} STACK_SHRINK({-diff});\n")
116+
for i, output in enumerate(reversed(instr.outputs or ()), 1):
117+
f.write(f"{indent} POKE({i}, {output});\n")
118+
assert instr.block
119+
120+
def write_cases(f: TextIO, instrs: list[InstDef], supers: list[parser.Super]):
71121
predictions: set[str] = set()
72-
for inst in instrs:
73-
assert inst.block is not None
74-
for target in re.findall(r"(?:PREDICT|GO_TO_INSTRUCTION)\((\w+)\)", inst.block.text):
122+
for instr in instrs:
123+
assert isinstance(instr, InstDef)
124+
assert instr.block is not None
125+
for target in re.findall(r"(?:PREDICT|GO_TO_INSTRUCTION)\((\w+)\)", instr.block.text):
75126
predictions.add(target)
76127
indent = " "
77128
f.write(f"// This file is generated by {os.path.relpath(__file__)}\n")
78-
f.write("// Do not edit!\n")
129+
f.write(f"// Do not edit!\n")
79130
instr_index: dict[str, InstDef] = {}
80131
for instr in instrs:
81-
assert isinstance(instr, InstDef)
82132
instr_index[instr.name] = instr
83133
f.write(f"\n{indent}TARGET({instr.name}) {{\n")
84134
if instr.name in predictions:
85135
f.write(f"{indent} PREDICTED({instr.name});\n")
86-
# TODO: Is it better to count forward or backward?
87-
for i, input in enumerate(reversed(instr.inputs or ()), 1):
88-
f.write(f"{indent} PyObject *{input} = PEEK({i});\n")
89-
for output in instr.outputs or ():
90-
f.write(f"{indent} PyObject *{output};\n")
91-
# input = ", ".join(instr.inputs)
92-
# output = ", ".join(instr.outputs)
93-
# f.write(f"{indent} // {input} -- {output}\n")
94-
assert instr.block is not None
95-
blocklines = instr.block.text.splitlines(True)
96-
# Remove blank lines from ends
97-
while blocklines and not blocklines[0].strip():
98-
blocklines.pop(0)
99-
while blocklines and not blocklines[-1].strip():
100-
blocklines.pop()
101-
# Remove leading '{' and trailing '}'
102-
assert blocklines and blocklines[0].strip() == "{"
103-
assert blocklines and blocklines[-1].strip() == "}"
104-
blocklines.pop()
105-
blocklines.pop(0)
106-
# Remove trailing blank lines
107-
while blocklines and not blocklines[-1].strip():
108-
blocklines.pop()
109-
# Write the body
110-
ninputs = len(instr.inputs or ())
111-
for line in blocklines:
112-
if m := re.match(r"(\s*)ERROR_IF\(([^,]+), (\w+)\);\s*$", line):
113-
space, cond, label = m.groups()
114-
# ERROR_IF() must remove the inputs from the stack.
115-
# The code block is responsible for DECREF()ing them.
116-
if ninputs:
117-
f.write(f"{space}if ({cond}) {{ STACK_SHRINK({ninputs}); goto {label}; }}\n")
118-
else:
119-
f.write(f"{space}if ({cond}) {{ goto {label}; }}\n")
120-
else:
121-
f.write(line)
122-
noutputs = len(instr.outputs or ())
123-
diff = noutputs - ninputs
124-
if diff > 0:
125-
f.write(f"{indent} STACK_GROW({diff});\n")
126-
elif diff < 0:
127-
f.write(f"{indent} STACK_SHRINK({-diff});\n")
128-
for i, output in enumerate(reversed(instr.outputs or ()), 1):
129-
f.write(f"{indent} POKE({i}, {output});\n")
136+
write_instr(instr, predictions, indent, f)
130137
assert instr.block
131138
if not always_exits(instr.block):
132139
f.write(f"{indent} DISPATCH();\n")
@@ -138,14 +145,13 @@ def write_cases(f: io.TextIOBase, instrs: list[InstDef], supers: list[parser.Sup
138145
components = [instr_index[name] for name in sup.ops]
139146
f.write(f"\n{indent}TARGET({sup.name}) {{\n")
140147
for i, instr in enumerate(components):
148+
assert instr.block
141149
if i > 0:
142150
f.write(f"{indent} NEXTOPARG();\n")
143151
f.write(f"{indent} next_instr++;\n")
144-
text = instr.block.to_text(-4)
145-
textlines = text.splitlines(True)
146-
textlines = [line for line in textlines if not line.strip().startswith("PREDICTED(")]
147-
text = "".join(textlines)
148-
f.write(f"{indent} {text.strip()}\n")
152+
f.write(f"{indent} {{\n")
153+
write_instr(instr, predictions, indent, f, dedent=-4)
154+
f.write(f" {indent}}}\n")
149155
f.write(f"{indent} DISPATCH();\n")
150156
f.write(f"{indent}}}\n")
151157

0 commit comments

Comments
 (0)