From dff101fc1705b61c41bf6c09af95626997735879 Mon Sep 17 00:00:00 2001 From: Neko Asakura Date: Wed, 8 Apr 2026 12:36:03 -0400 Subject: [PATCH] gh-148211: refactor bool to explicit uops in JIT --- Python/optimizer_analysis.c | 43 ++++++++++++++---------------------- Python/optimizer_bytecodes.c | 39 +++++++++++++++++++------------- Python/optimizer_cases.c.h | 39 +++++++++++++++++++------------- 3 files changed, 64 insertions(+), 57 deletions(-) diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index ed1619df2a188b..a3c6efeb2f1177 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -155,7 +155,8 @@ type_watcher_callback(PyTypeObject* type) } static PyObject * -convert_global_to_const(_PyUOpInstruction *inst, PyObject *obj, bool insert) +convert_global_to_const(_PyUOpInstruction *inst, PyObject *obj, + uint16_t immortal_op, uint16_t mortal_op) { assert(inst->opcode == _LOAD_GLOBAL_MODULE || inst->opcode == _LOAD_GLOBAL_BUILTINS || inst->opcode == _LOAD_ATTR_MODULE); assert(PyDict_CheckExact(obj)); @@ -175,18 +176,12 @@ convert_global_to_const(_PyUOpInstruction *inst, PyObject *obj, bool insert) if (res == NULL) { return NULL; } - if (insert) { - if (_Py_IsImmortal(res)) { - inst->opcode = _INSERT_1_LOAD_CONST_INLINE_BORROW; - } else { - inst->opcode = _INSERT_1_LOAD_CONST_INLINE; - } + if (_Py_IsImmortal(res)) { + inst->opcode = immortal_op; } else { - if (_Py_IsImmortal(res)) { - inst->opcode = _LOAD_CONST_INLINE_BORROW; - } else { - inst->opcode = _LOAD_CONST_INLINE; - } + inst->opcode = mortal_op; + } + if (inst->opcode == _LOAD_CONST_INLINE_BORROW || inst->opcode == _LOAD_CONST_INLINE) { if (inst->oparg & 1) { assert(inst[1].opcode == _PUSH_NULL_CONDITIONAL); assert(inst[1].oparg & 1); @@ -330,7 +325,7 @@ optimize_to_bool( JitOptContext *ctx, JitOptRef value, JitOptRef *result_ptr, - bool insert_mode) + uint16_t prefix, uint16_t load_op) { if (sym_matches_type(value, &PyBool_Type)) { ADD_OP(_NOP, 0, 0); @@ -340,12 +335,10 @@ optimize_to_bool( int truthiness = sym_truthiness(ctx, value); if (truthiness >= 0) { PyObject *load = truthiness ? Py_True : Py_False; - if (insert_mode) { - ADD_OP(_INSERT_1_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)load); - } else { - ADD_OP(_POP_TOP, 0, 0); - ADD_OP(_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)load); + if (prefix != _NOP) { + ADD_OP(prefix, 0, 0); } + ADD_OP(load_op, 0, (uintptr_t)load); *result_ptr = sym_new_const(ctx, load); return 1; } @@ -391,22 +384,18 @@ eliminate_pop_guard(_PyUOpInstruction *this_instr, JitOptContext *ctx, bool exit static JitOptRef lookup_attr(JitOptContext *ctx, _PyBloomFilter *dependencies, _PyUOpInstruction *this_instr, - PyTypeObject *type, PyObject *name, bool pop) + PyTypeObject *type, PyObject *name, + uint16_t prefix, uint16_t immortal_op, uint16_t mortal_op) { // The cached value may be dead, so we need to do the lookup again... :( if (type && PyType_Check(type)) { PyObject *lookup = _PyType_Lookup(type, name); if (lookup) { bool immortal = _Py_IsImmortal(lookup) || (type->tp_flags & Py_TPFLAGS_IMMUTABLETYPE); - if (pop) { - ADD_OP(_POP_TOP, 0, 0); - ADD_OP(immortal ? _LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE, - 0, (uintptr_t)lookup); - } - else { - ADD_OP(immortal ? _INSERT_1_LOAD_CONST_INLINE_BORROW : _INSERT_1_LOAD_CONST_INLINE, - 0, (uintptr_t)lookup); + if (prefix != _NOP) { + ADD_OP(prefix, 0, 0); } + ADD_OP(immortal ? immortal_op : mortal_op, 0, (uintptr_t)lookup); PyType_Watch(TYPE_WATCHER_ID, (PyObject *)type); _Py_BloomFilter_Add(dependencies, type); return sym_new_const(ctx, lookup); diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 3ba404b81ea043..7dc763db71b34b 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -536,21 +536,24 @@ dummy_func(void) { } op(_TO_BOOL, (value -- res)) { - int already_bool = optimize_to_bool(this_instr, ctx, value, &res, false); + int already_bool = optimize_to_bool(this_instr, ctx, value, &res, + _POP_TOP, _LOAD_CONST_INLINE_BORROW); if (!already_bool) { res = sym_new_truthiness(ctx, value, true); } } op(_TO_BOOL_BOOL, (value -- value)) { - int already_bool = optimize_to_bool(this_instr, ctx, value, &value, false); + int already_bool = optimize_to_bool(this_instr, ctx, value, &value, + _POP_TOP, _LOAD_CONST_INLINE_BORROW); if (!already_bool) { sym_set_type(value, &PyBool_Type); } } op(_TO_BOOL_INT, (value -- res, v)) { - int already_bool = optimize_to_bool(this_instr, ctx, value, &res, true); + int already_bool = optimize_to_bool(this_instr, ctx, value, &res, + _NOP, _INSERT_1_LOAD_CONST_INLINE_BORROW); if (!already_bool) { sym_set_type(value, &PyLong_Type); res = sym_new_truthiness(ctx, value, true); @@ -559,7 +562,8 @@ dummy_func(void) { } op(_TO_BOOL_LIST, (value -- res, v)) { - int already_bool = optimize_to_bool(this_instr, ctx, value, &res, true); + int already_bool = optimize_to_bool(this_instr, ctx, value, &res, + _NOP, _INSERT_1_LOAD_CONST_INLINE_BORROW); if (!already_bool) { res = sym_new_type(ctx, &PyBool_Type); } @@ -567,7 +571,8 @@ dummy_func(void) { } op(_TO_BOOL_NONE, (value -- res)) { - int already_bool = optimize_to_bool(this_instr, ctx, value, &res, false); + int already_bool = optimize_to_bool(this_instr, ctx, value, &res, + _POP_TOP, _LOAD_CONST_INLINE_BORROW); if (!already_bool) { sym_set_const(value, Py_None); res = sym_new_const(ctx, Py_False); @@ -593,7 +598,8 @@ dummy_func(void) { } op(_TO_BOOL_STR, (value -- res, v)) { - int already_bool = optimize_to_bool(this_instr, ctx, value, &res, true); + int already_bool = optimize_to_bool(this_instr, ctx, value, &res, + _NOP, _INSERT_1_LOAD_CONST_INLINE_BORROW); v = value; if (!already_bool) { res = sym_new_truthiness(ctx, value, true); @@ -837,7 +843,8 @@ dummy_func(void) { if (watched_mutations < _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS) { PyDict_Watch(GLOBALS_WATCHER_ID, dict); _Py_BloomFilter_Add(dependencies, dict); - PyObject *res = convert_global_to_const(this_instr, dict, true); + PyObject *res = convert_global_to_const(this_instr, dict, + _INSERT_1_LOAD_CONST_INLINE_BORROW, _INSERT_1_LOAD_CONST_INLINE); if (res == NULL) { attr = sym_new_not_null(ctx); } @@ -890,7 +897,7 @@ dummy_func(void) { PyTypeObject *type = (PyTypeObject *)sym_get_const(ctx, owner); PyObject *name = get_co_name(ctx, oparg >> 1); attr = lookup_attr(ctx, dependencies, this_instr, type, name, - true); + _POP_TOP, _LOAD_CONST_INLINE_BORROW, _LOAD_CONST_INLINE); } op(_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, (descr/4, owner -- attr)) { @@ -898,7 +905,7 @@ dummy_func(void) { PyTypeObject *type = sym_get_type(owner); PyObject *name = get_co_name(ctx, oparg >> 1); attr = lookup_attr(ctx, dependencies, this_instr, type, name, - true); + _POP_TOP, _LOAD_CONST_INLINE_BORROW, _LOAD_CONST_INLINE); } op(_LOAD_ATTR_NONDESCRIPTOR_NO_DICT, (descr/4, owner -- attr)) { @@ -906,7 +913,7 @@ dummy_func(void) { PyTypeObject *type = sym_get_type(owner); PyObject *name = get_co_name(ctx, oparg >> 1); attr = lookup_attr(ctx, dependencies, this_instr, type, name, - true); + _POP_TOP, _LOAD_CONST_INLINE_BORROW, _LOAD_CONST_INLINE); } op(_LOAD_ATTR_METHOD_WITH_VALUES, (descr/4, owner -- attr, self)) { @@ -914,7 +921,7 @@ dummy_func(void) { PyTypeObject *type = sym_get_type(owner); PyObject *name = get_co_name(ctx, oparg >> 1); attr = lookup_attr(ctx, dependencies, this_instr, type, name, - false); + _NOP, _INSERT_1_LOAD_CONST_INLINE_BORROW, _INSERT_1_LOAD_CONST_INLINE); self = owner; } @@ -923,7 +930,7 @@ dummy_func(void) { PyTypeObject *type = sym_get_type(owner); PyObject *name = get_co_name(ctx, oparg >> 1); attr = lookup_attr(ctx, dependencies, this_instr, type, name, - false); + _NOP, _INSERT_1_LOAD_CONST_INLINE_BORROW, _INSERT_1_LOAD_CONST_INLINE); self = owner; } @@ -932,7 +939,7 @@ dummy_func(void) { PyTypeObject *type = sym_get_type(owner); PyObject *name = get_co_name(ctx, oparg >> 1); attr = lookup_attr(ctx, dependencies, this_instr, type, name, - false); + _NOP, _INSERT_1_LOAD_CONST_INLINE_BORROW, _INSERT_1_LOAD_CONST_INLINE); self = owner; } @@ -2007,7 +2014,8 @@ dummy_func(void) { ctx->builtins_watched = true; } if (ctx->frame->globals_checked_version != 0 && ctx->frame->globals_watched) { - cnst = convert_global_to_const(this_instr, builtins, false); + cnst = convert_global_to_const(this_instr, builtins, + _LOAD_CONST_INLINE_BORROW, _LOAD_CONST_INLINE); } } if (cnst == NULL) { @@ -2046,7 +2054,8 @@ dummy_func(void) { ctx->frame->globals_checked_version = version; } if (ctx->frame->globals_checked_version == version) { - cnst = convert_global_to_const(this_instr, globals, false); + cnst = convert_global_to_const(this_instr, globals, + _LOAD_CONST_INLINE_BORROW, _LOAD_CONST_INLINE); } } } diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 2c8a0bff13ce35..2462959ace83a3 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -332,7 +332,8 @@ JitOptRef value; JitOptRef res; value = stack_pointer[-1]; - int already_bool = optimize_to_bool(this_instr, ctx, value, &res, false); + int already_bool = optimize_to_bool(this_instr, ctx, value, &res, + _POP_TOP, _LOAD_CONST_INLINE_BORROW); if (!already_bool) { res = sym_new_truthiness(ctx, value, true); } @@ -343,7 +344,8 @@ case _TO_BOOL_BOOL: { JitOptRef value; value = stack_pointer[-1]; - int already_bool = optimize_to_bool(this_instr, ctx, value, &value, false); + int already_bool = optimize_to_bool(this_instr, ctx, value, &value, + _POP_TOP, _LOAD_CONST_INLINE_BORROW); if (!already_bool) { sym_set_type(value, &PyBool_Type); } @@ -356,7 +358,8 @@ JitOptRef res; JitOptRef v; value = stack_pointer[-1]; - int already_bool = optimize_to_bool(this_instr, ctx, value, &res, true); + int already_bool = optimize_to_bool(this_instr, ctx, value, &res, + _NOP, _INSERT_1_LOAD_CONST_INLINE_BORROW); if (!already_bool) { sym_set_type(value, &PyLong_Type); res = sym_new_truthiness(ctx, value, true); @@ -411,7 +414,8 @@ JitOptRef res; JitOptRef v; value = stack_pointer[-1]; - int already_bool = optimize_to_bool(this_instr, ctx, value, &res, true); + int already_bool = optimize_to_bool(this_instr, ctx, value, &res, + _NOP, _INSERT_1_LOAD_CONST_INLINE_BORROW); if (!already_bool) { res = sym_new_type(ctx, &PyBool_Type); } @@ -428,7 +432,8 @@ JitOptRef value; JitOptRef res; value = stack_pointer[-1]; - int already_bool = optimize_to_bool(this_instr, ctx, value, &res, false); + int already_bool = optimize_to_bool(this_instr, ctx, value, &res, + _POP_TOP, _LOAD_CONST_INLINE_BORROW); if (!already_bool) { sym_set_const(value, Py_None); res = sym_new_const(ctx, Py_False); @@ -469,7 +474,8 @@ JitOptRef res; JitOptRef v; value = stack_pointer[-1]; - int already_bool = optimize_to_bool(this_instr, ctx, value, &res, true); + int already_bool = optimize_to_bool(this_instr, ctx, value, &res, + _NOP, _INSERT_1_LOAD_CONST_INLINE_BORROW); v = value; if (!already_bool) { res = sym_new_truthiness(ctx, value, true); @@ -2086,7 +2092,8 @@ ctx->frame->globals_checked_version = version; } if (ctx->frame->globals_checked_version == version) { - cnst = convert_global_to_const(this_instr, globals, false); + cnst = convert_global_to_const(this_instr, globals, + _LOAD_CONST_INLINE_BORROW, _LOAD_CONST_INLINE); } } } @@ -2129,7 +2136,8 @@ ctx->builtins_watched = true; } if (ctx->frame->globals_checked_version != 0 && ctx->frame->globals_watched) { - cnst = convert_global_to_const(this_instr, builtins, false); + cnst = convert_global_to_const(this_instr, builtins, + _LOAD_CONST_INLINE_BORROW, _LOAD_CONST_INLINE); } } if (cnst == NULL) { @@ -2439,7 +2447,8 @@ if (watched_mutations < _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS) { PyDict_Watch(GLOBALS_WATCHER_ID, dict); _Py_BloomFilter_Add(dependencies, dict); - PyObject *res = convert_global_to_const(this_instr, dict, true); + PyObject *res = convert_global_to_const(this_instr, dict, + _INSERT_1_LOAD_CONST_INLINE_BORROW, _INSERT_1_LOAD_CONST_INLINE); if (res == NULL) { attr = sym_new_not_null(ctx); } @@ -2520,7 +2529,7 @@ PyTypeObject *type = (PyTypeObject *)sym_get_const(ctx, owner); PyObject *name = get_co_name(ctx, oparg >> 1); attr = lookup_attr(ctx, dependencies, this_instr, type, name, - true); + _POP_TOP, _LOAD_CONST_INLINE_BORROW, _LOAD_CONST_INLINE); stack_pointer[-1] = attr; break; } @@ -3413,7 +3422,7 @@ PyTypeObject *type = sym_get_type(owner); PyObject *name = get_co_name(ctx, oparg >> 1); attr = lookup_attr(ctx, dependencies, this_instr, type, name, - false); + _NOP, _INSERT_1_LOAD_CONST_INLINE_BORROW, _INSERT_1_LOAD_CONST_INLINE); self = owner; CHECK_STACK_BOUNDS(1); stack_pointer[-1] = attr; @@ -3433,7 +3442,7 @@ PyTypeObject *type = sym_get_type(owner); PyObject *name = get_co_name(ctx, oparg >> 1); attr = lookup_attr(ctx, dependencies, this_instr, type, name, - false); + _NOP, _INSERT_1_LOAD_CONST_INLINE_BORROW, _INSERT_1_LOAD_CONST_INLINE); self = owner; CHECK_STACK_BOUNDS(1); stack_pointer[-1] = attr; @@ -3452,7 +3461,7 @@ PyTypeObject *type = sym_get_type(owner); PyObject *name = get_co_name(ctx, oparg >> 1); attr = lookup_attr(ctx, dependencies, this_instr, type, name, - true); + _POP_TOP, _LOAD_CONST_INLINE_BORROW, _LOAD_CONST_INLINE); stack_pointer[-1] = attr; break; } @@ -3466,7 +3475,7 @@ PyTypeObject *type = sym_get_type(owner); PyObject *name = get_co_name(ctx, oparg >> 1); attr = lookup_attr(ctx, dependencies, this_instr, type, name, - true); + _POP_TOP, _LOAD_CONST_INLINE_BORROW, _LOAD_CONST_INLINE); stack_pointer[-1] = attr; break; } @@ -3485,7 +3494,7 @@ PyTypeObject *type = sym_get_type(owner); PyObject *name = get_co_name(ctx, oparg >> 1); attr = lookup_attr(ctx, dependencies, this_instr, type, name, - false); + _NOP, _INSERT_1_LOAD_CONST_INLINE_BORROW, _INSERT_1_LOAD_CONST_INLINE); self = owner; CHECK_STACK_BOUNDS(1); stack_pointer[-1] = attr;