@@ -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."""