@@ -244,7 +244,61 @@ def assign(self, dst: StackEffect, src: StackEffect):
244244 def cast (self , dst : StackEffect , src : StackEffect ) -> str :
245245 return f"({ dst .type or 'PyObject *' } )" if src .type != dst .type else ""
246246
247- INSTRUCTION_FLAGS = ['HAS_ARG' , 'HAS_CONST' , 'HAS_NAME' , 'HAS_JUMP' , 'IS_UOP' ]
247+ @dataclasses .dataclass
248+ class InstructionFlags :
249+ """Construct and manipulate instruction flags"""
250+
251+ HAS_ARG_FLAG : bool
252+ HAS_CONST_FLAG : bool
253+ HAS_NAME_FLAG : bool
254+ HAS_JUMP_FLAG : bool
255+
256+ def __post_init__ (self ):
257+ self .bitmask = {
258+ name : (1 << i ) for i , name in enumerate (self .names ())
259+ }
260+
261+ @staticmethod
262+ def fromInstruction (instr : "AnyInstruction" ):
263+ return InstructionFlags (
264+ HAS_ARG_FLAG = variable_used (instr , "oparg" ),
265+ HAS_CONST_FLAG = variable_used (instr , "FRAME_CO_CONSTS" ),
266+ HAS_NAME_FLAG = variable_used (instr , "FRAME_CO_NAMES" ),
267+ HAS_JUMP_FLAG = variable_used (instr , "JUMPBY" ),
268+ )
269+
270+ @staticmethod
271+ def newEmpty ():
272+ return InstructionFlags (False , False , False , False )
273+
274+ def add (self , other : "InstructionFlags" ) -> None :
275+ for name , value in dataclasses .asdict (other ).items ():
276+ if value :
277+ setattr (self , name , value )
278+
279+ def names (self , value = None ):
280+ if value is None :
281+ return dataclasses .asdict (self ).keys ()
282+ return [n for n , v in dataclasses .asdict (self ).items () if v == value ]
283+
284+ def bitmap (self ) -> int :
285+ flags = 0
286+ for name in self .names ():
287+ if getattr (self , name ):
288+ flags |= self .bitmask [name ]
289+ return flags
290+
291+ @classmethod
292+ def emit_macros (cls , out : Formatter ):
293+ flags = cls .newEmpty ()
294+ for name , value in flags .bitmask .items ():
295+ out .emit (f"#define { name } ({ value } )" );
296+
297+ for name , value in flags .bitmask .items ():
298+ out .emit (
299+ f"#define OPCODE_{ name [:- len ('_FLAG' )]} (OP) "
300+ f"(_PyOpcode_opcode_metadata[(OP)].flags & ({ name } ))" )
301+
248302
249303FORBIDDEN_INSTRUCTIONS = (
250304 "cframe" ,
@@ -280,8 +334,7 @@ class Instruction:
280334 output_effects : list [StackEffect ]
281335 unmoved_names : frozenset [str ]
282336 instr_fmt : str
283- flags : int
284- flag_data : dict [str , bool ]
337+ instr_flags : InstructionFlags
285338
286339 # Set later
287340 family : parser .Family | None = None
@@ -310,19 +363,10 @@ def __init__(self, inst: parser.InstDef):
310363 else :
311364 break
312365 self .unmoved_names = frozenset (unmoved_names )
313- self .flag_data = {
314- 'HAS_ARG' : variable_used (inst , "oparg" ),
315- 'HAS_CONST' : variable_used (inst , "FRAME_CO_CONSTS" ),
316- 'HAS_NAME' : variable_used (inst , "FRAME_CO_NAMES" ),
317- 'HAS_JUMP' : variable_used (inst , "JUMPBY" ),
318- 'IS_UOP' : self .is_viable_uop (),
319- }
320- assert set (self .flag_data .keys ()) == set (INSTRUCTION_FLAGS )
321- self .flags = 0
322- for i , name in enumerate (INSTRUCTION_FLAGS ):
323- self .flags |= (1 << i ) if self .flag_data [name ] else 0
324366
325- if self .flag_data ['HAS_ARG' ]:
367+ self .instr_flags = InstructionFlags .fromInstruction (inst )
368+
369+ if self .instr_flags .HAS_ARG_FLAG :
326370 fmt = "IB"
327371 else :
328372 fmt = "IX"
@@ -544,7 +588,7 @@ class MacroInstruction:
544588 initial_sp : int
545589 final_sp : int
546590 instr_fmt : str
547- flags : int
591+ instr_flags : InstructionFlags
548592 macro : parser .Macro
549593 parts : list [Component | parser .CacheEffect ]
550594 predicted : bool = False
@@ -557,7 +601,7 @@ class PseudoInstruction:
557601 name : str
558602 targets : list [Instruction ]
559603 instr_fmt : str
560- flags : int
604+ instr_flags : InstructionFlags
561605
562606
563607@dataclasses .dataclass
@@ -567,7 +611,6 @@ class OverriddenInstructionPlaceHolder:
567611
568612AnyInstruction = Instruction | MacroInstruction | PseudoInstruction
569613INSTR_FMT_PREFIX = "INSTR_FMT_"
570- INSTR_FLAG_SUFFIX = "_FLAG"
571614
572615
573616class Analyzer :
@@ -839,7 +882,7 @@ def analyze_macro(self, macro: parser.Macro) -> MacroInstruction:
839882 sp = initial_sp
840883 parts : list [Component | parser .CacheEffect ] = []
841884 format = "IB"
842- flags = 0
885+ flags = InstructionFlags . newEmpty ()
843886 cache = "C"
844887 for component in components :
845888 match component :
@@ -855,7 +898,7 @@ def analyze_macro(self, macro: parser.Macro) -> MacroInstruction:
855898 for _ in range (ce .size ):
856899 format += cache
857900 cache = "0"
858- flags |= instr .flags & 0x0F # Strip out IS_UOP
901+ flags . add ( instr .instr_flags )
859902 case _:
860903 typing .assert_never (component )
861904 final_sp = sp
@@ -869,9 +912,8 @@ def analyze_pseudo(self, pseudo: parser.Pseudo) -> PseudoInstruction:
869912 # Make sure the targets have the same fmt
870913 fmts = list (set ([t .instr_fmt for t in targets ]))
871914 assert (len (fmts ) == 1 )
872- flags_list = list (set ([t .flags for t in targets ]))
873- assert (len (flags_list ) == 1 )
874- return PseudoInstruction (pseudo .name , targets , fmts [0 ], flags_list [0 ])
915+ assert (len (list (set ([t .instr_flags .bitmap () for t in targets ]))) == 1 )
916+ return PseudoInstruction (pseudo .name , targets , fmts [0 ], targets [0 ].instr_flags )
875917
876918 def analyze_instruction (
877919 self , instr : Instruction , stack : list [StackEffect ], sp : int
@@ -1119,13 +1161,8 @@ def write_metadata(self) -> None:
11191161
11201162 # Write type definitions
11211163 self .out .emit (f"enum InstructionFormat {{ { ', ' .join (format_enums )} }};" )
1122- for i , flag in enumerate (INSTRUCTION_FLAGS ):
1123- self .out .emit (f"#define { flag } { INSTR_FLAG_SUFFIX } ({ 1 << i } )" );
1124- for flag in INSTRUCTION_FLAGS :
1125- flag_name = f"{ flag } { INSTR_FLAG_SUFFIX } "
1126- self .out .emit (
1127- f"#define OPCODE_{ flag } (OP) "
1128- f"(_PyOpcode_opcode_metadata[(OP)].flags & ({ flag_name } ))" )
1164+
1165+ InstructionFlags .emit_macros (self .out )
11291166
11301167 self .out .emit ("struct opcode_metadata {" )
11311168 with self .out .indent ():
@@ -1205,25 +1242,28 @@ def write_pseudo_instrs(self) -> None:
12051242 self .out .emit (f" ((OP) == { op } ) || \\ " )
12061243 self .out .emit (f" 0" )
12071244
1208- def emit_metadata_entry (self , name : str , fmt : str , flags : int ) -> None :
1209- flags_strs = [f"{ name } { INSTR_FLAG_SUFFIX } "
1210- for i , name in enumerate (INSTRUCTION_FLAGS ) if (flags & (1 << i ))]
1211- flags_s = "0" if not flags_strs else ' | ' .join (flags_strs )
1245+ def emit_metadata_entry (
1246+ self , name : str , fmt : str , flags : InstructionFlags
1247+ ) -> None :
1248+ flag_names = flags .names (value = True )
1249+ if not flag_names :
1250+ flag_names .append ("0" )
12121251 self .out .emit (
1213- f" [{ name } ] = {{ true, { INSTR_FMT_PREFIX } { fmt } , { flags_s } }},"
1252+ f" [{ name } ] = {{ true, { INSTR_FMT_PREFIX } { fmt } ,"
1253+ f" { ' | ' .join (flag_names )} }},"
12141254 )
12151255
12161256 def write_metadata_for_inst (self , instr : Instruction ) -> None :
12171257 """Write metadata for a single instruction."""
1218- self .emit_metadata_entry (instr .name , instr .instr_fmt , instr .flags )
1258+ self .emit_metadata_entry (instr .name , instr .instr_fmt , instr .instr_flags )
12191259
12201260 def write_metadata_for_macro (self , mac : MacroInstruction ) -> None :
12211261 """Write metadata for a macro-instruction."""
1222- self .emit_metadata_entry (mac .name , mac .instr_fmt , mac .flags )
1262+ self .emit_metadata_entry (mac .name , mac .instr_fmt , mac .instr_flags )
12231263
12241264 def write_metadata_for_pseudo (self , ps : PseudoInstruction ) -> None :
12251265 """Write metadata for a macro-instruction."""
1226- self .emit_metadata_entry (ps .name , ps .instr_fmt , ps .flags )
1266+ self .emit_metadata_entry (ps .name , ps .instr_fmt , ps .instr_flags )
12271267
12281268 def write_instructions (self ) -> None :
12291269 """Write instructions to output file."""
0 commit comments