mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
bpo-45885: Specialize COMPARE_OP (GH-29734)
* Add COMPARE_OP_ADAPTIVE adaptive instruction. * Add COMPARE_OP_FLOAT_JUMP, COMPARE_OP_INT_JUMP and COMPARE_OP_STR_JUMP specialized instructions. * Introduce and use _PyUnicode_Equal
This commit is contained in:
parent
99fcf15052
commit
03768c4d13
9 changed files with 289 additions and 60 deletions
|
@ -129,6 +129,7 @@ _Py_GetSpecializationStats(void) {
|
|||
err += add_stat_dict(stats, STORE_ATTR, "store_attr");
|
||||
err += add_stat_dict(stats, CALL_FUNCTION, "call_function");
|
||||
err += add_stat_dict(stats, BINARY_OP, "binary_op");
|
||||
err += add_stat_dict(stats, COMPARE_OP, "compare_op");
|
||||
if (err < 0) {
|
||||
Py_DECREF(stats);
|
||||
return NULL;
|
||||
|
@ -187,6 +188,7 @@ _Py_PrintSpecializationStats(void)
|
|||
print_stats(out, &_specialization_stats[STORE_ATTR], "store_attr");
|
||||
print_stats(out, &_specialization_stats[CALL_FUNCTION], "call_function");
|
||||
print_stats(out, &_specialization_stats[BINARY_OP], "binary_op");
|
||||
print_stats(out, &_specialization_stats[COMPARE_OP], "compare_op");
|
||||
if (out != stderr) {
|
||||
fclose(out);
|
||||
}
|
||||
|
@ -239,6 +241,7 @@ static uint8_t adaptive_opcodes[256] = {
|
|||
[CALL_FUNCTION] = CALL_FUNCTION_ADAPTIVE,
|
||||
[STORE_ATTR] = STORE_ATTR_ADAPTIVE,
|
||||
[BINARY_OP] = BINARY_OP_ADAPTIVE,
|
||||
[COMPARE_OP] = COMPARE_OP_ADAPTIVE,
|
||||
};
|
||||
|
||||
/* The number of cache entries required for a "family" of instructions. */
|
||||
|
@ -251,6 +254,7 @@ static uint8_t cache_requirements[256] = {
|
|||
[CALL_FUNCTION] = 2, /* _PyAdaptiveEntry and _PyObjectCache/_PyCallCache */
|
||||
[STORE_ATTR] = 2, /* _PyAdaptiveEntry and _PyAttrCache */
|
||||
[BINARY_OP] = 1, // _PyAdaptiveEntry
|
||||
[COMPARE_OP] = 1, /* _PyAdaptiveEntry */
|
||||
};
|
||||
|
||||
/* Return the oparg for the cache_offset and instruction index.
|
||||
|
@ -487,6 +491,10 @@ initial_counter_value(void) {
|
|||
#define SPEC_FAIL_BAD_CALL_FLAGS 17
|
||||
#define SPEC_FAIL_CLASS 18
|
||||
|
||||
/* COMPARE_OP */
|
||||
#define SPEC_FAIL_STRING_COMPARE 13
|
||||
#define SPEC_FAIL_NOT_FOLLOWED_BY_COND_JUMP 14
|
||||
#define SPEC_FAIL_BIG_INT 15
|
||||
|
||||
static int
|
||||
specialize_module_load_attr(
|
||||
|
@ -1536,3 +1544,74 @@ success:
|
|||
STAT_INC(BINARY_OP, specialization_success);
|
||||
adaptive->counter = initial_counter_value();
|
||||
}
|
||||
|
||||
static int compare_masks[] = {
|
||||
// 1-bit: jump if less than
|
||||
// 2-bit: jump if equal
|
||||
// 4-bit: jump if greater
|
||||
[Py_LT] = 1 | 0 | 0,
|
||||
[Py_LE] = 1 | 2 | 0,
|
||||
[Py_EQ] = 0 | 2 | 0,
|
||||
[Py_NE] = 1 | 0 | 4,
|
||||
[Py_GT] = 0 | 0 | 4,
|
||||
[Py_GE] = 0 | 2 | 4,
|
||||
};
|
||||
|
||||
void
|
||||
_Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs,
|
||||
_Py_CODEUNIT *instr, SpecializedCacheEntry *cache)
|
||||
{
|
||||
_PyAdaptiveEntry *adaptive = &cache->adaptive;
|
||||
int op = adaptive->original_oparg;
|
||||
int next_opcode = _Py_OPCODE(instr[1]);
|
||||
if (next_opcode != POP_JUMP_IF_FALSE && next_opcode != POP_JUMP_IF_TRUE) {
|
||||
// Can't ever combine, so don't don't bother being adaptive.
|
||||
SPECIALIZATION_FAIL(COMPARE_OP, SPEC_FAIL_NOT_FOLLOWED_BY_COND_JUMP);
|
||||
*instr = _Py_MAKECODEUNIT(COMPARE_OP, adaptive->original_oparg);
|
||||
goto failure;
|
||||
}
|
||||
assert(op <= Py_GE);
|
||||
int when_to_jump_mask = compare_masks[op];
|
||||
if (next_opcode == POP_JUMP_IF_FALSE) {
|
||||
when_to_jump_mask = (1 | 2 | 4) & ~when_to_jump_mask;
|
||||
}
|
||||
if (Py_TYPE(lhs) != Py_TYPE(rhs)) {
|
||||
SPECIALIZATION_FAIL(COMPARE_OP, SPEC_FAIL_DIFFERENT_TYPES);
|
||||
goto failure;
|
||||
}
|
||||
if (PyFloat_CheckExact(lhs)) {
|
||||
*instr = _Py_MAKECODEUNIT(COMPARE_OP_FLOAT_JUMP, _Py_OPARG(*instr));
|
||||
adaptive->index = when_to_jump_mask;
|
||||
goto success;
|
||||
}
|
||||
if (PyLong_CheckExact(lhs)) {
|
||||
if (Py_ABS(Py_SIZE(lhs)) <= 1 && Py_ABS(Py_SIZE(rhs)) <= 1) {
|
||||
*instr = _Py_MAKECODEUNIT(COMPARE_OP_INT_JUMP, _Py_OPARG(*instr));
|
||||
adaptive->index = when_to_jump_mask;
|
||||
goto success;
|
||||
}
|
||||
else {
|
||||
SPECIALIZATION_FAIL(COMPARE_OP, SPEC_FAIL_BIG_INT);
|
||||
goto failure;
|
||||
}
|
||||
}
|
||||
if (PyUnicode_CheckExact(lhs)) {
|
||||
if (op != Py_EQ && op != Py_NE) {
|
||||
SPECIALIZATION_FAIL(COMPARE_OP, SPEC_FAIL_STRING_COMPARE);
|
||||
goto failure;
|
||||
}
|
||||
else {
|
||||
*instr = _Py_MAKECODEUNIT(COMPARE_OP_STR_JUMP, _Py_OPARG(*instr));
|
||||
adaptive->index = (when_to_jump_mask & 2) == 0;
|
||||
goto success;
|
||||
}
|
||||
}
|
||||
SPECIALIZATION_FAIL(COMPARE_OP, SPEC_FAIL_OTHER);
|
||||
failure:
|
||||
STAT_INC(COMPARE_OP, specialization_failure);
|
||||
cache_backoff(adaptive);
|
||||
return;
|
||||
success:
|
||||
STAT_INC(COMPARE_OP, specialization_success);
|
||||
adaptive->counter = initial_counter_value();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue