Skip to content

Commit e4f1624

Browse files
Clean up the cases generator
1 parent a62fe40 commit e4f1624

File tree

4 files changed

+74
-69
lines changed

4 files changed

+74
-69
lines changed

Python/generated_tracer_cases.c.h

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

Tools/cases_generator/generators_common.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,9 @@ class Emitter:
107107
labels: dict[str, Label]
108108
_replacers: dict[str, ReplacementFunctionType]
109109
cannot_escape: bool
110-
tracing: str
110+
jump_prefix: str
111111

112-
def __init__(self, out: CWriter, labels: dict[str, Label], cannot_escape: bool = False, is_tracing: bool = False):
112+
def __init__(self, out: CWriter, labels: dict[str, Label], cannot_escape: bool = False, jump_prefix: str = ""):
113113
self._replacers = {
114114
"EXIT_IF": self.exit_if,
115115
"AT_END_EXIT_IF": self.exit_if_after,
@@ -133,7 +133,7 @@ def __init__(self, out: CWriter, labels: dict[str, Label], cannot_escape: bool =
133133
self.out = out
134134
self.labels = labels
135135
self.cannot_escape = cannot_escape
136-
self.tracing = "TRACING_" if is_tracing else ""
136+
self.jump_prefix = jump_prefix
137137

138138
def dispatch(
139139
self,
@@ -170,7 +170,7 @@ def deopt_if(
170170
family_name = inst.family.name
171171
self.emit(f"UPDATE_MISS_STATS({family_name});\n")
172172
self.emit(f"assert(_PyOpcode_Deopt[opcode] == ({family_name}));\n")
173-
self.emit(f"JUMP_TO_PREDICTED({family_name});\n")
173+
self.emit(f"JUMP_TO_PREDICTED({self.jump_prefix}{family_name});\n")
174174
self.emit("}\n")
175175
return not always_true(first_tkn)
176176

@@ -201,10 +201,10 @@ def exit_if_after(
201201

202202
def goto_error(self, offset: int, storage: Storage) -> str:
203203
if offset > 0:
204-
return f"{self.tracing}JUMP_TO_LABEL(pop_{offset}_error);"
204+
return f"{self.jump_prefix}JUMP_TO_LABEL(pop_{offset}_error);"
205205
if offset < 0:
206206
storage.copy().flush(self.out)
207-
return f"{self.tracing}JUMP_TO_LABEL(error);"
207+
return f"{self.jump_prefix}JUMP_TO_LABEL(error);"
208208

209209
def error_if(
210210
self,
@@ -424,7 +424,7 @@ def goto_label(self, goto: Token, label: Token, storage: Storage) -> None:
424424
elif storage.spilled:
425425
raise analysis_error("Cannot jump from spilled label without reloading the stack pointer", goto)
426426
self.out.start_line()
427-
self.out.emit(f"{self.tracing}JUMP_TO_LABEL(")
427+
self.out.emit(f"{self.jump_prefix}JUMP_TO_LABEL(")
428428
self.out.emit(label)
429429
self.out.emit(")")
430430

Tools/cases_generator/tier1_generator.py

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -217,23 +217,20 @@ def get_popped(inst: Instruction, analysis: Analysis) -> str:
217217
return (-stack.base_offset).to_c()
218218

219219
def generate_tier1_cases(
220-
analysis: Analysis, out: CWriter, emitter: Emitter, is_tracing: bool = False
220+
analysis: Analysis, out: CWriter, emitter: Emitter
221221
) -> None:
222-
tracing_prepend = "TRACING_" if is_tracing else ""
223222
out.emit("\n")
224223
for name, inst in sorted(analysis.instructions.items()):
225224
out.emit("\n")
226-
out.emit(f"{tracing_prepend}TARGET({name}) {{\n")
227-
if is_tracing:
228-
out.emit(f"assert(IS_JIT_TRACING());\n")
225+
out.emit(f"TARGET({name}) {{\n")
229226
popped = get_popped(inst, analysis)
230227
# We need to ifdef it because this breaks platforms
231228
# without computed gotos/tail calling.
232229
out.emit(f"#if _Py_TAIL_CALL_INTERP\n")
233230
out.emit(f"int opcode = {name};\n")
234231
out.emit(f"(void)(opcode);\n")
235232
out.emit(f"#endif\n")
236-
needs_this = is_tracing or uses_this(inst)
233+
needs_this = uses_this(inst)
237234
unused_guard = "(void)this_instr;\n"
238235
if inst.properties.needs_prev:
239236
out.emit(f"_Py_CODEUNIT* const prev_instr = frame->instr_ptr;\n")
@@ -247,21 +244,10 @@ def generate_tier1_cases(
247244
out.emit(f"next_instr += {inst.size};\n")
248245
out.emit(f"INSTRUCTION_STATS({name});\n")
249246
if inst.is_target:
250-
out.emit(f"PREDICTED_{tracing_prepend}{name}:;\n")
247+
out.emit(f"PREDICTED_{name}:;\n")
251248
if needs_this:
252249
out.emit(f"_Py_CODEUNIT* const this_instr = next_instr - {inst.size};\n")
253250
out.emit(unused_guard)
254-
if is_tracing:
255-
# This is required so that the predicted ops reflect the correct opcode.
256-
out.emit(f"opcode = {name};\n")
257-
out.emit(f"PyCodeObject *old_code = (PyCodeObject *)PyStackRef_AsPyObjectBorrow(frame->f_executable);\n")
258-
out.emit(f"(void)old_code;\n")
259-
out.emit(f"PyFunctionObject *old_func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj);\n")
260-
out.emit(f"(void)old_func;\n")
261-
out.emit(f"int _jump_taken = false;\n")
262-
out.emit(f"(void)_jump_taken;\n")
263-
out.emit(f"int _old_stack_level = !PyStackRef_IsNull(frame->f_executable) ? STACK_LEVEL() : 0;\n")
264-
out.emit(f"(void)(_old_stack_level);\n")
265251
if inst.properties.uses_opcode:
266252
out.emit(f"opcode = {name};\n")
267253
if inst.family is not None:
@@ -279,7 +265,7 @@ def generate_tier1_cases(
279265
out.start_line()
280266
if reachable: # type: ignore[possibly-undefined]
281267
stack.flush(out)
282-
out.emit(f"{tracing_prepend}DISPATCH();\n")
268+
out.emit(f"DISPATCH();\n")
283269
out.start_line()
284270
out.emit("}")
285271
out.emit("\n")

Tools/cases_generator/tracer_generator.py

Lines changed: 62 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
from typing import TextIO
2929
from lexer import Token
3030
from stack import Local, Stack, StackError, get_stack_effect, Storage
31-
from tier1_generator import generate_tier1_cases
31+
from tier1_generator import get_popped, declare_variables, write_uop
3232

3333
DEFAULT_OUTPUT = ROOT / "Python/generated_tracer_cases.c.h"
3434

@@ -39,7 +39,7 @@ class TracerEmitter(Emitter):
3939
cannot_escape: bool
4040

4141
def __init__(self, out: CWriter, labels: dict[str, Label], cannot_escape: bool = False):
42-
super().__init__(out, labels, cannot_escape, is_tracing=True)
42+
super().__init__(out, labels, cannot_escape, jump_prefix="TRACING_")
4343
self._replacers = {
4444
**self._replacers,
4545
"DISPATCH": self.dispatch,
@@ -109,38 +109,71 @@ def record_dynamic_jump_taken(
109109
self.out.emit(";\n")
110110
return True
111111

112-
def deopt_if(
113-
self,
114-
tkn: Token,
115-
tkn_iter: TokenIterator,
116-
uop: CodeSection,
117-
storage: Storage,
118-
inst: Instruction | None,
119-
) -> bool:
120-
self.out.start_line()
121-
self.out.emit("if (")
122-
lparen = next(tkn_iter)
123-
assert lparen.kind == "LPAREN"
124-
first_tkn = tkn_iter.peek()
125-
emit_to(self.out, tkn_iter, "RPAREN")
126-
self.emit(") {\n")
127-
next(tkn_iter) # Semi colon
128-
assert inst is not None
129-
assert inst.family is not None
130-
family_name = inst.family.name
131-
self.emit(f"UPDATE_MISS_STATS({family_name});\n")
132-
self.emit(f"assert(_PyOpcode_Deopt[opcode] == ({family_name}));\n")
133-
self.emit(f"JUMP_TO_PREDICTED(TRACING_{family_name});\n")
134-
self.emit("}\n")
135-
return not always_true(first_tkn)
136-
137-
exit_if = deopt_if
112+
def generate_tier1_tracer_cases(
113+
analysis: Analysis, out: CWriter, emitter: Emitter
114+
) -> None:
115+
out.emit("\n")
116+
for name, inst in sorted(analysis.instructions.items()):
117+
out.emit("\n")
118+
out.emit(f"TRACING_TARGET({name}) {{\n")
119+
out.emit(f"assert(IS_JIT_TRACING());\n")
120+
# We need to ifdef it because this breaks platforms
121+
# without computed gotos/tail calling.
122+
out.emit(f"#if _Py_TAIL_CALL_INTERP\n")
123+
out.emit(f"int opcode = {name};\n")
124+
out.emit(f"(void)(opcode);\n")
125+
out.emit(f"#endif\n")
126+
unused_guard = "(void)this_instr;\n"
127+
if inst.properties.needs_prev:
128+
out.emit(f"_Py_CODEUNIT* const prev_instr = frame->instr_ptr;\n")
129+
if not inst.is_target:
130+
out.emit(f"_Py_CODEUNIT* const this_instr = next_instr;\n")
131+
out.emit(unused_guard)
132+
if not inst.properties.no_save_ip:
133+
out.emit(f"frame->instr_ptr = next_instr;\n")
134+
135+
out.emit(f"next_instr += {inst.size};\n")
136+
out.emit(f"INSTRUCTION_STATS({name});\n")
137+
if inst.is_target:
138+
out.emit(f"PREDICTED_TRACING_{name}:;\n")
139+
out.emit(f"_Py_CODEUNIT* const this_instr = next_instr - {inst.size};\n")
140+
out.emit(unused_guard)
141+
# This is required so that the predicted ops reflect the correct opcode.
142+
out.emit(f"opcode = {name};\n")
143+
out.emit(f"PyCodeObject *old_code = (PyCodeObject *)PyStackRef_AsPyObjectBorrow(frame->f_executable);\n")
144+
out.emit(f"(void)old_code;\n")
145+
out.emit(f"PyFunctionObject *old_func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj);\n")
146+
out.emit(f"(void)old_func;\n")
147+
out.emit(f"int _jump_taken = false;\n")
148+
out.emit(f"(void)_jump_taken;\n")
149+
out.emit(f"int _old_stack_level = !PyStackRef_IsNull(frame->f_executable) ? STACK_LEVEL() : 0;\n")
150+
out.emit(f"(void)(_old_stack_level);\n")
151+
if inst.family is not None:
152+
out.emit(
153+
f"static_assert({inst.family.size} == {inst.size-1}"
154+
', "incorrect cache size");\n'
155+
)
156+
declare_variables(inst, out)
157+
offset = 1 # The instruction itself
158+
stack = Stack()
159+
for part in inst.parts:
160+
# Only emit braces if more than one uop
161+
insert_braces = len([p for p in inst.parts if isinstance(p, Uop)]) > 1
162+
reachable, offset, stack = write_uop(part, emitter, offset, stack, inst, insert_braces)
163+
out.start_line()
164+
if reachable: # type: ignore[possibly-undefined]
165+
stack.flush(out)
166+
out.emit(f"TRACING_DISPATCH();\n")
167+
out.start_line()
168+
out.emit("}")
169+
out.emit("\n")
170+
138171

139172
def generate_tracer_cases(
140173
analysis: Analysis, out: CWriter
141174
) -> None:
142175
out.emit(f"#ifdef _Py_TIER2 /* BEGIN TRACING INSTRUCTIONS */\n")
143-
generate_tier1_cases(analysis, out, TracerEmitter(out, analysis.labels), is_tracing=True)
176+
generate_tier1_tracer_cases(analysis, out, TracerEmitter(out, analysis.labels))
144177
out.emit(f"#endif /* END TRACING INSTRUCTIONS */\n")
145178

146179
def generate_tracer(

0 commit comments

Comments
 (0)