gh-104909: Split some more insts into ops (#109943)

These are the most popular specializations of `LOAD_ATTR` and `STORE_ATTR`
that weren't already viable uops:

* Split LOAD_ATTR_METHOD_WITH_VALUES
* Split LOAD_ATTR_METHOD_NO_DICT
* Split LOAD_ATTR_SLOT
* Split STORE_ATTR_SLOT
* Split STORE_ATTR_INSTANCE_VALUE

Also:

* Add `-v` flag to code generator which prints a list of non-viable uops
  (easter-egg: it can print execution counts -- see source)
* Double _Py_UOP_MAX_TRACE_LENGTH to 128



I had dropped one of the DEOPT_IF() calls! :-(
This commit is contained in:
Guido van Rossum 2023-09-27 15:27:44 -07:00 committed by GitHub
parent 45cf5b0c69
commit 5bb6f0fcba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 519 additions and 115 deletions

View file

@ -1714,6 +1714,83 @@
break;
}
case _LOAD_ATTR_SLOT: {
PyObject *owner;
PyObject *attr;
PyObject *null = NULL;
owner = stack_pointer[-1];
uint16_t index = (uint16_t)operand;
char *addr = (char *)owner + index;
attr = *(PyObject **)addr;
DEOPT_IF(attr == NULL, LOAD_ATTR);
STAT_INC(LOAD_ATTR, hit);
Py_INCREF(attr);
null = NULL;
Py_DECREF(owner);
STACK_GROW(((oparg & 1) ? 1 : 0));
stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr;
if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; }
break;
}
case _GUARD_DORV_VALUES: {
PyObject *owner;
owner = stack_pointer[-1];
PyTypeObject *tp = Py_TYPE(owner);
assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
DEOPT_IF(!_PyDictOrValues_IsValues(dorv), STORE_ATTR);
break;
}
case _STORE_ATTR_INSTANCE_VALUE: {
PyObject *owner;
PyObject *value;
owner = stack_pointer[-1];
value = stack_pointer[-2];
uint16_t index = (uint16_t)operand;
PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
STAT_INC(STORE_ATTR, hit);
PyDictValues *values = _PyDictOrValues_GetValues(dorv);
PyObject *old_value = values->values[index];
values->values[index] = value;
if (old_value == NULL) {
_PyDictValues_AddToInsertionOrder(values, index);
}
else {
Py_DECREF(old_value);
}
Py_DECREF(owner);
STACK_SHRINK(2);
break;
}
case _GUARD_TYPE_VERSION_STORE: {
PyObject *owner;
owner = stack_pointer[-1];
uint32_t type_version = (uint32_t)operand;
PyTypeObject *tp = Py_TYPE(owner);
assert(type_version != 0);
DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
break;
}
case _STORE_ATTR_SLOT: {
PyObject *owner;
PyObject *value;
owner = stack_pointer[-1];
value = stack_pointer[-2];
uint16_t index = (uint16_t)operand;
char *addr = (char *)owner + index;
STAT_INC(STORE_ATTR, hit);
PyObject *old_value = *(PyObject **)addr;
*(PyObject **)addr = value;
Py_XDECREF(old_value);
Py_DECREF(owner);
STACK_SHRINK(2);
break;
}
case COMPARE_OP: {
PyObject *right;
PyObject *left;
@ -2219,6 +2296,68 @@
break;
}
case _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT: {
PyObject *owner;
owner = stack_pointer[-1];
PyTypeObject *owner_cls = Py_TYPE(owner);
assert(owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT);
PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner);
DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) &&
!_PyObject_MakeInstanceAttributesFromDict(owner, dorv),
LOAD_ATTR);
break;
}
case _GUARD_KEYS_VERSION: {
PyObject *owner;
owner = stack_pointer[-1];
uint32_t keys_version = (uint32_t)operand;
PyTypeObject *owner_cls = Py_TYPE(owner);
PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls;
DEOPT_IF(owner_heap_type->ht_cached_keys->dk_version !=
keys_version, LOAD_ATTR);
break;
}
case _LOAD_ATTR_METHOD_WITH_VALUES: {
PyObject *owner;
PyObject *attr;
PyObject *self;
owner = stack_pointer[-1];
PyObject *descr = (PyObject *)operand;
assert(oparg & 1);
/* Cached method object */
STAT_INC(LOAD_ATTR, hit);
assert(descr != NULL);
attr = Py_NewRef(descr);
assert(_PyType_HasFeature(Py_TYPE(attr), Py_TPFLAGS_METHOD_DESCRIPTOR));
self = owner;
STACK_GROW(1);
stack_pointer[-2] = attr;
stack_pointer[-1] = self;
break;
}
case _LOAD_ATTR_METHOD_NO_DICT: {
PyObject *owner;
PyObject *attr;
PyObject *self;
owner = stack_pointer[-1];
PyObject *descr = (PyObject *)operand;
assert(oparg & 1);
PyTypeObject *owner_cls = Py_TYPE(owner);
assert(owner_cls->tp_dictoffset == 0);
STAT_INC(LOAD_ATTR, hit);
assert(descr != NULL);
assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR));
attr = Py_NewRef(descr);
self = owner;
STACK_GROW(1);
stack_pointer[-2] = attr;
stack_pointer[-1] = self;
break;
}
case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS: {
PyObject *null;
PyObject *callable;