8000 GH-118095: Unify the behavior of tier 2 FOR_ITER branch micro-ops (GH… · python/cpython@72867c9 · GitHub
[go: up one dir, main page]

Skip to content

Commit 72867c9

Browse files
authored
GH-118095: Unify the behavior of tier 2 FOR_ITER branch micro-ops (GH-118420)
* Target _FOR_ITER_TIER_TWO at POP_TOP following the matching END_FOR * Modify _GUARD_NOT_EXHAUSTED_RANGE, _GUARD_NOT_EXHAUSTED_LIST and _GUARD_NOT_EXHAUSTED_TUPLE so that they also target the POP_TOP following the matching END_FOR
1 parent 9789440 commit 72867c9

File tree

5 files changed

+56
-21
lines changed

5 files changed

+56
-21
lines changed

Python/bytecodes.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2610,9 +2610,7 @@ dummy_func(
26102610
_PyErr_Clear(tstate);
26112611
}
26122612
/* iterator ended normally */
2613-
Py_DECREF(iter);
2614-
STACK_SHRINK(1);
2615-
/* The translator sets the deopt target just past END_FOR */
2613+
/* The translator sets the deopt target just past the matching END_FOR */
26162614
DEOPT_IF(true);
26172615
}
26182616
// Common case: no jump, leave it to the code generator

Python/executor_cases.c.h

Lines changed: 1 addition & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/optimizer.c

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,19 @@
2323

2424
#define MAX_EXECUTORS_SIZE 256
2525

26+
#ifdef Py_DEBUG
27+
static int
28+
base_opcode(PyCodeObject *code, int offset)
29+
{
30+
int opcode = _Py_GetBaseOpcode(code, offset);
31+
if (opcode == ENTER_EXECUTOR) {
32+
int oparg = _PyCode_CODE(code)[offset].op.arg;
33+
_PyExecutorObject *ex = code->co_executors->executors[oparg];
34+
return ex->vm_data.opcode;
35+
}
36+
return opcode;
37+
}
38+
#endif
2639

2740
static bool
2841
has_space_for_executor(PyCodeObject *code, _Py_CODEUNIT *instr)
@@ -445,6 +458,14 @@ _PyUOp_Replacements[MAX_UOP_ID + 1] = {
445458
[_FOR_ITER] = _FOR_ITER_TIER_TWO,
446459
};
447460

