| 
									
										
										
										
											2024-01-28 18:48:48 -08:00
										 |  |  | """Utilities for writing StencilGroups out to a C header file.""" | 
					
						
							| 
									
										
										
										
											2024-05-01 14:35:49 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-03 16:41:07 -07:00
										 |  |  | import itertools | 
					
						
							| 
									
										
										
										
											2024-01-28 18:48:48 -08:00
										 |  |  | import typing | 
					
						
							| 
									
										
										
										
											2024-10-02 20:07:20 +01:00
										 |  |  | import math | 
					
						
							| 
									
										
										
										
											2024-01-28 18:48:48 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import _stencils | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-02 20:07:20 +01:00
										 |  |  | def _dump_footer( | 
					
						
							|  |  |  |     groups: dict[str, _stencils.StencilGroup], symbols: dict[str, int] | 
					
						
							|  |  |  | ) -> typing.Iterator[str]: | 
					
						
							|  |  |  |     symbol_mask_size = max(math.ceil(len(symbols) / 32), 1) | 
					
						
							|  |  |  |     yield f'static_assert(SYMBOL_MASK_WORDS >= {symbol_mask_size}, "SYMBOL_MASK_WORDS too small");' | 
					
						
							|  |  |  |     yield "" | 
					
						
							| 
									
										
										
										
											2024-01-28 18:48:48 -08:00
										 |  |  |     yield "typedef struct {" | 
					
						
							| 
									
										
										
										
											2024-05-03 16:41:07 -07:00
										 |  |  |     yield "    void (*emit)(" | 
					
						
							|  |  |  |     yield "        unsigned char *code, unsigned char *data, _PyExecutorObject *executor," | 
					
						
							| 
									
										
										
										
											2024-10-02 20:07:20 +01:00
										 |  |  |     yield "        const _PyUOpInstruction *instruction, jit_state *state);" | 
					
						
							| 
									
										
										
										
											2024-05-03 16:41:07 -07:00
										 |  |  |     yield "    size_t code_size;" | 
					
						
							|  |  |  |     yield "    size_t data_size;" | 
					
						
							| 
									
										
										
										
											2024-10-02 20:07:20 +01:00
										 |  |  |     yield "    symbol_mask trampoline_mask;" | 
					
						
							| 
									
										
										
										
											2024-01-28 18:48:48 -08:00
										 |  |  |     yield "} StencilGroup;" | 
					
						
							|  |  |  |     yield "" | 
					
						
							| 
									
										
										
										
											2024-05-03 16:41:07 -07:00
										 |  |  |     yield f"static const StencilGroup trampoline = {groups['trampoline'].as_c('trampoline')};" | 
					
						
							| 
									
										
										
										
											2024-01-28 18:48:48 -08:00
										 |  |  |     yield "" | 
					
						
							| 
									
										
										
										
											2024-05-03 16:41:07 -07:00
										 |  |  |     yield "static const StencilGroup stencil_groups[MAX_UOP_ID + 1] = {" | 
					
						
							|  |  |  |     for opname, group in sorted(groups.items()): | 
					
						
							| 
									
										
										
										
											2024-05-01 08:05:53 -07:00
										 |  |  |         if opname == "trampoline": | 
					
						
							|  |  |  |             continue | 
					
						
							| 
									
										
										
										
											2024-05-03 16:41:07 -07:00
										 |  |  |         yield f"    [{opname}] = {group.as_c(opname)}," | 
					
						
							| 
									
										
										
										
											2024-01-28 18:48:48 -08:00
										 |  |  |     yield "};" | 
					
						
							| 
									
										
										
										
											2024-10-02 20:07:20 +01:00
										 |  |  |     yield "" | 
					
						
							|  |  |  |     yield f"static const void * const symbols_map[{max(len(symbols), 1)}] = {{" | 
					
						
							| 
									
										
										
										
											2024-10-18 15:51:29 -04:00
										 |  |  |     if symbols: | 
					
						
							|  |  |  |         for symbol, ordinal in symbols.items(): | 
					
						
							|  |  |  |             yield f"    [{ordinal}] = &{symbol}," | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         yield "    0" | 
					
						
							| 
									
										
										
										
											2024-10-02 20:07:20 +01:00
										 |  |  |     yield "};" | 
					
						
							| 
									
										
										
										
											2024-01-28 18:48:48 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _dump_stencil(opname: str, group: _stencils.StencilGroup) -> typing.Iterator[str]: | 
					
						
							| 
									
										
										
										
											2024-05-03 16:41:07 -07:00
										 |  |  |     yield "void" | 
					
						
							|  |  |  |     yield f"emit_{opname}(" | 
					
						
							|  |  |  |     yield "    unsigned char *code, unsigned char *data, _PyExecutorObject *executor," | 
					
						
							| 
									
										
										
										
											2024-10-02 20:07:20 +01:00
										 |  |  |     yield "    const _PyUOpInstruction *instruction, jit_state *state)" | 
					
						
							| 
									
										
										
										
											2024-05-03 16:41:07 -07:00
										 |  |  |     yield "{" | 
					
						
							| 
									
										
										
										
											2024-01-28 18:48:48 -08:00
										 |  |  |     for part, stencil in [("code", group.code), ("data", group.data)]: | 
					
						
							|  |  |  |         for line in stencil.disassembly: | 
					
						
							| 
									
										
										
										
											2024-05-03 16:41:07 -07:00
										 |  |  |             yield f"    // {line}" | 
					
						
							| 
									
										
										
										
											2024-01-28 18:48:48 -08:00
										 |  |  |         if stencil.body: | 
					
						
							| 
									
										
										
										
											2024-05-03 16:41:07 -07:00
										 |  |  |             yield f"    const unsigned char {part}_body[{len(stencil.body)}] = {{" | 
					
						
							| 
									
										
										
										
											2024-01-28 18:48:48 -08:00
										 |  |  |             for i in range(0, len(stencil.body), 8): | 
					
						
							|  |  |  |                 row = " ".join(f"{byte:#04x}," for byte in stencil.body[i : i + 8]) | 
					
						
							| 
									
										
										
										
											2024-05-03 16:41:07 -07:00
										 |  |  |                 yield f"        {row}" | 
					
						
							|  |  |  |             yield "    };" | 
					
						
							|  |  |  |     # Data is written first (so relaxations in the code work properly): | 
					
						
							|  |  |  |     for part, stencil in [("data", group.data), ("code", group.code)]: | 
					
						
							|  |  |  |         if stencil.body: | 
					
						
							|  |  |  |             yield f"    memcpy({part}, {part}_body, sizeof({part}_body));" | 
					
						
							|  |  |  |         skip = False | 
					
						
							|  |  |  |         stencil.holes.sort(key=lambda hole: hole.offset) | 
					
						
							|  |  |  |         for hole, pair in itertools.zip_longest(stencil.holes, stencil.holes[1:]): | 
					
						
							|  |  |  |             if skip: | 
					
						
							|  |  |  |                 skip = False | 
					
						
							|  |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2024-10-30 12:03:31 -07:00
										 |  |  |             if pair and (folded := hole.fold(pair, stencil.body)): | 
					
						
							| 
									
										
										
										
											2024-05-03 16:41:07 -07:00
										 |  |  |                 skip = True | 
					
						
							|  |  |  |                 hole = folded | 
					
						
							|  |  |  |             yield f"    {hole.as_c(part)}" | 
					
						
							|  |  |  |     yield "}" | 
					
						
							| 
									
										
										
										
											2024-01-28 18:48:48 -08:00
										 |  |  |     yield "" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-02 20:07:20 +01:00
										 |  |  | def dump( | 
					
						
							|  |  |  |     groups: dict[str, _stencils.StencilGroup], symbols: dict[str, int] | 
					
						
							|  |  |  | ) -> typing.Iterator[str]: | 
					
						
							| 
									
										
										
										
											2024-01-28 18:48:48 -08:00
										 |  |  |     """Yield a JIT compiler line-by-line as a C header file.""" | 
					
						
							| 
									
										
										
										
											2024-05-03 16:41:07 -07:00
										 |  |  |     for opname, group in sorted(groups.items()): | 
					
						
							| 
									
										
										
										
											2024-01-28 18:48:48 -08:00
										 |  |  |         yield from _dump_stencil(opname, group) | 
					
						
							| 
									
										
										
										
											2024-10-02 20:07:20 +01:00
										 |  |  |     yield from _dump_footer(groups, symbols) |