@@ -109,6 +109,7 @@ class Instruction:
109109
110110 # Parts of the underlying instruction definition
111111 inst : parser .InstDef
112+ register : bool
112113 kind : typing .Literal ["inst" , "op" ]
113114 name : str
114115 block : parser .Block
@@ -121,13 +122,16 @@ class Instruction:
121122 cache_effects : list [parser .CacheEffect ]
122123 input_effects : list [StackEffect ]
123124 output_effects : list [StackEffect ]
125+ input_registers : list [str ] # Parallel to input_effects
126+ output_registers : list [str ] # Etc.
124127
125128 # Set later
126129 family : parser .Family | None = None
127130 predicted : bool = False
128131
129132 def __init__ (self , inst : parser .InstDef ):
130133 self .inst = inst
134+ self .register = inst .register
131135 self .kind = inst .kind
132136 self .name = inst .name
133137 self .block = inst .block
@@ -142,6 +146,14 @@ def __init__(self, inst: parser.InstDef):
142146 ]
143147 self .output_effects = inst .outputs # For consistency/completeness
144148
149+ def analyze_registers (self , a : "Analyzer" ) -> None :
150+ regs = iter (("REG(oparg)" , "REG(oparg2)" , "REG(oparg3)" ))
151+ try :
152+ self .input_registers = [next (regs ) for _ in self .input_effects ]
153+ self .output_registers = [next (regs ) for _ in self .output_effects ]
154+ except StopIteration : # Running out of registers
155+ a .error (f"Instruction { self .name } has too many register effects" )
156+
145157 def write (self , out : Formatter ) -> None :
146158 """Write one instruction, sans prologue and epilogue."""
147159 # Write a static assertion that a family's cache size is correct
@@ -153,10 +165,16 @@ def write(self, out: Formatter) -> None:
153165 f'{ self .cache_offset } , "incorrect cache size");'
154166 )
155167
156- # Write input stack effect variable declarations and initializations
157- for i , ieffect in enumerate (reversed (self .input_effects ), 1 ):
158- src = StackEffect (f"PEEK({ i } )" , "" )
159- out .declare (ieffect , src )
168+ if not self .register :
169+ # Write input stack effect variable declarations and initializations
170+ for i , ieffect in enumerate (reversed (self .input_effects ), 1 ):
171+ src = StackEffect (f"PEEK({ i } )" , "" )
172+ out .declare (ieffect , src )
173+ else :
174+ # Write input register variable declarations and initializations
175+ for ieffect , reg in zip (self .input_effects , self .input_registers ):
176+ src = StackEffect (reg , "" )
177+ out .declare (ieffect , src )
160178
161179 # Write output stack effect variable declarations
162180 input_names = {ieffect .name for ieffect in self .input_effects }
@@ -170,18 +188,24 @@ def write(self, out: Formatter) -> None:
170188 if self .always_exits :
171189 return
172190
173- # Write net stack growth/shrinkage
174- diff = len (self .output_effects ) - len (self .input_effects )
175- out .stack_adjust (diff )
176-
177- # Write output stack effect assignments
178- unmoved_names : set [str ] = set ()
179- for ieffect , oeffect in zip (self .input_effects , self .output_effects ):
180- if ieffect .name == oeffect .name :
181- unmoved_names .add (ieffect .name )
182- for i , oeffect in enumerate (reversed (self .output_effects ), 1 ):
183- if oeffect .name not in unmoved_names :
184- dst = StackEffect (f"PEEK({ i } )" , "" )
191+ if not self .register :
192+ # Write net stack growth/shrinkage
193+ diff = len (self .output_effects ) - len (self .input_effects )
194+ out .stack_adjust (diff )
195+
196+ # Write output stack effect assignments
197+ unmoved_names : set [str ] = set ()
198+ for ieffect , oeffect in zip (self .input_effects , self .output_effects ):
199+ if ieffect .name == oeffect .name :
200+ unmoved_names .add (ieffect .name )
201+ for i , oeffect in enumerate (reversed (self .output_effects ), 1 ):
202+ if oeffect .name not in unmoved_names :
203+ dst = StackEffect (f"PEEK({ i } )" , "" )
204+ out .assign (dst , oeffect )
205+ else :
206+ # Write output register assignments
207+ for oeffect , reg in zip (self .output_effects , self .output_registers ):
208+ dst = StackEffect (reg , "" )
185209 out .assign (dst , oeffect )
186210
187211 # Write cache effect
@@ -233,9 +257,10 @@ def write_body(self, out: Formatter, dedent: int, cache_adjust: int = 0) -> None
233257 else :
234258 out .write_raw (f"{ extra } { space } if ({ cond } ) goto { label } ;\n " )
235259 elif m := re .match (r"(\s*)DECREF_INPUTS\(\);\s*$" , line ):
236- space = m .group (1 )
237- for ieff in self .input_effects :
238- out .write_raw (f"{ extra } { space } Py_DECREF({ ieff .name } );\n " )
260+ if not self .register :
261+ space = m .group (1 )
262+ for ieff in self .input_effects :
263+ out .write_raw (f"{ extra } { space } Py_DECREF({ ieff .name } );\n " )
239264 else :
240265 out .write_raw (extra + line )
241266
@@ -387,6 +412,7 @@ def analyze(self) -> None:
387412 self .find_predictions ()
388413 self .map_families ()
389414 self .check_families ()
415+ self .analyze_register_instrs ()
390416 self .analyze_supers_and_macros ()
391417
392418 def find_predictions (self ) -> None :
@@ -453,6 +479,11 @@ def check_families(self) -> None:
453479 family ,
454480 )
455481
482+ def analyze_register_instrs (self ) -> None :
483+ for instr in self .instrs .values ():
484+ if instr .register :
485+ instr .analyze_registers (self )
486+
456487 def analyze_supers_and_macros (self ) -> None :
457488 """Analyze each super- and macro instruction."""
458489 self .super_instrs = {}
0 commit comments