2828from typing import TextIO
2929from lexer import Token
3030from 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
3333DEFAULT_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
139172def 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
146179def generate_tracer (
0 commit comments