Skip to content

Commit e771fd0

Browse files
committed
use add_op to save optimized uops
1 parent 03e6457 commit e771fd0

File tree

6 files changed

+172
-139
lines changed

6 files changed

+172
-139
lines changed

Include/internal/pycore_optimizer_types.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,10 @@ typedef struct _JitOptContext {
128128
JitOptRef *n_consumed;
129129
JitOptRef *limit;
130130
JitOptRef locals_and_stack[MAX_ABSTRACT_INTERP_SIZE];
131+
132+
// buffer to save optimized result
133+
int out_len;
134+
_PyUOpInstruction out_buffer[UOP_MAX_TRACE_LENGTH];
131135
} JitOptContext;
132136

133137

Python/optimizer.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1509,6 +1509,7 @@ uop_optimize(
15091509
if (length <= 0) {
15101510
return length;
15111511
}
1512+
buffer = _tstate->jit_tracer_state->opt_context.out_buffer;
15121513
}
15131514
assert(length < UOP_MAX_TRACE_LENGTH/2);
15141515
assert(length >= 1);

Python/optimizer_analysis.c

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,16 @@ incorrect_keys(PyObject *obj, uint32_t version)
152152
(INST)->oparg = ARG; \
153153
(INST)->operand0 = OPERAND;
154154

155+
#define ADD_OP(OP, ARG, OPERAND) ( \
156+
ctx->out_buffer[ctx->out_len].opcode = (OP), \
157+
ctx->out_buffer[ctx->out_len].format = this_instr->format, \
158+
ctx->out_buffer[ctx->out_len].oparg = (ARG), \
159+
ctx->out_buffer[ctx->out_len].target = this_instr->target, \
160+
ctx->out_buffer[ctx->out_len].operand0 = (OPERAND), \
161+
ctx->out_buffer[ctx->out_len].operand1 = this_instr->operand1, \
162+
ctx->out_len++ \
163+
)
164+
155165
/* Shortened forms for convenience, used in optimizer_bytecodes.c */
156166
#define sym_is_not_null _Py_uop_sym_is_not_null
157167
#define sym_is_const _Py_uop_sym_is_const
@@ -219,7 +229,7 @@ optimize_to_bool(
219229
bool insert_mode)
220230
{
221231
if (sym_matches_type(value, &PyBool_Type)) {
222-
REPLACE_OP(this_instr, _NOP, 0, 0);
232+
ADD_OP(_NOP, 0, 0);
223233
*result_ptr = value;
224234
return 1;
225235
}
@@ -229,17 +239,17 @@ optimize_to_bool(
229239
int opcode = insert_mode ?
230240
_INSERT_1_LOAD_CONST_INLINE_BORROW :
231241
_POP_TOP_LOAD_CONST_INLINE_BORROW;
232-
REPLACE_OP(this_instr, opcode, 0, (uintptr_t)load);
242+
ADD_OP(opcode, 0, (uintptr_t)load);
233243
*result_ptr = sym_new_const(ctx, load);
234244
return 1;
235245
}
236246
return 0;
237247
}
238248

239249
static void
240-
eliminate_pop_guard(_PyUOpInstruction *this_instr, bool exit)
250+
eliminate_pop_guard(_PyUOpInstruction *this_instr, JitOptContext *ctx, bool exit)
241251
{
242-
REPLACE_OP(this_instr, _POP_TOP, 0, 0);
252+
ADD_OP(_POP_TOP, 0, 0);
243253
if (exit) {
244254
REPLACE_OP((this_instr+1), _EXIT_TRACE, 0, 0);
245255
this_instr[1].target = this_instr->target;
@@ -256,7 +266,7 @@ lookup_attr(JitOptContext *ctx, _PyBloomFilter *dependencies, _PyUOpInstruction
256266
PyObject *lookup = _PyType_Lookup(type, name);
257267
if (lookup) {
258268
int opcode = _Py_IsImmortal(lookup) ? immortal : mortal;
259-
REPLACE_OP(this_instr, opcode, 0, (uintptr_t)lookup);
269+
ADD_OP(opcode, 0, (uintptr_t)lookup);
260270
PyType_Watch(TYPE_WATCHER_ID, (PyObject *)type);
261271
_Py_BloomFilter_Add(dependencies, type);
262272
return sym_new_const(ctx, lookup);
@@ -364,6 +374,7 @@ optimize_uops(
364374
frame->func = func;
365375
ctx->curr_frame_depth++;
366376
ctx->frame = frame;
377+
ctx->out_len = 0;
367378

368379
_PyUOpInstruction *this_instr = NULL;
369380
JitOptRef *stack_pointer = ctx->frame->stack_pointer;
@@ -387,6 +398,7 @@ optimize_uops(
387398
}
388399
#endif
389400

401+
int out_len_before = ctx->out_len;
390402
switch (opcode) {
391403

392404
#include "optimizer_cases.c.h"
@@ -395,6 +407,10 @@ optimize_uops(
395407
DPRINTF(1, "\nUnknown opcode in abstract interpreter\n");
396408
Py_UNREACHABLE();
397409
}
410+
// If no ADD_OP was called during this iteration, copy the original instruction
411+
if (ctx->out_len == out_len_before) {
412+
ctx->out_buffer[ctx->out_len++] = *this_instr;
413+
}
398414
assert(ctx->frame != NULL);
399415
if (!CURRENT_FRAME_IS_INIT_SHIM()) {
400416
DPRINTF(3, " stack_level %d\n", STACK_LEVEL());
@@ -423,7 +439,18 @@ optimize_uops(
423439
/* Either reached the end or cannot optimize further, but there
424440
* would be no benefit in retrying later */
425441
_Py_uop_abstractcontext_fini(ctx);
426-
return trace_len;
442+
// Check that the trace ends with a proper terminator
443+
if (ctx->out_len > 0) {
444+
int last_opcode = ctx->out_buffer[ctx->out_len - 1].opcode;
445+
if (last_opcode != _EXIT_TRACE &&
446+
last_opcode != _JUMP_TO_TOP &&
447+
last_opcode != _DYNAMIC_EXIT &&
448+
last_opcode != _DEOPT) {
449+
return 0;
450+
}
451+
}
452+
453+
return ctx->out_len;
427454

428455
error:
429456
DPRINTF(3, "\n");
@@ -584,6 +611,7 @@ _Py_uop_analyze_and_optimize(
584611
)
585612
{
586613
OPT_STAT_INC(optimizer_attempts);
614+
JitOptContext *ctx = &tstate->jit_tracer_state->opt_context;
587615

588616
length = optimize_uops(
589617
tstate, buffer,
@@ -595,7 +623,7 @@ _Py_uop_analyze_and_optimize(
595623

596624
assert(length > 0);
597625

598-
length = remove_unneeded_uops(buffer, length);
626+
length = remove_unneeded_uops(ctx->out_buffer, length);
599627
assert(length > 0);
600628

601629
OPT_STAT_INC(optimizer_successes);

0 commit comments

Comments
 (0)