@@ -234,7 +234,61 @@ def assign(self, dst: StackEffect, src: StackEffect):
234
234
def cast (self , dst : StackEffect , src : StackEffect ) -> str :
235
235
return f"({ dst .type or 'PyObject *' } )" if src .type != dst .type else ""
236
236
237
- INSTRUCTION_FLAGS = ['HAS_ARG' , 'HAS_CONST' , 'HAS_NAME' , 'HAS_JUMP' ]
237
+ @dataclasses .dataclass
238
+ class InstructionFlags :
239
+ """Construct and manipulate instruction flags"""
240
+
241
+ HAS_ARG_FLAG : bool
242
+ HAS_CONST_FLAG : bool
243
+ HAS_NAME_FLAG : bool
244
+ HAS_JUMP_FLAG : bool
245
+
246
+ def __post_init__ (self ):
247
+ self .bitmask = {
248
+ name : (1 << i ) for i , name in enumerate (self .names ())
249
+ }
250
+
251
+ @staticmethod
252
+ def fromInstruction (instr : "AnyInstruction" ):
253
+ return InstructionFlags (
254
+ HAS_ARG_FLAG = variable_used (instr , "oparg" ),
255
+ HAS_CONST_FLAG = variable_used (instr , "FRAME_CO_CONSTS" ),
256
+ HAS_NAME_FLAG = variable_used (instr , "FRAME_CO_NAMES" ),
257
+ HAS_JUMP_FLAG = variable_used (instr , "JUMPBY" ),
258
+ )
259
+
260
+ @staticmethod
261
+ def newEmpty ():
262
+ return InstructionFlags (False , False , False , False )
263
+
264
+ def add (self , other : "InstructionFlags" ) -> None :
265
+ for name , value in dataclasses .asdict (other ).items ():
266
+ if value :
267
+ setattr (self , name , value )
268
+
269
+ def names (self , value = None ):
270
+ if value is None :
271
+ return dataclasses .asdict (self ).keys ()
272
+ return [n for n , v in dataclasses .asdict (self ).items () if v == value ]
273
+
274
+ def bitmap (self ) -> int :
275
+ flags = 0
276
+ for name in self .names ():
277
+ if getattr (self , name ):
278
+ flags |= self .bitmask [name ]
279
+ return flags
280
+
281
+ @classmethod
282
+ def emit_macros (cls , out : Formatter ):
283
+ flags = cls .newEmpty ()
284
+ for name , value in flags .bitmask .items ():
285
+ out .emit (f"#define { name } ({ value } )" );
286
+
287
+ for name , value in flags .bitmask .items ():
288
+ out .emit (
289
+ f"#define OPCODE_{ name [:- len ('_FLAG' )]} (OP) "
290
+ f"(_PyOpcode_opcode_metadata[(OP)].flags & ({ name } ))" )
291
+
238
292
239
293
@dataclasses .dataclass
240
294
class Instruction :
@@ -256,7 +310,7 @@ class Instruction:
256
310
output_effects : list [StackEffect ]
257
311
unmoved_names : frozenset [str ]
258
312
instr_fmt : str
259
- flags : int
313
+ instr_flags : InstructionFlags
260
314
261
315
# Set later
262
316
family : parser .Family | None = None
@@ -285,18 +339,10 @@ def __init__(self, inst: parser.InstDef):
285
339
else :
286
340
break
287
341
self .unmoved_names = frozenset (unmoved_names )
288
- flag_data = {
289
- 'HAS_ARG' : variable_used (inst , "oparg" ),
290
- 'HAS_CONST' : variable_used (inst , "FRAME_CO_CONSTS" ),
291
- 'HAS_NAME' : variable_used (inst , "FRAME_CO_NAMES" ),
292
- 'HAS_JUMP' : variable_used (inst , "JUMPBY" ),
293
- }
294
- assert set (flag_data .keys ()) == set (INSTRUCTION_FLAGS )
295
- self .flags = 0
296
- for i , name in enumerate (INSTRUCTION_FLAGS ):
297
- self .flags |= (1 << i ) if flag_data [name ] else 0
298
342
299
- if flag_data ['HAS_ARG' ]:
343
+ self .instr_flags = InstructionFlags .fromInstruction (inst )
344
+
345
+ if self .instr_flags .HAS_ARG_FLAG :
300
346
fmt = "IB"
301
347
else :
302
348
fmt = "IX"
@@ -495,7 +541,7 @@ class MacroInstruction:
495
541
initial_sp : int
496
542
final_sp : int
497
543
instr_fmt : str
498
- flags : int
544
+ instr_flags : InstructionFlags
499
545
macro : parser .Macro
500
546
parts : list [Component | parser .CacheEffect ]
501
547
predicted : bool = False
@@ -508,7 +554,7 @@ class PseudoInstruction:
508
554
name : str
509
555
targets : list [Instruction ]
510
556
instr_fmt : str
511
- flags : int
557
+ instr_flags : InstructionFlags
512
558
513
559
514
560
@dataclasses .dataclass
@@ -518,7 +564,6 @@ class OverriddenInstructionPlaceHolder:
518
564
519
565
AnyInstruction = Instruction | MacroInstruction | PseudoInstruction
520
566
INSTR_FMT_PREFIX = "INSTR_FMT_"
521
- INSTR_FLAG_SUFFIX = "_FLAG"
522
567
523
568
524
569
class Analyzer :
@@ -787,7 +832,7 @@ def analyze_macro(self, macro: parser.Macro) -> MacroInstruction:
787
832
sp = initial_sp
788
833
parts : list [Component | parser .CacheEffect ] = []
789
834
format = "IB"
790
- flags = 0
835
+ flags = InstructionFlags . newEmpty ()
791
836
cache = "C"
792
837
for component in components :
793
838
match component :
@@ -803,7 +848,7 @@ def analyze_macro(self, macro: parser.Macro) -> MacroInstruction:
803
848
for _ in range (ce .size ):
804
849
format += cache
805
850
cache = "0"
806
- flags |= instr .flags
851
+ flags . add ( instr .instr_flags )
807
852
case _:
808
853
typing .assert_never (component )
809
854
final_sp = sp
@@ -817,9 +862,8 @@ def analyze_pseudo(self, pseudo: parser.Pseudo) -> PseudoInstruction:
817
862
# Make sure the targets have the same fmt
818
863
fmts = list (set ([t .instr_fmt for t in targets ]))
819
864
assert (len (fmts ) == 1 )
820
- flags_list = list (set ([t .flags for t in targets ]))
821
- assert (len (flags_list ) == 1 )
822
- return PseudoInstruction (pseudo .name , targets , fmts [0 ], flags_list [0 ])
865
+ assert (len (list (set ([t .instr_flags .bitmap () for t in targets ]))) == 1 )
866
+ return PseudoInstruction (pseudo .name , targets , fmts [0 ], targets [0 ].instr_flags )
823
867
824
868
def analyze_instruction (
825
869
self , instr : Instruction , stack : list [StackEffect ], sp : int
@@ -1067,13 +1111,8 @@ def write_metadata(self) -> None:
1067
1111
1068
1112
# Write type definitions
1069
1113
self .out .emit (f"enum InstructionFormat {{ { ', ' .join (format_enums )} }};" )
1070
- for i , flag in enumerate (INSTRUCTION_FLAGS ):
1071
- self .out .emit (f"#define { flag } { INSTR_FLAG_SUFFIX } ({ 1 << i } )" );
1072
- for flag in INSTRUCTION_FLAGS :
1073
- flag_name = f"{ flag } { INSTR_FLAG_SUFFIX } "
1074
- self .out .emit (
1075
- f"#define OPCODE_{ flag } (OP) "
1076
- f"(_PyOpcode_opcode_metadata[(OP)].flags & ({ flag_name } ))" )
1114
+
1115
+ InstructionFlags .emit_macros (self .out )
1077
1116
1078
1117
self .out .emit ("struct opcode_metadata {" )
1079
1118
with self .out .indent ():
@@ -1153,25 +1192,28 @@ def write_pseudo_instrs(self) -> None:
1153
1192
self .out .emit (f" ((OP) == { op } ) || \\ " )
1154
1193
self .out .emit (f" 0" )
1155
1194
1156
- def emit_metadata_entry (self , name : str , fmt : str , flags : int ) -> None :
1157
- flags_strs = [f"{ name } { INSTR_FLAG_SUFFIX } "
1158
- for i , name in enumerate (INSTRUCTION_FLAGS ) if (flags & (1 << i ))]
1159
- flags_s = "0" if not flags_strs else ' | ' .join (flags_strs )
1195
+ def emit_metadata_entry (
1196
+ self , name : str , fmt : str , flags : InstructionFlags
1197
+ ) -> None :
1198
+ flag_names = flags .names (value = True )
1199
+ if not flag_names :
1200
+ flag_names .append ("0" )
1160
1201
self .out .emit (
1161
- f" [{ name } ] = {{ true, { INSTR_FMT_PREFIX } { fmt } , { flags_s } }},"
1202
+ f" [{ name } ] = {{ true, { INSTR_FMT_PREFIX } { fmt } ,"
1203
+ f" { ' | ' .join (flag_names )} }},"
1162
1204
)
1163
1205
1164
1206
def write_metadata_for_inst (self , instr : Instruction ) -> None :
1165
1207
"""Write metadata for a single instruction."""
1166
- self .emit_metadata_entry (instr .name , instr .instr_fmt , instr .flags )
1208
+ self .emit_metadata_entry (instr .name , instr .instr_fmt , instr .instr_flags )
1167
1209
1168
1210
def write_metadata_for_macro (self , mac : MacroInstruction ) -> None :
1169
1211
"""Write metadata for a macro-instruction."""
1170
- self .emit_metadata_entry (mac .name , mac .instr_fmt , mac .flags )
1212
+ self .emit_metadata_entry (mac .name , mac .instr_fmt , mac .instr_flags )
1171
1213
1172
1214
def write_metadata_for_pseudo (self , ps : PseudoInstruction ) -> None :
1173
1215
"""Write metadata for a macro-instruction."""
1174
- self .emit_metadata_entry (ps .name , ps .instr_fmt , ps .flags )
1216
+ self .emit_metadata_entry (ps .name , ps .instr_fmt , ps .instr_flags )
1175
1217
1176
1218
def write_instructions (self ) -> None :
1177
1219
"""Write instructions to output file."""
0 commit comments