Skip to content

Commit c207ecf

Browse files
committed
Give uop_execute an instruction decoding loop
1 parent b4d1545 commit c207ecf

File tree

1 file changed

+71
-21
lines changed

1 file changed

+71
-21
lines changed

Python/optimizer.c

Lines changed: 71 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -283,11 +283,16 @@ PyUnstable_Optimizer_NewCounter(void)
283283

284284
typedef struct {
285285
_PyOptimizerObject base;
286+
int traces_executed;
286287
int instrs_executed;
287288
} UOpOptimizerObject;
288289

289290
const int MAX_TRACE_LENGTH = 16;
290291

292+
// UOp opcodes are outside the range of bytecodes or pseudo ops
293+
const int EXIT_TRACE = 512;
294+
const int SET_IP = 513;
295+
291296
typedef struct {
292297
int opcode;
293298
int oparg;
@@ -297,8 +302,6 @@ typedef struct {
297302
_PyExecutorObject executor; // Base
298303
UOpOptimizerObject *optimizer;
299304
uop_instruction trace[MAX_TRACE_LENGTH]; // TODO: variable length
300-
// TODO: drop the rest
301-
_Py_CODEUNIT *next_instr; // The instruction after the trace
302305
} UOpExecutorObject;
303306

304307
static void
@@ -320,25 +323,60 @@ static _PyInterpreterFrame *
320323
uop_execute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject **stack_pointer)
321324
{
322325
UOpExecutorObject *self = (UOpExecutorObject *)executor;
323-
assert(self->trace[0].opcode == LOAD_FAST);
324-
int oparg = self->trace[0].oparg;
325-
fprintf(stderr, "LOAD_FAST %d\n", oparg);
326-
self->optimizer->instrs_executed++;
327-
PyObject *value = frame->localsplus[oparg];
328-
assert(value != 0);
329-
Py_INCREF(value);
330-
*stack_pointer++ = value;
331-
_PyFrame_SetStackPointer(frame, stack_pointer);
332-
frame->prev_instr = self->next_instr - 1;
333-
Py_DECREF(self);
334-
return frame;
326+
self->optimizer->traces_executed++;
327+
_Py_CODEUNIT *ip_offset = (_Py_CODEUNIT *)_PyFrame_GetCode(frame)->co_code_adaptive - 1;
328+
int pc = 0;
329+
for (;;) {
330+
int opcode = self->trace[pc].opcode;
331+
int oparg = self->trace[pc].oparg;
332+
pc++;
333+
self->optimizer->instrs_executed++;
334+
switch (opcode) {
335+
// TODO: Tools/cases_generator should generate these from Python/bytecodes.c
336+
case LOAD_FAST:
337+
{
338+
fprintf(stderr, "LOAD_FAST %d\n", oparg);
339+
PyObject *value = frame->localsplus[oparg];
340+
assert(value != 0);
341+
Py_INCREF(value);
342+
*stack_pointer++ = value;
343+
break;
344+
}
345+
case SET_IP:
346+
{
347+
fprintf(stderr, "SET_IP %d\n", oparg);
348+
frame->prev_instr = ip_offset + oparg;
349+
break;
350+
}
351+
case EXIT_TRACE:
352+
{
353+
fprintf(stderr, "EXIT_TRACE\n");
354+
_PyFrame_SetStackPointer(frame, stack_pointer);
355+
Py_DECREF(self);
356+
return frame;
357+
}
358+
default:
359+
{
360+
fprintf(stderr, "Unknown uop %d, oparg %d\n", opcode, oparg);
361+
Py_FatalError("Unknown uop");
362+
abort(); // Unreachable
363+
for (;;) {}
364+
// Really unreachable
365+
}
366+
}
367+
}
335368
}
336369

337370
static int
338-
translate_bytecode_to_trace(_Py_CODEUNIT *instr, uop_instruction *trace, int max_length)
371+
translate_bytecode_to_trace(
372+
PyCodeObject *code,
373+
_Py_CODEUNIT *instr,
374+
uop_instruction *trace,
375+
int max_length)
339376
{
377+
assert(max_length >= 3); // One op, one SET_IP, one END_TRACE
340378
int trace_length = 0;
341-
while (trace_length < max_length) {
379+
while (trace_length + 2 < max_length) {
342380
if (trace_length >= 1) {
343381
break; // Temporarily, only handle one instruction
344382
}
@@ -350,7 +388,12 @@ translate_bytecode_to_trace(_Py_CODEUNIT *instr, uop_instruction *trace, int max
350388
instr++;
351389
trace_length++;
352390
}
353-
return trace_length;
391+
int ip_offset = instr - (_Py_CODEUNIT *)code->co_code_adaptive;
392+
trace[trace_length].opcode = SET_IP;
393+
trace[trace_length].oparg = ip_offset;
394+
trace[trace_length + 1].opcode = EXIT_TRACE;
395+
trace[trace_length + 1].oparg = 0;
396+
return trace_length + 2;
354397
}
355398

356399
static int
@@ -361,7 +404,7 @@ uop_optimize(
361404
_PyExecutorObject **exec_ptr)
362405
{
363406
uop_instruction trace[MAX_TRACE_LENGTH];
364-
int trace_length = translate_bytecode_to_trace(instr, trace, MAX_TRACE_LENGTH);
407+
int trace_length = translate_bytecode_to_trace(code, instr, trace, MAX_TRACE_LENGTH);
365408
if (trace_length <= 0) {
366409
// Error or nothing translated
367410
return trace_length;
@@ -374,19 +417,25 @@ uop_optimize(
374417
Py_INCREF(self);
375418
executor->optimizer = (UOpOptimizerObject *)self;
376419
memcpy(executor->trace, trace, trace_length * sizeof(uop_instruction));
377-
executor->next_instr = instr + 1; // Skip the LOAD_FAST!
378420
*exec_ptr = (_PyExecutorObject *)executor;
379421
return 1;
380422
}
381423

382424
static PyObject *
383-
uop_get_state(PyObject *self, PyObject *args)
425+
uop_get_traces(PyObject *self, PyObject *args)
426+
{
427+
return PyLong_FromLongLong(((UOpOptimizerObject *)self)->traces_executed);
428+
}
429+
430+
static PyObject *
431+
uop_get_instrs(PyObject *self, PyObject *args)
384432
{
385433
return PyLong_FromLongLong(((UOpOptimizerObject *)self)->instrs_executed);
386434
}
387435

388436
static PyMethodDef uop_methods[] = {
389-
{ "state", uop_get_state, METH_NOARGS, NULL },
437+
{ "get_traces", uop_get_traces, METH_NOARGS, NULL },
438+
{ "get_instrs", uop_get_instrs, METH_NOARGS, NULL },
390439
{ NULL, NULL },
391440
};
392441

@@ -409,6 +458,7 @@ PyUnstable_Optimizer_NewUOpOptimizer(void)
409458
opt->base.optimize = uop_optimize;
410459
opt->base.resume_threshold = UINT16_MAX;
411460
opt->base.backedge_threshold = 0;
461+
opt->traces_executed = 0;
412462
opt->instrs_executed = 0;
413463
return (PyObject *)opt;
414464
}

0 commit comments

Comments
 (0)