|
28 | 28 | # Must match MAX_RECORDED_VALUES in Include/internal/pycore_optimizer.h. |
29 | 29 | MAX_RECORDED_VALUES = 3 |
30 | 30 |
|
| 31 | +# Map `_RECORD_*` uops to the helper that converts a raw family-recorded |
| 32 | +# value to the form the specialized member consumes. |
| 33 | +_RECORD_TRANSFORM_HELPERS: dict[str, str] = { |
| 34 | + "_RECORD_TOS_TYPE": "record_trace_transform_to_type", |
| 35 | + "_RECORD_NOS_TYPE": "record_trace_transform_to_type", |
| 36 | + "_RECORD_NOS_GEN_FUNC": "record_trace_transform_gen_func", |
| 37 | + "_RECORD_3OS_GEN_FUNC": "record_trace_transform_gen_func", |
| 38 | + "_RECORD_BOUND_METHOD": "record_trace_transform_bound_method", |
| 39 | +} |
| 40 | + |
31 | 41 |
|
32 | 42 | class RecorderEmitter(Emitter): |
33 | 43 | def __init__(self, out: CWriter): |
@@ -119,11 +129,14 @@ def generate_recorder_tables(analysis: Analysis, out: CWriter) -> None: |
119 | 129 | record_function_indexes: dict[str, int] = dict() |
120 | 130 | record_table: dict[str, list[str]] = {} |
121 | 131 | record_consumer_table: dict[str, tuple[list[int], bool]] = {} |
122 | | - record_slot_keys = { |
123 | | - name: get_record_slot_kind(name) |
| 132 | + record_uop_names = { |
| 133 | + name |
124 | 134 | for name, uop in analysis.uops.items() |
125 | 135 | if uop.properties.records_value |
126 | 136 | } |
| 137 | + record_slot_keys = { |
| 138 | + name: get_record_slot_kind(name) for name in record_uop_names |
| 139 | + } |
127 | 140 | index = 1 |
128 | 141 | for inst in analysis.instructions.values(): |
129 | 142 | source_inst = inst |
@@ -187,6 +200,38 @@ def generate_recorder_tables(analysis: Analysis, out: CWriter) -> None: |
187 | 200 | for name in record_function_indexes: |
188 | 201 | out.emit(f" [{name}_INDEX] = _PyOpcode_RecordFunction{name[7:]},\n") |
189 | 202 | out.emit("};\n") |
| 203 | + generate_record_transform_dispatcher(record_uop_names, out) |
| 204 | + |
| 205 | + |
| 206 | +def generate_record_transform_dispatcher( |
| 207 | + record_uop_names: set[str], out: CWriter |
| 208 | +) -> None: |
| 209 | + """Emit a switch that converts a family-recorded value for a recorder uop. |
| 210 | +
|
| 211 | + Only `_RECORD_*` uops that need conversion get a case; the default |
| 212 | + returns the input value unchanged. Helpers live in Python/optimizer.c. |
| 213 | + """ |
| 214 | + cases: dict[str, list[str]] = {} |
| 215 | + for record_name in record_uop_names: |
| 216 | + helper = _RECORD_TRANSFORM_HELPERS.get(record_name) |
| 217 | + if helper is None: |
| 218 | + continue |
| 219 | + cases.setdefault(helper, []).append(record_name) |
| 220 | + out.emit("\n") |
| 221 | + out.emit( |
| 222 | + "PyObject *\n" |
| 223 | + "_PyOpcode_RecordTransformValue(int uop, PyObject *value)\n" |
| 224 | + "{\n" |
| 225 | + ) |
| 226 | + out.emit(" switch (uop) {\n") |
| 227 | + for helper, names in cases.items(): |
| 228 | + for name in names: |
| 229 | + out.emit(f" case {name}:\n") |
| 230 | + out.emit(f" return {helper}(value);\n") |
| 231 | + out.emit(" default:\n") |
| 232 | + out.emit(" return value;\n") |
| 233 | + out.emit(" }\n") |
| 234 | + out.emit("}\n") |
190 | 235 |
|
191 | 236 |
|
192 | 237 | arg_parser = argparse.ArgumentParser( |
|
0 commit comments