summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Include/internal/pycore_opcode_metadata.h120
-rw-r--r--Include/internal/pycore_uops.h2
-rw-r--r--Python/abstract_interp_cases.c.h47
-rw-r--r--Python/bytecodes.c66
-rw-r--r--Python/executor_cases.c.h139
-rw-r--r--Python/generated_cases.c.h191
-rw-r--r--Tools/cases_generator/analysis.py58
-rw-r--r--Tools/cases_generator/generate_cases.py11
8 files changed, 519 insertions, 115 deletions
diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h
index bb37e9a..16c1637 100644
--- a/Include/internal/pycore_opcode_metadata.h
+++ b/Include/internal/pycore_opcode_metadata.h
@@ -46,31 +46,40 @@
#define _GUARD_TYPE_VERSION 318
#define _CHECK_MANAGED_OBJECT_HAS_VALUES 319
#define _LOAD_ATTR_INSTANCE_VALUE 320
-#define _IS_NONE 321
-#define _ITER_CHECK_LIST 322
-#define _ITER_JUMP_LIST 323
-#define _IS_ITER_EXHAUSTED_LIST 324
-#define _ITER_NEXT_LIST 325
-#define _ITER_CHECK_TUPLE 326
-#define _ITER_JUMP_TUPLE 327
-#define _IS_ITER_EXHAUSTED_TUPLE 328
-#define _ITER_NEXT_TUPLE 329
-#define _ITER_CHECK_RANGE 330
-#define _ITER_JUMP_RANGE 331
-#define _IS_ITER_EXHAUSTED_RANGE 332
-#define _ITER_NEXT_RANGE 333
-#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 334
-#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 335
-#define _CHECK_PEP_523 336
-#define _CHECK_FUNCTION_EXACT_ARGS 337
-#define _CHECK_STACK_SPACE 338
-#define _INIT_CALL_PY_EXACT_ARGS 339
-#define _PUSH_FRAME 340
-#define _POP_JUMP_IF_FALSE 341
-#define _POP_JUMP_IF_TRUE 342
-#define _JUMP_TO_TOP 343
-#define _SAVE_CURRENT_IP 344
-#define _INSERT 345
+#define _LOAD_ATTR_SLOT 321
+#define _GUARD_DORV_VALUES 322
+#define _STORE_ATTR_INSTANCE_VALUE 323
+#define _GUARD_TYPE_VERSION_STORE 324
+#define _STORE_ATTR_SLOT 325
+#define _IS_NONE 326
+#define _ITER_CHECK_LIST 327
+#define _ITER_JUMP_LIST 328
+#define _IS_ITER_EXHAUSTED_LIST 329
+#define _ITER_NEXT_LIST 330
+#define _ITER_CHECK_TUPLE 331
+#define _ITER_JUMP_TUPLE 332
+#define _IS_ITER_EXHAUSTED_TUPLE 333
+#define _ITER_NEXT_TUPLE 334
+#define _ITER_CHECK_RANGE 335
+#define _ITER_JUMP_RANGE 336
+#define _IS_ITER_EXHAUSTED_RANGE 337
+#define _ITER_NEXT_RANGE 338
+#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 339
+#define _GUARD_KEYS_VERSION 340
+#define _LOAD_ATTR_METHOD_WITH_VALUES 341
+#define _LOAD_ATTR_METHOD_NO_DICT 342
+#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 343
+#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 344
+#define _CHECK_PEP_523 345
+#define _CHECK_FUNCTION_EXACT_ARGS 346
+#define _CHECK_STACK_SPACE 347
+#define _INIT_CALL_PY_EXACT_ARGS 348
+#define _PUSH_FRAME 349
+#define _POP_JUMP_IF_FALSE 350
+#define _POP_JUMP_IF_TRUE 351
+#define _JUMP_TO_TOP 352
+#define _SAVE_CURRENT_IP 353
+#define _INSERT 354
extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump);
#ifdef NEED_OPCODE_METADATA
@@ -356,6 +365,8 @@ int _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
return 1;
case LOAD_ATTR_WITH_HINT:
return 1;
+ case _LOAD_ATTR_SLOT:
+ return 1;
case LOAD_ATTR_SLOT:
return 1;
case LOAD_ATTR_CLASS:
@@ -364,10 +375,18 @@ int _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
return 1;
case LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN:
return 1;
+ case _GUARD_DORV_VALUES:
+ return 1;
+ case _STORE_ATTR_INSTANCE_VALUE:
+ return 2;
case STORE_ATTR_INSTANCE_VALUE:
return 2;
case STORE_ATTR_WITH_HINT:
return 2;
+ case _GUARD_TYPE_VERSION_STORE:
+ return 1;
+ case _STORE_ATTR_SLOT:
+ return 2;
case STORE_ATTR_SLOT:
return 2;
case COMPARE_OP:
@@ -478,8 +497,16 @@ int _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
return 0;
case PUSH_EXC_INFO:
return 1;
+ case _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT:
+ return 1;
+ case _GUARD_KEYS_VERSION:
+ return 1;
+ case _LOAD_ATTR_METHOD_WITH_VALUES:
+ return 1;
case LOAD_ATTR_METHOD_WITH_VALUES:
return 1;
+ case _LOAD_ATTR_METHOD_NO_DICT:
+ return 1;
case LOAD_ATTR_METHOD_NO_DICT:
return 1;
case LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES:
@@ -896,18 +923,28 @@ int _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
return ((oparg & 1) ? 1 : 0) + 1;
case LOAD_ATTR_WITH_HINT:
return ((oparg & 1) ? 1 : 0) + 1;
- case LOAD_ATTR_SLOT:
+ case _LOAD_ATTR_SLOT:
return ((oparg & 1) ? 1 : 0) + 1;
+ case LOAD_ATTR_SLOT:
+ return (oparg & 1 ? 1 : 0) + 1;
case LOAD_ATTR_CLASS:
return ((oparg & 1) ? 1 : 0) + 1;
case LOAD_ATTR_PROPERTY:
return 1;
case LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN:
return 1;
+ case _GUARD_DORV_VALUES:
+ return 1;
+ case _STORE_ATTR_INSTANCE_VALUE:
+ return 0;
case STORE_ATTR_INSTANCE_VALUE:
return 0;
case STORE_ATTR_WITH_HINT:
return 0;
+ case _GUARD_TYPE_VERSION_STORE:
+ return 1;
+ case _STORE_ATTR_SLOT:
+ return 0;
case STORE_ATTR_SLOT:
return 0;
case COMPARE_OP:
@@ -1018,8 +1055,16 @@ int _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
return 0;
case PUSH_EXC_INFO:
return 2;
+ case _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT:
+ return 1;
+ case _GUARD_KEYS_VERSION:
+ return 1;
+ case _LOAD_ATTR_METHOD_WITH_VALUES:
+ return 2;
case LOAD_ATTR_METHOD_WITH_VALUES:
return 2;
+ case _LOAD_ATTR_METHOD_NO_DICT:
+ return 2;
case LOAD_ATTR_METHOD_NO_DICT:
return 2;
case LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES:
@@ -1359,12 +1404,17 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = {
[LOAD_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG },
[LOAD_ATTR_MODULE] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG },
[LOAD_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG },
+ [_LOAD_ATTR_SLOT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG },
[LOAD_ATTR_SLOT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG },
[LOAD_ATTR_CLASS] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG },
[LOAD_ATTR_PROPERTY] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG },
[LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG },
+ [_GUARD_DORV_VALUES] = { true, INSTR_FMT_IX, HAS_DEOPT_FLAG },
+ [_STORE_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IXC, 0 },
[STORE_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IXC000, HAS_DEOPT_FLAG },
[STORE_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG },
+ [_GUARD_TYPE_VERSION_STORE] = { true, INSTR_FMT_IXC0, HAS_DEOPT_FLAG },
+ [_STORE_ATTR_SLOT] = { true, INSTR_FMT_IXC, 0 },
[STORE_ATTR_SLOT] = { true, INSTR_FMT_IXC000, HAS_DEOPT_FLAG },
[COMPARE_OP] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_ERROR_FLAG },
[COMPARE_OP_FLOAT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG },
@@ -1420,7 +1470,11 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = {
[SETUP_WITH] = { true, INSTR_FMT_IX, 0 },
[POP_BLOCK] = { true, INSTR_FMT_IX, 0 },
[PUSH_EXC_INFO] = { true, INSTR_FMT_IX, 0 },
+ [_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT] = { true, INSTR_FMT_IX, HAS_DEOPT_FLAG },
+ [_GUARD_KEYS_VERSION] = { true, INSTR_FMT_IXC0, HAS_DEOPT_FLAG },
+ [_LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG },
[LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG },
+ [_LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG },
[LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG },
[LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG },
[LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG },
@@ -1583,6 +1637,9 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN
[LOAD_SUPER_ATTR_METHOD] = { .nuops = 1, .uops = { { LOAD_SUPER_ATTR_METHOD, 0, 0 } } },
[LOAD_ATTR] = { .nuops = 1, .uops = { { LOAD_ATTR, 0, 0 } } },
[LOAD_ATTR_INSTANCE_VALUE] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_MANAGED_OBJECT_HAS_VALUES, 0, 0 }, { _LOAD_ATTR_INSTANCE_VALUE, 1, 3 } } },
+ [LOAD_ATTR_SLOT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_SLOT, 1, 3 } } },
+ [STORE_ATTR_INSTANCE_VALUE] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION_STORE, 2, 1 }, { _GUARD_DORV_VALUES, 0, 0 }, { _STORE_ATTR_INSTANCE_VALUE, 1, 3 } } },
+ [STORE_ATTR_SLOT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION_STORE, 2, 1 }, { _STORE_ATTR_SLOT, 1, 3 } } },
[COMPARE_OP] = { .nuops = 1, .uops = { { COMPARE_OP, 0, 0 } } },
[COMPARE_OP_FLOAT] = { .nuops = 1, .uops = { { COMPARE_OP_FLOAT, 0, 0 } } },
[COMPARE_OP_INT] = { .nuops = 1, .uops = { { COMPARE_OP_INT, 0, 0 } } },
@@ -1600,6 +1657,8 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN
[GET_YIELD_FROM_ITER] = { .nuops = 1, .uops = { { GET_YIELD_FROM_ITER, 0, 0 } } },
[WITH_EXCEPT_START] = { .nuops = 1, .uops = { { WITH_EXCEPT_START, 0, 0 } } },
[PUSH_EXC_INFO] = { .nuops = 1, .uops = { { PUSH_EXC_INFO, 0, 0 } } },
+ [LOAD_ATTR_METHOD_WITH_VALUES] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, 0, 0 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_METHOD_WITH_VALUES, 4, 5 } } },
+ [LOAD_ATTR_METHOD_NO_DICT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_METHOD_NO_DICT, 4, 5 } } },
[CALL_BOUND_METHOD_EXACT_ARGS] = { .nuops = 9, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_CALL_BOUND_METHOD_EXACT_ARGS, 0, 0 }, { _INIT_CALL_BOUND_METHOD_EXACT_ARGS, 0, 0 }, { _CHECK_FUNCTION_EXACT_ARGS, 2, 1 }, { _CHECK_STACK_SPACE, 0, 0 }, { _INIT_CALL_PY_EXACT_ARGS, 0, 0 }, { _SET_IP, 7, 3 }, { _SAVE_CURRENT_IP, 0, 0 }, { _PUSH_FRAME, 0, 0 } } },
[CALL_PY_EXACT_ARGS] = { .nuops = 7, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_FUNCTION_EXACT_ARGS, 2, 1 }, { _CHECK_STACK_SPACE, 0, 0 }, { _INIT_CALL_PY_EXACT_ARGS, 0, 0 }, { _SET_IP, 7, 3 }, { _SAVE_CURRENT_IP, 0, 0 }, { _PUSH_FRAME, 0, 0 } } },
[CALL_TYPE_1] = { .nuops = 1, .uops = { { CALL_TYPE_1, 0, 0 } } },
@@ -1652,6 +1711,11 @@ const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE] = {
[_GUARD_TYPE_VERSION] = "_GUARD_TYPE_VERSION",
[_CHECK_MANAGED_OBJECT_HAS_VALUES] = "_CHECK_MANAGED_OBJECT_HAS_VALUES",
[_LOAD_ATTR_INSTANCE_VALUE] = "_LOAD_ATTR_INSTANCE_VALUE",
+ [_LOAD_ATTR_SLOT] = "_LOAD_ATTR_SLOT",
+ [_GUARD_DORV_VALUES] = "_GUARD_DORV_VALUES",
+ [_STORE_ATTR_INSTANCE_VALUE] = "_STORE_ATTR_INSTANCE_VALUE",
+ [_GUARD_TYPE_VERSION_STORE] = "_GUARD_TYPE_VERSION_STORE",
+ [_STORE_ATTR_SLOT] = "_STORE_ATTR_SLOT",
[_IS_NONE] = "_IS_NONE",
[_ITER_CHECK_LIST] = "_ITER_CHECK_LIST",
[_ITER_JUMP_LIST] = "_ITER_JUMP_LIST",
@@ -1665,6 +1729,10 @@ const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE] = {
[_ITER_JUMP_RANGE] = "_ITER_JUMP_RANGE",
[_IS_ITER_EXHAUSTED_RANGE] = "_IS_ITER_EXHAUSTED_RANGE",
[_ITER_NEXT_RANGE] = "_ITER_NEXT_RANGE",
+ [_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT] = "_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT",
+ [_GUARD_KEYS_VERSION] = "_GUARD_KEYS_VERSION",
+ [_LOAD_ATTR_METHOD_WITH_VALUES] = "_LOAD_ATTR_METHOD_WITH_VALUES",
+ [_LOAD_ATTR_METHOD_NO_DICT] = "_LOAD_ATTR_METHOD_NO_DICT",
[_CHECK_CALL_BOUND_METHOD_EXACT_ARGS] = "_CHECK_CALL_BOUND_METHOD_EXACT_ARGS",
[_INIT_CALL_BOUND_METHOD_EXACT_ARGS] = "_INIT_CALL_BOUND_METHOD_EXACT_ARGS",
[_CHECK_PEP_523] = "_CHECK_PEP_523",
diff --git a/Include/internal/pycore_uops.h b/Include/internal/pycore_uops.h
index 249f5c0..d8a7d97 100644
--- a/Include/internal/pycore_uops.h
+++ b/Include/internal/pycore_uops.h
@@ -10,7 +10,7 @@ extern "C" {
#include "pycore_frame.h" // _PyInterpreterFrame
-#define _Py_UOP_MAX_TRACE_LENGTH 64
+#define _Py_UOP_MAX_TRACE_LENGTH 128
typedef struct {
uint32_t opcode;
diff --git a/Python/abstract_interp_cases.c.h b/Python/abstract_interp_cases.c.h
index 5a3848c..61b1db9 100644
--- a/Python/abstract_interp_cases.c.h
+++ b/Python/abstract_interp_cases.c.h
@@ -474,6 +474,31 @@
break;
}
+ case _LOAD_ATTR_SLOT: {
+ STACK_GROW(((oparg & 1) ? 1 : 0));
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1 - (oparg & 1 ? 1 : 0))), true);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-(oparg & 1 ? 1 : 0))), true);
+ break;
+ }
+
+ case _GUARD_DORV_VALUES: {
+ break;
+ }
+
+ case _STORE_ATTR_INSTANCE_VALUE: {
+ STACK_SHRINK(2);
+ break;
+ }
+
+ case _GUARD_TYPE_VERSION_STORE: {
+ break;
+ }
+
+ case _STORE_ATTR_SLOT: {
+ STACK_SHRINK(2);
+ break;
+ }
+
case COMPARE_OP: {
STACK_SHRINK(1);
PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
@@ -627,6 +652,28 @@
break;
}
+ case _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT: {
+ break;
+ }
+
+ case _GUARD_KEYS_VERSION: {
+ break;
+ }
+
+ case _LOAD_ATTR_METHOD_WITH_VALUES: {
+ STACK_GROW(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-2)), true);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case _LOAD_ATTR_METHOD_NO_DICT: {
+ STACK_GROW(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-2)), true);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS: {
break;
}
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index 402b271..0f89779 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -1939,10 +1939,7 @@ dummy_func(
DECREF_INPUTS();
}
- inst(LOAD_ATTR_SLOT, (unused/1, type_version/2, index/1, unused/5, owner -- attr, null if (oparg & 1))) {
- PyTypeObject *tp = Py_TYPE(owner);
- assert(type_version != 0);
- DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
+ op(_LOAD_ATTR_SLOT, (index/1, owner -- attr, null if (oparg & 1))) {
char *addr = (char *)owner + index;
attr = *(PyObject **)addr;
DEOPT_IF(attr == NULL, LOAD_ATTR);
@@ -1952,6 +1949,12 @@ dummy_func(
DECREF_INPUTS();
}
+ macro(LOAD_ATTR_SLOT) =
+ unused/1 +
+ _GUARD_TYPE_VERSION +
+ _LOAD_ATTR_SLOT + // NOTE: This action may also deopt
+ unused/5;
+
inst(LOAD_ATTR_CLASS, (unused/1, type_version/2, unused/2, descr/4, owner -- attr, null if (oparg & 1))) {
DEOPT_IF(!PyType_Check(owner), LOAD_ATTR);
@@ -2019,13 +2022,15 @@ dummy_func(
DISPATCH_INLINED(new_frame);
}
- inst(STORE_ATTR_INSTANCE_VALUE, (unused/1, type_version/2, index/1, value, owner --)) {
+ op(_GUARD_DORV_VALUES, (owner -- owner)) {
PyTypeObject *tp = Py_TYPE(owner);
- assert(type_version != 0);
- DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
DEOPT_IF(!_PyDictOrValues_IsValues(dorv), STORE_ATTR);
+ }
+
+ op(_STORE_ATTR_INSTANCE_VALUE, (index/1, value, owner --)) {
+ PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
STAT_INC(STORE_ATTR, hit);
PyDictValues *values = _PyDictOrValues_GetValues(dorv);
PyObject *old_value = values->values[index];
@@ -2039,6 +2044,12 @@ dummy_func(
Py_DECREF(owner);
}
+ macro(STORE_ATTR_INSTANCE_VALUE) =
+ unused/1 +
+ _GUARD_TYPE_VERSION_STORE +
+ _GUARD_DORV_VALUES +
+ _STORE_ATTR_INSTANCE_VALUE;
+
inst(STORE_ATTR_WITH_HINT, (unused/1, type_version/2, hint/1, value, owner --)) {
PyTypeObject *tp = Py_TYPE(owner);
assert(type_version != 0);
@@ -2080,10 +2091,13 @@ dummy_func(
Py_DECREF(owner);
}
- inst(STORE_ATTR_SLOT, (unused/1, type_version/2, index/1, value, owner --)) {
+ op(_GUARD_TYPE_VERSION_STORE, (type_version/2, owner -- owner)) {
PyTypeObject *tp = Py_TYPE(owner);
assert(type_version != 0);
DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
+ }
+
+ op(_STORE_ATTR_SLOT, (index/1, value, owner --)) {
char *addr = (char *)owner + index;
STAT_INC(STORE_ATTR, hit);
PyObject *old_value = *(PyObject **)addr;
@@ -2092,6 +2106,11 @@ dummy_func(
Py_DECREF(owner);
}
+ macro(STORE_ATTR_SLOT) =
+ unused/1 +
+ _GUARD_TYPE_VERSION_STORE +
+ _STORE_ATTR_SLOT;
+
family(COMPARE_OP, INLINE_CACHE_ENTRIES_COMPARE_OP) = {
COMPARE_OP_FLOAT,
COMPARE_OP_INT,
@@ -2769,20 +2788,25 @@ dummy_func(
exc_info->exc_value = Py_NewRef(new_exc);
}
- inst(LOAD_ATTR_METHOD_WITH_VALUES, (unused/1, type_version/2, keys_version/2, descr/4, owner -- attr, self if (1))) {
- assert(oparg & 1);
- /* Cached method object */
+ op(_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, (owner -- owner)) {
PyTypeObject *owner_cls = Py_TYPE(owner);
- assert(type_version != 0);
- DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR);
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);
+ }
+
+ op(_GUARD_KEYS_VERSION, (keys_version/2, owner -- owner)) {
+ 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);
+ }
+
+ op(_LOAD_ATTR_METHOD_WITH_VALUES, (descr/4, owner -- attr, self if (1))) {
+ assert(oparg & 1);
+ /* Cached method object */
STAT_INC(LOAD_ATTR, hit);
assert(descr != NULL);
attr = Py_NewRef(descr);
@@ -2790,10 +2814,16 @@ dummy_func(
self = owner;
}
- inst(LOAD_ATTR_METHOD_NO_DICT, (unused/1, type_version/2, unused/2, descr/4, owner -- attr, self if (1))) {
+ macro(LOAD_ATTR_METHOD_WITH_VALUES) =
+ unused/1 +
+ _GUARD_TYPE_VERSION +
+ _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT +
+ _GUARD_KEYS_VERSION +
+ _LOAD_ATTR_METHOD_WITH_VALUES;
+
+ op(_LOAD_ATTR_METHOD_NO_DICT, (descr/4, owner -- attr, self if (1))) {
assert(oparg & 1);
PyTypeObject *owner_cls = Py_TYPE(owner);
- DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR);
assert(owner_cls->tp_dictoffset == 0);
STAT_INC(LOAD_ATTR, hit);
assert(descr != NULL);
@@ -2802,6 +2832,12 @@ dummy_func(
self = owner;
}
+ macro(LOAD_ATTR_METHOD_NO_DICT) =
+ unused/1 +
+ _GUARD_TYPE_VERSION +
+ unused/2 +
+ _LOAD_ATTR_METHOD_NO_DICT;
+
inst(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, (unused/1, type_version/2, keys_version/2, descr/4, owner -- attr, unused if (0))) {
assert((oparg & 1) == 0);
PyTypeObject *owner_cls = Py_TYPE(owner);
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h
index befb972..981db69 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -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;
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index ebb87a8..17df440 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -2504,19 +2504,25 @@
PyObject *owner;
PyObject *attr;
PyObject *null = NULL;
+ // _GUARD_TYPE_VERSION
owner = stack_pointer[-1];
- uint32_t type_version = read_u32(&next_instr[1].cache);
- uint16_t index = read_u16(&next_instr[3].cache);
- PyTypeObject *tp = Py_TYPE(owner);
- assert(type_version != 0);
- DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
- 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);
+ {
+ uint32_t type_version = read_u32(&next_instr[1].cache);
+ PyTypeObject *tp = Py_TYPE(owner);
+ assert(type_version != 0);
+ DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
+ }
+ // _LOAD_ATTR_SLOT
+ {
+ uint16_t index = read_u16(&next_instr[3].cache);
+ 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; }
@@ -2615,27 +2621,38 @@
TARGET(STORE_ATTR_INSTANCE_VALUE) {
PyObject *owner;
PyObject *value;
+ // _GUARD_TYPE_VERSION_STORE
owner = stack_pointer[-1];
- value = stack_pointer[-2];
- uint32_t type_version = read_u32(&next_instr[1].cache);
- uint16_t index = read_u16(&next_instr[3].cache);
- PyTypeObject *tp = Py_TYPE(owner);
- assert(type_version != 0);
- DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
- assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
- DEOPT_IF(!_PyDictOrValues_IsValues(dorv), STORE_ATTR);
- 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);
+ {
+ uint32_t type_version = read_u32(&next_instr[1].cache);
+ PyTypeObject *tp = Py_TYPE(owner);
+ assert(type_version != 0);
+ DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
}
- else {
- Py_DECREF(old_value);
+ // _GUARD_DORV_VALUES
+ {
+ 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);
+ }
+ // _STORE_ATTR_INSTANCE_VALUE
+ value = stack_pointer[-2];
+ {
+ uint16_t index = read_u16(&next_instr[3].cache);
+ 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);
}
- Py_DECREF(owner);
STACK_SHRINK(2);
next_instr += 4;
DISPATCH();
@@ -2694,19 +2711,25 @@
TARGET(STORE_ATTR_SLOT) {
PyObject *owner;
PyObject *value;
+ // _GUARD_TYPE_VERSION_STORE
owner = stack_pointer[-1];
+ {
+ uint32_t type_version = read_u32(&next_instr[1].cache);
+ PyTypeObject *tp = Py_TYPE(owner);
+ assert(type_version != 0);
+ DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
+ }
+ // _STORE_ATTR_SLOT
value = stack_pointer[-2];
- uint32_t type_version = read_u32(&next_instr[1].cache);
- uint16_t index = read_u16(&next_instr[3].cache);
- PyTypeObject *tp = Py_TYPE(owner);
- assert(type_version != 0);
- DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
- 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);
+ {
+ uint16_t index = read_u16(&next_instr[3].cache);
+ 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);
next_instr += 4;
DISPATCH();
@@ -3557,28 +3580,42 @@
PyObject *owner;
PyObject *attr;
PyObject *self;
+ // _GUARD_TYPE_VERSION
owner = stack_pointer[-1];
- uint32_t type_version = read_u32(&next_instr[1].cache);
- uint32_t keys_version = read_u32(&next_instr[3].cache);
- PyObject *descr = read_obj(&next_instr[5].cache);
- assert(oparg & 1);
- /* Cached method object */
- PyTypeObject *owner_cls = Py_TYPE(owner);
- assert(type_version != 0);
- DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR);
- 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);
- PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls;
- DEOPT_IF(owner_heap_type->ht_cached_keys->dk_version !=
- keys_version, LOAD_ATTR);
- STAT_INC(LOAD_ATTR, hit);
- assert(descr != NULL);
- attr = Py_NewRef(descr);
- assert(_PyType_HasFeature(Py_TYPE(attr), Py_TPFLAGS_METHOD_DESCRIPTOR));
- self = owner;
+ {
+ uint32_t type_version = read_u32(&next_instr[1].cache);
+ PyTypeObject *tp = Py_TYPE(owner);
+ assert(type_version != 0);
+ DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
+ }
+ // _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT
+ {
+ 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);
+ }
+ // _GUARD_KEYS_VERSION
+ {
+ uint32_t keys_version = read_u32(&next_instr[3].cache);
+ 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);
+ }
+ // _LOAD_ATTR_METHOD_WITH_VALUES
+ {
+ PyObject *descr = read_obj(&next_instr[5].cache);
+ 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;
@@ -3590,18 +3627,26 @@
PyObject *owner;
PyObject *attr;
PyObject *self;
+ // _GUARD_TYPE_VERSION
owner = stack_pointer[-1];
- uint32_t type_version = read_u32(&next_instr[1].cache);
- PyObject *descr = read_obj(&next_instr[5].cache);
- assert(oparg & 1);
- PyTypeObject *owner_cls = Py_TYPE(owner);
- DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR);
- 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;
+ {
+ uint32_t type_version = read_u32(&next_instr[1].cache);
+ PyTypeObject *tp = Py_TYPE(owner);
+ assert(type_version != 0);
+ DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
+ }
+ // _LOAD_ATTR_METHOD_NO_DICT
+ {
+ PyObject *descr = read_obj(&next_instr[5].cache);
+ 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;
diff --git a/Tools/cases_generator/analysis.py b/Tools/cases_generator/analysis.py
index b920c0a..91dcba8 100644
--- a/Tools/cases_generator/analysis.py
+++ b/Tools/cases_generator/analysis.py
@@ -414,3 +414,61 @@ class Analyzer:
case _:
assert_never(uop)
return components
+
+ def report_non_viable_uops(self, jsonfile: str) -> None:
+ print("The following ops are not viable uops:")
+ skips = {
+ "CACHE",
+ "RESERVED",
+ "INTERPRETER_EXIT",
+ "JUMP_BACKWARD",
+ "LOAD_FAST_LOAD_FAST",
+ "LOAD_CONST_LOAD_FAST",
+ "STORE_FAST_STORE_FAST",
+ "_BINARY_OP_INPLACE_ADD_UNICODE",
+ "POP_JUMP_IF_TRUE",
+ "POP_JUMP_IF_FALSE",
+ "_ITER_JUMP_LIST",
+ "_ITER_JUMP_TUPLE",
+ "_ITER_JUMP_RANGE",
+ }
+ try:
+ # Secret feature: if bmraw.json exists, print and sort by execution count
+ counts = load_execution_counts(jsonfile)
+ except FileNotFoundError as err:
+ counts = {}
+ non_viable = [
+ instr
+ for instr in self.instrs.values()
+ if instr.name not in skips
+ and not instr.name.startswith("INSTRUMENTED_")
+ and not instr.is_viable_uop()
+ ]
+ non_viable.sort(key=lambda instr: (-counts.get(instr.name, 0), instr.name))
+ for instr in non_viable:
+ if instr.name in counts:
+ scount = f"{counts[instr.name]:,}"
+ else:
+ scount = ""
+ print(f" {scount:>15} {instr.name:<35}", end="")
+ if instr.name in self.families:
+ print(" (unspecialized)", end="")
+ elif instr.family is not None:
+ print(f" (specialization of {instr.family.name})", end="")
+ print()
+
+
+def load_execution_counts(jsonfile: str) -> dict[str, int]:
+ import json
+
+ with open(jsonfile) as f:
+ jsondata = json.load(f)
+
+ # Look for keys like "opcode[LOAD_FAST].execution_count"
+ prefix = "opcode["
+ suffix = "].execution_count"
+ res: dict[str, int] = {}
+ for key, value in jsondata.items():
+ if key.startswith(prefix) and key.endswith(suffix):
+ res[key[len(prefix) : -len(suffix)]] = value
+ return res
diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py
index 8987362..9192d10 100644
--- a/Tools/cases_generator/generate_cases.py
+++ b/Tools/cases_generator/generate_cases.py
@@ -92,6 +92,13 @@ arg_parser = argparse.ArgumentParser(
description="Generate the code for the interpreter switch.",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
+
+arg_parser.add_argument(
+ "-v",
+ "--verbose",
+ help="Print list of non-viable uops and exit",
+ action="store_true",
+)
arg_parser.add_argument(
"-o", "--output", type=str, help="Generated code", default=DEFAULT_OUTPUT
)
@@ -865,6 +872,10 @@ def main() -> None:
a.analyze() # Prints messages and sets a.errors on failure
if a.errors:
sys.exit(f"Found {a.errors} errors")
+ if args.verbose:
+ # Load execution counts from bmraw.json, if it exists
+ a.report_non_viable_uops("bmraw.json")
+ return
# These raise OSError if output can't be written
a.write_instructions(args.output, args.emit_line_directives)