Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GH-113710: Improve _SET_IP and _CHECK_VALIDITY #115248

Merged
merged 9 commits into from
Feb 13, 2024
3 changes: 2 additions & 1 deletion Include/internal/pycore_uop_ids.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Include/internal/pycore_uop_metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = {
[_GUARD_IS_NONE_POP] = HAS_DEOPT_FLAG,
[_GUARD_IS_NOT_NONE_POP] = HAS_DEOPT_FLAG,
[_JUMP_TO_TOP] = HAS_EVAL_BREAK_FLAG,
[_SET_IP] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG,
[_SET_IP] = 0,
[_SAVE_RETURN_OFFSET] = HAS_ARG_FLAG,
[_EXIT_TRACE] = HAS_DEOPT_FLAG,
[_CHECK_VALIDITY] = HAS_DEOPT_FLAG,
Expand All @@ -209,6 +209,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = {
[_CHECK_GLOBALS] = HAS_DEOPT_FLAG,
[_CHECK_BUILTINS] = HAS_DEOPT_FLAG,
[_INTERNAL_INCREMENT_OPT_COUNTER] = 0,
[_CHECK_VALIDITY_AND_SET_IP] = HAS_DEOPT_FLAG,
};

const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = {
Expand Down Expand Up @@ -264,6 +265,7 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = {
[_CHECK_PEP_523] = "_CHECK_PEP_523",
[_CHECK_STACK_SPACE] = "_CHECK_STACK_SPACE",
[_CHECK_VALIDITY] = "_CHECK_VALIDITY",
[_CHECK_VALIDITY_AND_SET_IP] = "_CHECK_VALIDITY_AND_SET_IP",
[_COMPARE_OP] = "_COMPARE_OP",
[_COMPARE_OP_FLOAT] = "_COMPARE_OP_FLOAT",
[_COMPARE_OP_INT] = "_COMPARE_OP_INT",
Expand Down
10 changes: 7 additions & 3 deletions Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -4034,10 +4034,9 @@ dummy_func(
CHECK_EVAL_BREAKER();
}

op(_SET_IP, (--)) {
op(_SET_IP, (instr_ptr/4 --)) {
TIER_TWO_ONLY
// TODO: Put the code pointer in `operand` to avoid indirection via `frame`
frame->instr_ptr = _PyCode_CODE(_PyFrame_GetCode(frame)) + oparg;
frame->instr_ptr = (_Py_CODEUNIT *)instr_ptr;
}

op(_SAVE_RETURN_OFFSET, (--)) {
Expand Down Expand Up @@ -4097,6 +4096,11 @@ dummy_func(
exe->count++;
}

op(_CHECK_VALIDITY_AND_SET_IP, (instr_ptr/4 --)) {
TIER_TWO_ONLY
DEOPT_IF(!current_executor->vm_data.valid);
frame->instr_ptr = instr_ptr;
}

// END BYTECODES //

Expand Down
13 changes: 10 additions & 3 deletions Python/executor_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions Python/optimizer.c
Original file line number Diff line number Diff line change
Expand Up @@ -417,9 +417,8 @@ translate_bytecode_to_trace(
top: // Jump here after _PUSH_FRAME or likely branches
for (;;) {
target = INSTR_IP(instr, code);
RESERVE_RAW(3, "epilogue"); // Always need space for _SET_IP, _CHECK_VALIDITY and _EXIT_TRACE
ADD_TO_TRACE(_SET_IP, target, 0, target);
ADD_TO_TRACE(_CHECK_VALIDITY, 0, 0, target);
RESERVE_RAW(2, "epilogue"); // Always need space for _SET_IP, _CHECK_VALIDITY and _EXIT_TRACE
ADD_TO_TRACE(_CHECK_VALIDITY_AND_SET_IP, 0, (uintptr_t)instr, target);

uint32_t opcode = instr->op.code;
uint32_t oparg = instr->op.arg;
Expand Down
75 changes: 51 additions & 24 deletions Python/optimizer_analysis.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,35 +260,62 @@ peephole_opt(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, int buffer_s
static void
remove_unneeded_uops(_PyUOpInstruction *buffer, int buffer_size)
{
/* Remove _SET_IP and _CHECK_VALIDITY where possible.
* _SET_IP is needed if the following instruction escapes or
* could error. _CHECK_VALIDITY is needed if the previous
* instruction could have escaped. */
int last_set_ip = -1;
bool maybe_invalid = false;
bool may_have_escaped = false;
for (int pc = 0; pc < buffer_size; pc++) {
int opcode = buffer[pc].opcode;
if (opcode == _SET_IP) {
buffer[pc].opcode = NOP;
last_set_ip = pc;
}
else if (opcode == _CHECK_VALIDITY) {
if (maybe_invalid) {
maybe_invalid = false;
}
else {
switch (opcode) {
case _SET_IP:
buffer[pc].opcode = NOP;
}
}
else if (opcode == _JUMP_TO_TOP || opcode == _EXIT_TRACE) {
break;
}
else {
if (_PyUop_Flags[opcode] & HAS_ESCAPES_FLAG) {
maybe_invalid = true;
if (last_set_ip >= 0) {
buffer[last_set_ip].opcode = _SET_IP;
last_set_ip = pc;
break;
case _CHECK_VALIDITY:
if (may_have_escaped) {
may_have_escaped = false;
}
}
if ((_PyUop_Flags[opcode] & HAS_ERROR_FLAG) || opcode == _PUSH_FRAME) {
if (last_set_ip >= 0) {
buffer[last_set_ip].opcode = _SET_IP;
else {
buffer[pc].opcode = NOP;
}
break;
case _CHECK_VALIDITY_AND_SET_IP:
if (may_have_escaped) {
may_have_escaped = false;
buffer[pc].opcode = _CHECK_VALIDITY;
}
else {
buffer[pc].opcode = NOP;
}
last_set_ip = pc;
break;
case _JUMP_TO_TOP:
case _EXIT_TRACE:
return;
default:
{
bool needs_ip = false;
if (_PyUop_Flags[opcode] & HAS_ESCAPES_FLAG) {
needs_ip = true;
may_have_escaped = true;
}
if (_PyUop_Flags[opcode] & HAS_ERROR_FLAG) {
needs_ip = true;
}
if (opcode == _PUSH_FRAME) {
needs_ip = true;
}
if (needs_ip && last_set_ip >= 0) {
if (buffer[last_set_ip].opcode == _CHECK_VALIDITY) {
buffer[last_set_ip].opcode = _CHECK_VALIDITY_AND_SET_IP;
}
else {
assert(buffer[last_set_ip].opcode == _NOP);
buffer[last_set_ip].opcode = _SET_IP;
}
last_set_ip = -1;
}
}
}
Expand Down
Loading