Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 34k
GH-115651: Convert LOAD_MODULE_ATTR into LOAD_INLINE_CONST when the module is itself a constant.#115711
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
Uh oh!
There was an error while loading. Please reload this page.
GH-115651: Convert LOAD_MODULE_ATTR into LOAD_INLINE_CONST when the module is itself a constant. #115711
Changes from all commits
2762d4c49f58986fb05f876389dd6d95a8be1f5fa9File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Uh oh!
There was an error while loading. Please reload this page.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Uh oh!
There was an error while loading. Please reload this page.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -276,6 +276,20 @@ sym_is_null(_Py_UOpsSymType *sym) | ||
| return (sym->flags & (IS_NULL | NOT_NULL)) == IS_NULL; | ||
| } | ||
| static inline bool | ||
| sym_is_const(_Py_UOpsSymType *sym) | ||
| { | ||
| return (sym->flags & TRUE_CONST) != 0; | ||
| } | ||
| static inline PyObject * | ||
| sym_get_const(_Py_UOpsSymType *sym) | ||
| { | ||
| assert(sym_is_const(sym)); | ||
| assert(sym->const_val); | ||
| return sym->const_val; | ||
| } | ||
| static inline void | ||
| sym_set_type(_Py_UOpsSymType *sym, PyTypeObject *tp) | ||
| { | ||
| @@ -341,18 +355,6 @@ sym_new_const(_Py_UOpsAbstractInterpContext *ctx, PyObject *const_val) | ||
| return temp; | ||
| } | ||
| static inline bool | ||
| is_const(_Py_UOpsSymType *sym) | ||
| { | ||
| return sym->const_val != NULL; | ||
| } | ||
| static inline PyObject * | ||
| get_const(_Py_UOpsSymType *sym) | ||
| { | ||
| return sym->const_val; | ||
| } | ||
| static _Py_UOpsSymType* | ||
| sym_new_null(_Py_UOpsAbstractInterpContext *ctx) | ||
| { | ||
| @@ -413,18 +415,21 @@ globals_watcher_callback(PyDict_WatchEvent event, PyObject* dict, | ||
| return 0; | ||
| } | ||
| static void | ||
| global_to_const(_PyUOpInstruction *inst, PyObject *obj) | ||
| static PyObject * | ||
| convert_global_to_const(_PyUOpInstruction *inst, PyObject *obj) | ||
| { | ||
| assert(inst->opcode == _LOAD_GLOBAL_MODULE || inst->opcode == _LOAD_GLOBAL_BUILTINS); | ||
| assert(inst->opcode == _LOAD_GLOBAL_MODULE || inst->opcode == _LOAD_GLOBAL_BUILTINS || inst->opcode == _LOAD_ATTR_MODULE); | ||
| assert(PyDict_CheckExact(obj)); | ||
| PyDictObject *dict = (PyDictObject *)obj; | ||
| assert(dict->ma_keys->dk_kind == DICT_KEYS_UNICODE); | ||
| PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); | ||
| assert(inst->operand <= UINT16_MAX); | ||
| if ((int)inst->operand >= dict->ma_keys->dk_nentries){ | ||
| return NULL; | ||
| } | ||
| PyObject *res = entries[inst->operand].me_value; | ||
| if (res == NULL){ | ||
| return; | ||
| return NULL; | ||
| } | ||
| if (_Py_IsImmortal(res)){ | ||
| inst->opcode = (inst->oparg & 1) ? _LOAD_CONST_INLINE_BORROW_WITH_NULL : _LOAD_CONST_INLINE_BORROW; | ||
| @@ -433,6 +438,7 @@ global_to_const(_PyUOpInstruction *inst, PyObject *obj) | ||
| inst->opcode = (inst->oparg & 1) ? _LOAD_CONST_INLINE_WITH_NULL : _LOAD_CONST_INLINE; | ||
| } | ||
| inst->operand = (uint64_t)res; | ||
| return res; | ||
| } | ||
| static int | ||
| @@ -529,12 +535,12 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, | ||
| break; | ||
| case _LOAD_GLOBAL_BUILTINS: | ||
| if (globals_checked & builtins_checked & globals_watched & builtins_watched & 1){ | ||
| global_to_const(inst, builtins); | ||
| convert_global_to_const(inst, builtins); | ||
| } | ||
| break; | ||
| case _LOAD_GLOBAL_MODULE: | ||
| if (globals_checked & globals_watched & 1){ | ||
| global_to_const(inst, globals); | ||
| convert_global_to_const(inst, globals); | ||
| } | ||
| break; | ||
| case _PUSH_FRAME: | ||
| @@ -608,7 +614,8 @@ uop_redundancy_eliminator( | ||
| PyCodeObject *co, | ||
| _PyUOpInstruction *trace, | ||
| int trace_len, | ||
| int curr_stacklen | ||
| int curr_stacklen, | ||
| _PyBloomFilter *dependencies | ||
| ) | ||
| { | ||
| @@ -670,7 +677,7 @@ remove_unneeded_uops(_PyUOpInstruction *buffer, int buffer_size) | ||
| * could error. _CHECK_VALIDITY is needed if the previous | ||
| * instruction could have escaped. */ | ||
| int last_set_ip = -1; | ||
| bool may_have_escaped = false; | ||
| bool may_have_escaped = true; | ||
markshannon marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page. | ||
| for (int pc = 0; pc < buffer_size; pc++){ | ||
| int opcode = buffer[pc].opcode; | ||
| switch (opcode){ | ||
| @@ -696,6 +703,22 @@ remove_unneeded_uops(_PyUOpInstruction *buffer, int buffer_size) | ||
| } | ||
| last_set_ip = pc; | ||
| break; | ||
| case _POP_TOP: | ||
markshannon marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page. | ||
| { | ||
| _PyUOpInstruction *last = &buffer[pc-1]; | ||
| while (last->opcode == _NOP){ | ||
| last--; | ||
| } | ||
| if (last->opcode == _LOAD_CONST_INLINE || | ||
| last->opcode == _LOAD_CONST_INLINE_BORROW || | ||
| last->opcode == _LOAD_FAST || | ||
| last->opcode == _COPY | ||
| ){ | ||
| last->opcode = _NOP; | ||
| buffer[pc].opcode = NOP; | ||
| } | ||
| break; | ||
| } | ||
| case _JUMP_TO_TOP: | ||
| case _EXIT_TRACE: | ||
| return; | ||
| @@ -709,9 +732,6 @@ remove_unneeded_uops(_PyUOpInstruction *buffer, int buffer_size) | ||
| if (_PyUop_Flags[opcode] & HAS_ERROR_FLAG){ | ||
| needs_ip = true; | ||
| } | ||
| if (opcode == _PUSH_FRAME){ | ||
| needs_ip = true; | ||
| } | ||
markshannon marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page. | ||
| 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; | ||
| @@ -796,7 +816,7 @@ _Py_uop_analyze_and_optimize( | ||
| err = uop_redundancy_eliminator( | ||
| (PyCodeObject *)frame->f_executable, buffer, | ||
| buffer_size, curr_stacklen); | ||
| buffer_size, curr_stacklen, dependencies); | ||
| if (err == 0){ | ||
| goto not_ready; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| #include "Python.h" | ||
| #include "pycore_uops.h" | ||
| #include "pycore_uop_ids.h" | ||
| #include "internal/pycore_moduleobject.h" | ||
| #define op(name, ...) /* NAME is ignored */ | ||
| @@ -79,11 +80,11 @@ dummy_func(void){ | ||
| op(_BINARY_OP_ADD_INT, (left, right -- res)){ | ||
| if (is_const(left) && is_const(right)){ | ||
| assert(PyLong_CheckExact(get_const(left))); | ||
| assert(PyLong_CheckExact(get_const(right))); | ||
| PyObject *temp = _PyLong_Add((PyLongObject *)get_const(left), | ||
| (PyLongObject *)get_const(right)); | ||
| if (sym_is_const(left) && sym_is_const(right)){ | ||
| assert(PyLong_CheckExact(sym_get_const(left))); | ||
| assert(PyLong_CheckExact(sym_get_const(right))); | ||
| PyObject *temp = _PyLong_Add((PyLongObject *)sym_get_const(left), | ||
| (PyLongObject *)sym_get_const(right)); | ||
| if (temp == NULL){ | ||
| goto error; | ||
| } | ||
| @@ -97,11 +98,11 @@ dummy_func(void){ | ||
| } | ||
| op(_BINARY_OP_SUBTRACT_INT, (left, right -- res)){ | ||
| if (is_const(left) && is_const(right)){ | ||
| assert(PyLong_CheckExact(get_const(left))); | ||
| assert(PyLong_CheckExact(get_const(right))); | ||
| PyObject *temp = _PyLong_Subtract((PyLongObject *)get_const(left), | ||
| (PyLongObject *)get_const(right)); | ||
| if (sym_is_const(left) && sym_is_const(right)){ | ||
| assert(PyLong_CheckExact(sym_get_const(left))); | ||
| assert(PyLong_CheckExact(sym_get_const(right))); | ||
| PyObject *temp = _PyLong_Subtract((PyLongObject *)sym_get_const(left), | ||
| (PyLongObject *)sym_get_const(right)); | ||
| if (temp == NULL){ | ||
| goto error; | ||
| } | ||
| @@ -115,11 +116,11 @@ dummy_func(void){ | ||
| } | ||
| op(_BINARY_OP_MULTIPLY_INT, (left, right -- res)){ | ||
| if (is_const(left) && is_const(right)){ | ||
| assert(PyLong_CheckExact(get_const(left))); | ||
| assert(PyLong_CheckExact(get_const(right))); | ||
| PyObject *temp = _PyLong_Multiply((PyLongObject *)get_const(left), | ||
| (PyLongObject *)get_const(right)); | ||
| if (sym_is_const(left) && sym_is_const(right)){ | ||
| assert(PyLong_CheckExact(sym_get_const(left))); | ||
| assert(PyLong_CheckExact(sym_get_const(right))); | ||
| PyObject *temp = _PyLong_Multiply((PyLongObject *)sym_get_const(left), | ||
| (PyLongObject *)sym_get_const(right)); | ||
| if (temp == NULL){ | ||
| goto error; | ||
| } | ||
| @@ -133,12 +134,12 @@ dummy_func(void){ | ||
| } | ||
| op(_BINARY_OP_ADD_FLOAT, (left, right -- res)){ | ||
| if (is_const(left) && is_const(right)){ | ||
| assert(PyFloat_CheckExact(get_const(left))); | ||
| assert(PyFloat_CheckExact(get_const(right))); | ||
| if (sym_is_const(left) && sym_is_const(right)){ | ||
| assert(PyFloat_CheckExact(sym_get_const(left))); | ||
| assert(PyFloat_CheckExact(sym_get_const(right))); | ||
| PyObject *temp = PyFloat_FromDouble( | ||
| PyFloat_AS_DOUBLE(get_const(left)) + | ||
| PyFloat_AS_DOUBLE(get_const(right))); | ||
| PyFloat_AS_DOUBLE(sym_get_const(left)) + | ||
| PyFloat_AS_DOUBLE(sym_get_const(right))); | ||
| if (temp == NULL){ | ||
| goto error; | ||
| } | ||
| @@ -152,12 +153,12 @@ dummy_func(void){ | ||
| } | ||
| op(_BINARY_OP_SUBTRACT_FLOAT, (left, right -- res)){ | ||
| if (is_const(left) && is_const(right)){ | ||
| assert(PyFloat_CheckExact(get_const(left))); | ||
| assert(PyFloat_CheckExact(get_const(right))); | ||
| if (sym_is_const(left) && sym_is_const(right)){ | ||
| assert(PyFloat_CheckExact(sym_get_const(left))); | ||
| assert(PyFloat_CheckExact(sym_get_const(right))); | ||
| PyObject *temp = PyFloat_FromDouble( | ||
| PyFloat_AS_DOUBLE(get_const(left)) - | ||
| PyFloat_AS_DOUBLE(get_const(right))); | ||
| PyFloat_AS_DOUBLE(sym_get_const(left)) - | ||
| PyFloat_AS_DOUBLE(sym_get_const(right))); | ||
| if (temp == NULL){ | ||
| goto error; | ||
| } | ||
| @@ -171,12 +172,12 @@ dummy_func(void){ | ||
| } | ||
| op(_BINARY_OP_MULTIPLY_FLOAT, (left, right -- res)){ | ||
| if (is_const(left) && is_const(right)){ | ||
| assert(PyFloat_CheckExact(get_const(left))); | ||
| assert(PyFloat_CheckExact(get_const(right))); | ||
| if (sym_is_const(left) && sym_is_const(right)){ | ||
| assert(PyFloat_CheckExact(sym_get_const(left))); | ||
| assert(PyFloat_CheckExact(sym_get_const(right))); | ||
| PyObject *temp = PyFloat_FromDouble( | ||
| PyFloat_AS_DOUBLE(get_const(left)) * | ||
| PyFloat_AS_DOUBLE(get_const(right))); | ||
| PyFloat_AS_DOUBLE(sym_get_const(left)) * | ||
| PyFloat_AS_DOUBLE(sym_get_const(right))); | ||
| if (temp == NULL){ | ||
| goto error; | ||
| } | ||
| @@ -229,10 +230,43 @@ dummy_func(void){ | ||
| (void)owner; | ||
| } | ||
| op(_CHECK_ATTR_MODULE, (dict_version/2, owner -- owner)){ | ||
| (void)dict_version; | ||
| if (sym_is_const(owner)){ | ||
| PyObject *cnst = sym_get_const(owner); | ||
| if (PyModule_CheckExact(cnst)){ | ||
| PyModuleObject *mod = (PyModuleObject *)cnst; | ||
| PyObject *dict = mod->md_dict; | ||
| uint64_t watched_mutations = get_mutations(dict); | ||
| if (watched_mutations < _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS){ | ||
| PyDict_Watch(GLOBALS_WATCHER_ID, dict); | ||
markshannon marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page. | ||
| _Py_BloomFilter_Add(dependencies, dict); | ||
| this_instr->opcode = _NOP; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| op(_LOAD_ATTR_MODULE, (index/1, owner -- attr, null if (oparg & 1))){ | ||
| _LOAD_ATTR_NOT_NULL | ||
| (void)index; | ||
| (void)owner; | ||
| OUT_OF_SPACE_IF_NULL(null = sym_new_null(ctx)); | ||
| attr = NULL; | ||
| if (this_instr[-1].opcode == _NOP){ | ||
markshannon marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page. | ||
| // Preceding _CHECK_ATTR_MODULE was removed: mod is const and dict is watched. | ||
| assert(sym_is_const(owner)); | ||
| PyModuleObject *mod = (PyModuleObject *)sym_get_const(owner); | ||
| assert(PyModule_CheckExact(mod)); | ||
| PyObject *dict = mod->md_dict; | ||
| PyObject *res = convert_global_to_const(this_instr, dict); | ||
| if (res != NULL){ | ||
| this_instr[-1].opcode = _POP_TOP; | ||
markshannon marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page.
markshannon marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page. | ||
| OUT_OF_SPACE_IF_NULL(attr = sym_new_const(ctx, res)); | ||
| } | ||
| } | ||
| if (attr == NULL){ | ||
markshannon marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page. | ||
| /* No conversion made. We don't know what `attr` is. */ | ||
| OUT_OF_SPACE_IF_NULL(attr = sym_new_known_notnull(ctx)); | ||
| } | ||
| } | ||
| op(_LOAD_ATTR_WITH_HINT, (hint/1, owner -- attr, null if (oparg & 1))){ | ||
| @@ -339,4 +373,4 @@ dummy_func(void){ | ||
| // END BYTECODES // | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.