• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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