461+
static const uint8_t
462+
is_for_iter_test[MAX_UOP_ID + 1] = {
463+
[_GUARD_NOT_EXHAUSTED_RANGE] = 1,
464+
[_GUARD_NOT_EXHAUSTED_LIST] = 1,
465+
[_GUARD_NOT_EXHAUSTED_TUPLE] = 1,
466+
[_FOR_ITER_TIER_TWO] = 1,
467+
};
468+
448469
static const uint16_t
449470
BRANCH_TO_GUARD[4][2] = {
450471
[POP_JUMP_IF_FALSE - POP_JUMP_IF_FALSE][0] = _GUARD_IS_TRUE_POP,
@@ -594,7 +615,6 @@ translate_bytecode_to_trace(
594615

595616
uint32_t opcode = instr->op.code;
596617
uint32_t oparg = instr->op.arg;
597-
uint32_t extended = 0;
598618

599619
DPRINTF(2, "%d: %s(%d)\n", target, _PyOpcode_OpName[opcode], oparg);
600620

@@ -608,7 +628,6 @@ translate_bytecode_to_trace(
608628

609629
if (opcode == EXTENDED_ARG) {
610630
instr++;
611-
extended = 1;
612631
opcode = instr->op.code;
613632
oparg = (oparg << 8) | instr->op.arg;
614633
if (opcode == EXTENDED_ARG) {
@@ -772,12 +791,15 @@ translate_bytecode_to_trace(
772791
case OPARG_REPLACED:
773792
uop = _PyUOp_Replacements[uop];
774793
assert(uop != 0);
775-
if (uop == _FOR_ITER_TIER_TWO) {
776-
target += 1 + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 2 + extended;
777-
assert(_PyCode_CODE(code)[target-2].op.code == END_FOR ||
778-
_PyCode_CODE(code)[target-2].op.code == INSTRUMENTED_END_FOR);
779-
assert(_PyCode_CODE(code)[target-1].op.code == POP_TOP);
794+
#ifdef Py_DEBUG
795+
{
796+
uint32_t next_inst = target + 1 + INLINE_CACHE_ENTRIES_FOR_ITER + (oparg > 255);
797+
uint32_t jump_target = next_inst + oparg;
798+
assert(base_opcode(code, jump_target) == END_FOR ||
799+
base_opcode(code, jump_target) == INSTRUMENTED_END_FOR);
800+
assert(base_opcode(code, jump_target+1) == POP_TOP);
780801
}
802+
#endif
781803
break;
782804
default:
783805
fprintf(stderr,
@@ -1000,10 +1022,18 @@ prepare_for_execution(_PyUOpInstruction *buffer, int length)
10001022
if (_PyUop_Flags[opcode] & (HAS_EXIT_FLAG | HAS_DEOPT_FLAG)) {
10011023
uint16_t exit_op = (_PyUop_Flags[opcode] & HAS_EXIT_FLAG) ?
10021024
_SIDE_EXIT : _DEOPT;
1003-
if (target != current_jump_target || current_exit_op != exit_op) {
1004-
make_exit(&buffer[next_spare], exit_op, target);
1025+
int32_t jump_target = target;
1026+
if (is_for_iter_test[opcode]) {
1027+
/* Target the POP_TOP immediately after the END_FOR,
1028+
* leaving only the iterator on the stack. */
1029+
int extended_arg = inst->oparg > 255;
1030+
int32_t next_inst = target + 1 + INLINE_CACHE_ENTRIES_FOR_ITER + extended_arg;
1031+
jump_target = next_inst + inst->oparg + 1;
1032+
}
1033+
if (jump_target != current_jump_target || current_exit_op != exit_op) {
1034+
make_exit(&buffer[next_spare], exit_op, jump_target);
10051035
current_exit_op = exit_op;
1006-
current_jump_target = target;
1036+
current_jump_target = jump_target;
10071037
current_jump = next_spare;
10081038
next_spare++;
10091039
}

Python/optimizer_symbols.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,19 +164,26 @@ _Py_uop_sym_set_const(_Py_UopsSymbol *sym, PyObject *const_val)
164164
return true;
165165
}
166166

167-
168167
bool
169168
_Py_uop_sym_set_null(_Py_UopsSymbol *sym)
170169
{
170+
if (_Py_uop_sym_is_not_null(sym)) {
171+
sym_set_bottom(sym);
172+
return false;
173+
}
171174
sym_set_flag(sym, IS_NULL);
172-
return !_Py_uop_sym_is_bottom(sym);
175+
return true;
173176
}
174177

175178
bool
176179
_Py_uop_sym_set_non_null(_Py_UopsSymbol *sym)
177180
{
181+
if (_Py_uop_sym_is_null(sym)) {
182+
sym_set_bottom(sym);
183+
return false;
184+
}
178185
sym_set_flag(sym, NOT_NULL);
179-
return !_Py_uop_sym_is_bottom(sym);
186+
return true;
180187
}
181188

182189

Python/specialize.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ print_gc_stats(FILE *out, GCStats *stats)
215215
}
216216
}
217217

218+
#ifdef _Py_TIER2
218219
static void
219220
print_histogram(FILE *out, const char *name, uint64_t hist[_Py_UOP_HIST_SIZE])
220221
{
@@ -249,7 +250,6 @@ print_optimization_stats(FILE *out, OptimizationStats *stats)
249250
stats->optimizer_failure_reason_no_memory);
250251
fprintf(out, "Optimizer remove globals builtins changed: %" PRIu64 "\n", stats->remove_globals_builtins_changed);
251252
fprintf(out, "Optimizer remove globals incorrect keys: %" PRIu64 "\n", stats->remove_globals_incorrect_keys);
252-
253253
for (int i = 0; i <= MAX_UOP_ID; i++) {
254254
if (stats->opcode[i].execution_count) {
255255
fprintf(out, "uops[%s].execution_count : %" PRIu64 "\n", _PyUOpName(i), stats->opcode[i].execution_count);
@@ -258,7 +258,6 @@ print_optimization_stats(FILE *out, OptimizationStats *stats)
258258
fprintf(out, "uops[%s].specialization.miss : %" PRIu64 "\n", _PyUOpName(i), stats->opcode[i].miss);
259259
}
260260
}
261-
262261
for (int i = 0; i < 256; i++) {
263262
if (stats->unsupported_opcode[i]) {
264263
fprintf(
@@ -289,6 +288,7 @@ print_optimization_stats(FILE *out, OptimizationStats *stats)
289288
}
290289
}
291290
}
291+
#endif
292292

293293
static void
294294
print_rare_event_stats(FILE *out, RareEventStats *stats)
@@ -309,7 +309,9 @@ print_stats(FILE *out, PyStats *stats)
309309
print_call_stats(out, &stats->call_stats);
310310
print_object_stats(out, &stats->object_stats);
311311
print_gc_stats(out, stats->gc_stats);
312+
#ifdef _Py_TIER2
312313
print_optimization_stats(out, &stats->optimization_stats);
314+
#endif
313315
print_rare_event_stats(out, &stats->rare_event_stats);
314316
}
315317

0 commit comments

Comments
 (0)
0