1"""Generate uop metadata. 2Reads the instruction definitions from bytecodes.c. 3Writes the metadata to pycore_uop_metadata.h by default. 4""" 5 6import argparse 7 8from analyzer import ( 9 Analysis, 10 analyze_files, 11) 12from generators_common import ( 13 DEFAULT_INPUT, 14 ROOT, 15 write_header, 16 cflags, 17) 18from stack import Stack 19from cwriter import CWriter 20from typing import TextIO 21 22DEFAULT_OUTPUT = ROOT / "Include/internal/pycore_uop_metadata.h" 23 24 25def generate_names_and_flags(analysis: Analysis, out: CWriter) -> None: 26 out.emit("extern const uint16_t _PyUop_Flags[MAX_UOP_ID+1];\n") 27 out.emit("extern const uint8_t _PyUop_Replication[MAX_UOP_ID+1];\n") 28 out.emit("extern const char * const _PyOpcode_uop_name[MAX_UOP_ID+1];\n\n") 29 out.emit("extern int _PyUop_num_popped(int opcode, int oparg);\n\n") 30 out.emit("#ifdef NEED_OPCODE_METADATA\n") 31 out.emit("const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = {\n") 32 for uop in analysis.uops.values(): 33 if uop.is_viable() and uop.properties.tier != 1: 34 out.emit(f"[{uop.name}] = {cflags(uop.properties)},\n") 35 36 out.emit("};\n\n") 37 out.emit("const uint8_t _PyUop_Replication[MAX_UOP_ID+1] = {\n") 38 for uop in analysis.uops.values(): 39 if uop.replicated: 40 out.emit(f"[{uop.name}] = {uop.replicated},\n") 41 42 out.emit("};\n\n") 43 out.emit("const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = {\n") 44 for uop in sorted(analysis.uops.values(), key=lambda t: t.name): 45 if uop.is_viable() and uop.properties.tier != 1: 46 out.emit(f'[{uop.name}] = "{uop.name}",\n') 47 out.emit("};\n") 48 out.emit("int _PyUop_num_popped(int opcode, int oparg)\n{\n") 49 out.emit("switch(opcode) {\n") 50 for uop in analysis.uops.values(): 51 if uop.is_viable() and uop.properties.tier != 1: 52 stack = Stack() 53 for var in reversed(uop.stack.inputs): 54 stack.pop(var) 55 popped = (-stack.base_offset).to_c() 56 out.emit(f"case {uop.name}:\n") 57 out.emit(f" return {popped};\n") 58 out.emit("default:\n") 59 out.emit(" return -1;\n") 60 out.emit("}\n") 61 out.emit("}\n\n") 62 out.emit("#endif // NEED_OPCODE_METADATA\n\n") 63 64 65def generate_uop_metadata( 66 filenames: list[str], analysis: Analysis, outfile: TextIO 67) -> None: 68 write_header(__file__, filenames, outfile) 69 out = CWriter(outfile, 0, False) 70 with out.header_guard("Py_CORE_UOP_METADATA_H"): 71 out.emit("#include <stdint.h>\n") 72 out.emit('#include "pycore_uop_ids.h"\n') 73 generate_names_and_flags(analysis, out) 74 75 76arg_parser = argparse.ArgumentParser( 77 description="Generate the header file with uop metadata.", 78 formatter_class=argparse.ArgumentDefaultsHelpFormatter, 79) 80 81arg_parser.add_argument( 82 "-o", "--output", type=str, help="Generated code", default=DEFAULT_OUTPUT 83) 84 85arg_parser.add_argument( 86 "input", nargs=argparse.REMAINDER, help="Instruction definition file(s)" 87) 88 89if __name__ == "__main__": 90 args = arg_parser.parse_args() 91 if len(args.input) == 0: 92 args.input.append(DEFAULT_INPUT) 93 data = analyze_files(args.input) 94 with open(args.output, "w") as outfile: 95 generate_uop_metadata(args.input, data, outfile) 96