| """Utilities for writing StencilGroups out to a C header file.""" |
| import typing |
| |
| import _schema |
| import _stencils |
| |
| |
| def _dump_header() -> typing.Iterator[str]: |
| yield "typedef enum {" |
| for kind in typing.get_args(_schema.HoleKind): |
| yield f" HoleKind_{kind}," |
| yield "} HoleKind;" |
| yield "" |
| yield "typedef enum {" |
| for value in _stencils.HoleValue: |
| yield f" HoleValue_{value.name}," |
| yield "} HoleValue;" |
| yield "" |
| yield "typedef struct {" |
| yield " const uint64_t offset;" |
| yield " const HoleKind kind;" |
| yield " const HoleValue value;" |
| yield " const void *symbol;" |
| yield " const uint64_t addend;" |
| yield "} Hole;" |
| yield "" |
| yield "typedef struct {" |
| yield " const size_t body_size;" |
| yield " const unsigned char * const body;" |
| yield " const size_t holes_size;" |
| yield " const Hole * const holes;" |
| yield "} Stencil;" |
| yield "" |
| yield "typedef struct {" |
| yield " const Stencil code;" |
| yield " const Stencil data;" |
| yield "} StencilGroup;" |
| yield "" |
| |
| |
| def _dump_footer(opnames: typing.Iterable[str]) -> typing.Iterator[str]: |
| yield "#define INIT_STENCIL(STENCIL) { \\" |
| yield " .body_size = Py_ARRAY_LENGTH(STENCIL##_body) - 1, \\" |
| yield " .body = STENCIL##_body, \\" |
| yield " .holes_size = Py_ARRAY_LENGTH(STENCIL##_holes) - 1, \\" |
| yield " .holes = STENCIL##_holes, \\" |
| yield "}" |
| yield "" |
| yield "#define INIT_STENCIL_GROUP(OP) { \\" |
| yield " .code = INIT_STENCIL(OP##_code), \\" |
| yield " .data = INIT_STENCIL(OP##_data), \\" |
| yield "}" |
| yield "" |
| yield "static const StencilGroup stencil_groups[512] = {" |
| for opname in opnames: |
| yield f" [{opname}] = INIT_STENCIL_GROUP({opname})," |
| yield "};" |
| yield "" |
| yield "#define GET_PATCHES() { \\" |
| for value in _stencils.HoleValue: |
| yield f" [HoleValue_{value.name}] = (uint64_t)0xBADBADBADBADBADB, \\" |
| yield "}" |
| |
| |
| def _dump_stencil(opname: str, group: _stencils.StencilGroup) -> typing.Iterator[str]: |
| yield f"// {opname}" |
| for part, stencil in [("code", group.code), ("data", group.data)]: |
| for line in stencil.disassembly: |
| yield f"// {line}" |
| if stencil.body: |
| size = len(stencil.body) + 1 |
| yield f"static const unsigned char {opname}_{part}_body[{size}] = {{" |
| for i in range(0, len(stencil.body), 8): |
| row = " ".join(f"{byte:#04x}," for byte in stencil.body[i : i + 8]) |
| yield f" {row}" |
| yield "};" |
| else: |
| yield f"static const unsigned char {opname}_{part}_body[1];" |
| if stencil.holes: |
| size = len(stencil.holes) + 1 |
| yield f"static const Hole {opname}_{part}_holes[{size}] = {{" |
| for hole in stencil.holes: |
| yield f" {hole.as_c()}," |
| yield "};" |
| else: |
| yield f"static const Hole {opname}_{part}_holes[1];" |
| yield "" |
| |
| |
| def dump(groups: dict[str, _stencils.StencilGroup]) -> typing.Iterator[str]: |
| """Yield a JIT compiler line-by-line as a C header file.""" |
| yield from _dump_header() |
| for opname, group in groups.items(): |
| yield from _dump_stencil(opname, group) |
| yield from _dump_footer(groups) |