From 53e50c403478e40f368dd3a21178cb81f65bd554 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Wed, 1 Feb 2023 12:58:36 -0800 Subject: [PATCH 1/8] Get rid of COMPARE_AND_BRANCH --- Doc/library/dis.rst | 9 --- Include/internal/pycore_code.h | 2 +- Include/internal/pycore_opcode.h | 23 +++--- Include/opcode.h | 19 +++-- Lib/dis.py | 2 +- Lib/opcode.py | 13 ++-- Lib/test/test_compile.py | 2 +- Lib/test/test_dis.py | 16 ++--- Objects/frameobject.c | 8 --- Python/bytecodes.c | 100 +++++++++----------------- Python/ceval.c | 9 +++ Python/compile.c | 7 +- Python/generated_cases.c.h | 116 ++++++++++++------------------- Python/opcode_metadata.h | 31 ++++----- Python/opcode_targets.h | 14 ++-- Python/specialize.c | 92 +++++++++--------------- Tools/scripts/summarize_stats.py | 2 - 17 files changed, 173 insertions(+), 292 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 1fe2d5d6227d61..35bb0350c843b8 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1045,15 +1045,6 @@ iterations of the loop. ``cmp_op[opname]``. -.. opcode:: COMPARE_AND_BRANCH (opname) - - Compares the top two values on the stack, popping them, then branches. - The direction and offset of the jump is embedded as a ``POP_JUMP_IF_TRUE`` - or ``POP_JUMP_IF_FALSE`` instruction immediately following the cache. - - .. versionadded:: 3.12 - - .. opcode:: IS_OP (invert) Performs ``is`` comparison, or ``is not`` if ``invert`` is 1. diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index a287250acc1912..b53657ac08a041 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -228,7 +228,7 @@ extern void _Py_Specialize_Call(PyObject *callable, _Py_CODEUNIT *instr, int nargs, PyObject *kwnames); extern void _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, int oparg, PyObject **locals); -extern void _Py_Specialize_CompareAndBranch(PyObject *lhs, PyObject *rhs, +extern void _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, int oparg); extern void _Py_Specialize_UnpackSequence(PyObject *seq, _Py_CODEUNIT *instr, int oparg); diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 05c0485b0641d8..c374b3498e350f 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -50,7 +50,6 @@ const uint8_t _PyOpcode_Caches[256] = { [COMPARE_OP] = 1, [LOAD_GLOBAL] = 5, [BINARY_OP] = 1, - [COMPARE_AND_BRANCH] = 1, [CALL] = 4, }; @@ -103,11 +102,10 @@ const uint8_t _PyOpcode_Deopt[256] = { [CHECK_EG_MATCH] = CHECK_EG_MATCH, [CHECK_EXC_MATCH] = CHECK_EXC_MATCH, [CLEANUP_THROW] = CLEANUP_THROW, - [COMPARE_AND_BRANCH] = COMPARE_AND_BRANCH, - [COMPARE_AND_BRANCH_FLOAT] = COMPARE_AND_BRANCH, - [COMPARE_AND_BRANCH_INT] = COMPARE_AND_BRANCH, - [COMPARE_AND_BRANCH_STR] = COMPARE_AND_BRANCH, [COMPARE_OP] = COMPARE_OP, + [COMPARE_OP_FLOAT] = COMPARE_OP, + [COMPARE_OP_INT] = COMPARE_OP, + [COMPARE_OP_STR] = COMPARE_OP, [CONTAINS_OP] = CONTAINS_OP, [COPY] = COPY, [COPY_FREE_VARS] = COPY_FREE_VARS, @@ -276,7 +274,7 @@ static const char *const _PyOpcode_OpName[263] = { [CALL_NO_KW_STR_1] = "CALL_NO_KW_STR_1", [CALL_NO_KW_TUPLE_1] = "CALL_NO_KW_TUPLE_1", [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", - [COMPARE_AND_BRANCH_FLOAT] = "COMPARE_AND_BRANCH_FLOAT", + [COMPARE_OP_FLOAT] = "COMPARE_OP_FLOAT", [WITH_EXCEPT_START] = "WITH_EXCEPT_START", [GET_AITER] = "GET_AITER", [GET_ANEXT] = "GET_ANEXT", @@ -284,8 +282,8 @@ static const char *const _PyOpcode_OpName[263] = { [BEFORE_WITH] = "BEFORE_WITH", [END_ASYNC_FOR] = "END_ASYNC_FOR", [CLEANUP_THROW] = "CLEANUP_THROW", - [COMPARE_AND_BRANCH_INT] = "COMPARE_AND_BRANCH_INT", - [COMPARE_AND_BRANCH_STR] = "COMPARE_AND_BRANCH_STR", + [COMPARE_OP_INT] = "COMPARE_OP_INT", + [COMPARE_OP_STR] = "COMPARE_OP_STR", [FOR_ITER_LIST] = "FOR_ITER_LIST", [FOR_ITER_TUPLE] = "FOR_ITER_TUPLE", [STORE_SUBSCR] = "STORE_SUBSCR", @@ -369,9 +367,9 @@ static const char *const _PyOpcode_OpName[263] = { [STORE_DEREF] = "STORE_DEREF", [DELETE_DEREF] = "DELETE_DEREF", [JUMP_BACKWARD] = "JUMP_BACKWARD", - [COMPARE_AND_BRANCH] = "COMPARE_AND_BRANCH", - [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", + [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", + [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", [EXTENDED_ARG] = "EXTENDED_ARG", [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", @@ -381,14 +379,14 @@ static const char *const _PyOpcode_OpName[263] = { [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", - [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", + [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", [FORMAT_VALUE] = "FORMAT_VALUE", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", - [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", + [160] = "<160>", [161] = "<161>", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", @@ -495,6 +493,7 @@ static const char *const _PyOpcode_OpName[263] = { #endif #define EXTRA_CASES \ + case 160: \ case 161: \ case 166: \ case 167: \ diff --git a/Include/opcode.h b/Include/opcode.h index 827f9931beb3e6..0b689815ca6feb 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -95,7 +95,6 @@ extern "C" { #define STORE_DEREF 138 #define DELETE_DEREF 139 #define JUMP_BACKWARD 140 -#define COMPARE_AND_BRANCH 141 #define CALL_FUNCTION_EX 142 #define EXTENDED_ARG 144 #define LIST_APPEND 145 @@ -154,9 +153,9 @@ extern "C" { #define CALL_NO_KW_STR_1 45 #define CALL_NO_KW_TUPLE_1 46 #define CALL_NO_KW_TYPE_1 47 -#define COMPARE_AND_BRANCH_FLOAT 48 -#define COMPARE_AND_BRANCH_INT 56 -#define COMPARE_AND_BRANCH_STR 57 +#define COMPARE_OP_FLOAT 48 +#define COMPARE_OP_INT 56 +#define COMPARE_OP_STR 57 #define FOR_ITER_LIST 58 #define FOR_ITER_TUPLE 59 #define FOR_ITER_RANGE 62 @@ -180,12 +179,12 @@ extern "C" { #define STORE_ATTR_SLOT 87 #define STORE_ATTR_WITH_HINT 113 #define STORE_FAST__LOAD_FAST 121 -#define STORE_FAST__STORE_FAST 143 -#define STORE_SUBSCR_DICT 153 -#define STORE_SUBSCR_LIST_INT 154 -#define UNPACK_SEQUENCE_LIST 158 -#define UNPACK_SEQUENCE_TUPLE 159 -#define UNPACK_SEQUENCE_TWO_TUPLE 160 +#define STORE_FAST__STORE_FAST 141 +#define STORE_SUBSCR_DICT 143 +#define STORE_SUBSCR_LIST_INT 153 +#define UNPACK_SEQUENCE_LIST 154 +#define UNPACK_SEQUENCE_TUPLE 158 +#define UNPACK_SEQUENCE_TWO_TUPLE 159 #define DO_TRACING 255 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ diff --git a/Lib/dis.py b/Lib/dis.py index 72ab9536a2bf6a..76104c6098d40c 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -483,7 +483,7 @@ def _get_instructions_bytes(code, varname_from_oparg=None, elif deop in haslocal or deop in hasfree: argval, argrepr = _get_name_info(arg, varname_from_oparg) elif deop in hascompare: - argval = cmp_op[arg>>4] + argval = cmp_op[arg] argrepr = argval elif deop == FORMAT_VALUE: argval, argrepr = FORMAT_VALUE_CONVERTERS[arg & 0x3] diff --git a/Lib/opcode.py b/Lib/opcode.py index c317e23beae62b..1df8b15d68a1a9 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -192,8 +192,6 @@ def pseudo_op(name, op, real_ops): def_op('DELETE_DEREF', 139) hasfree.append(139) jrel_op('JUMP_BACKWARD', 140) # Number of words to skip (backwards) -def_op('COMPARE_AND_BRANCH', 141) # Comparison and jump -hascompare.append(141) def_op('CALL_FUNCTION_EX', 142) # Flags @@ -314,10 +312,10 @@ def pseudo_op(name, op, real_ops): "CALL_NO_KW_TUPLE_1", "CALL_NO_KW_TYPE_1", ], - "COMPARE_AND_BRANCH": [ - "COMPARE_AND_BRANCH_FLOAT", - "COMPARE_AND_BRANCH_INT", - "COMPARE_AND_BRANCH_STR", + "COMPARE_OP": [ + "COMPARE_OP_FLOAT", + "COMPARE_OP_INT", + "COMPARE_OP_STR", ], "FOR_ITER": [ "FOR_ITER_LIST", @@ -397,9 +395,6 @@ def pseudo_op(name, op, real_ops): "COMPARE_OP": { "counter": 1, }, - "COMPARE_AND_BRANCH": { - "counter": 1, - }, "BINARY_SUBSCR": { "counter": 1, "type_version": 2, diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 05a5ed1fa9a637..362eb691c4ab0f 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -1272,7 +1272,7 @@ def test_multiline_boolean_expression(self): self.assertOpcodeSourcePositionIs(compiled_code, 'POP_JUMP_IF_FALSE', line=2, end_line=2, column=15, end_column=16, occurrence=2) # compare d and 0 - self.assertOpcodeSourcePositionIs(compiled_code, 'COMPARE_AND_BRANCH', + self.assertOpcodeSourcePositionIs(compiled_code, 'COMPARE_OP', line=4, end_line=4, column=8, end_column=13, occurrence=1) # jump if comparison it True self.assertOpcodeSourcePositionIs(compiled_code, 'POP_JUMP_IF_TRUE', diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index bdf48c15309296..306085e98c9161 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -46,7 +46,7 @@ def cm(cls, x): %3d LOAD_FAST 1 (x) LOAD_CONST 1 (1) - COMPARE_OP 32 (==) + COMPARE_OP 2 (==) LOAD_FAST 0 (self) STORE_ATTR 0 (x) LOAD_CONST 0 (None) @@ -57,7 +57,7 @@ def cm(cls, x): RESUME 0 LOAD_FAST 1 LOAD_CONST 1 - COMPARE_OP 32 (==) + COMPARE_OP 2 (==) LOAD_FAST 0 STORE_ATTR 0 LOAD_CONST 0 @@ -69,7 +69,7 @@ def cm(cls, x): %3d LOAD_FAST 1 (x) LOAD_CONST 1 (1) - COMPARE_OP 32 (==) + COMPARE_OP 2 (==) LOAD_FAST 0 (cls) STORE_ATTR 0 (x) LOAD_CONST 0 (None) @@ -81,7 +81,7 @@ def cm(cls, x): %3d LOAD_FAST 0 (x) LOAD_CONST 1 (1) - COMPARE_OP 32 (==) + COMPARE_OP 2 (==) STORE_FAST 0 (x) LOAD_CONST 0 (None) RETURN_VALUE @@ -1567,12 +1567,12 @@ def _prepare_test_cases(): Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=58, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=60, starts_line=5, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=62, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_AND_BRANCH', opcode=141, arg=13, argval='<', argrepr='<', offset=64, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=64, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=72, argrepr='to 72', offset=68, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_BACKWARD', opcode=140, arg=22, argval=28, argrepr='to 28', offset=70, starts_line=6, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=72, starts_line=7, is_jump_target=True, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=74, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_AND_BRANCH', opcode=141, arg=68, argval='>', argrepr='>', offset=76, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=76, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=1, argval=84, argrepr='to 84', offset=80, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_BACKWARD', opcode=140, arg=28, argval=28, argrepr='to 28', offset=82, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=84, starts_line=8, is_jump_target=True, positions=None), @@ -1594,12 +1594,12 @@ def _prepare_test_cases(): Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=154, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=156, starts_line=14, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=158, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_AND_BRANCH', opcode=141, arg=75, argval='>', argrepr='>', offset=160, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=160, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=168, argrepr='to 168', offset=164, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_BACKWARD', opcode=140, arg=26, argval=116, argrepr='to 116', offset=166, starts_line=15, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=168, starts_line=16, is_jump_target=True, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=170, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_AND_BRANCH', opcode=141, arg=13, argval='<', argrepr='<', offset=172, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=172, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=180, argrepr='to 180', offset=176, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_FORWARD', opcode=110, arg=16, argval=212, argrepr='to 212', offset=178, starts_line=17, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=180, starts_line=11, is_jump_target=True, positions=None), diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 6bc04bc8e848fc..39ccca70f9cbf3 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -357,14 +357,6 @@ mark_stacks(PyCodeObject *code_obj, int len) assert(stacks[j] == UNINITIALIZED || stacks[j] == next_stack); stacks[j] = next_stack; break; - case COMPARE_AND_BRANCH: - next_stack = pop_value(pop_value(next_stack)); - i++; - j = get_arg(code, i) + i + 1; - assert(j < len); - assert(stacks[j] == UNINITIALIZED || stacks[j] == next_stack); - stacks[j] = next_stack; - break; case GET_ITER: case GET_AITER: next_stack = push_value(pop_value(next_stack), Iterator); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index bb1deaf3fbeb4b..ed8f72385109ae 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -76,7 +76,8 @@ dummy_func( PyObject **stack_pointer, PyObject *kwnames, int throwflag, - binaryfunc binary_ops[] + binaryfunc binary_ops[], + int compare_masks[], ) { _PyInterpreterFrame entry_frame; @@ -1725,78 +1726,47 @@ dummy_func( } inst(COMPARE_OP, (unused/1, left, right -- res)) { - STAT_INC(COMPARE_OP, deferred); - assert((oparg >> 4) <= Py_GE); - res = PyObject_RichCompare(left, right, oparg>>4); - Py_DECREF(left); - Py_DECREF(right); - ERROR_IF(res == NULL, error); - } - - // No cache size here, since this is a family of super-instructions. - family(compare_and_branch) = { - COMPARE_AND_BRANCH, - COMPARE_AND_BRANCH_FLOAT, - COMPARE_AND_BRANCH_INT, - COMPARE_AND_BRANCH_STR, - }; - - inst(COMPARE_AND_BRANCH, (unused/2, left, right -- )) { #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); next_instr--; - _Py_Specialize_CompareAndBranch(left, right, next_instr, oparg); + _Py_Specialize_CompareOp(left, right, next_instr, oparg); DISPATCH_SAME_OPARG(); } - STAT_INC(COMPARE_AND_BRANCH, deferred); + STAT_INC(COMPARE_OP, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ - assert((oparg >> 4) <= Py_GE); - PyObject *cond = PyObject_RichCompare(left, right, oparg>>4); + assert(oparg <= Py_GE); + res = PyObject_RichCompare(left, right, oparg); Py_DECREF(left); Py_DECREF(right); - ERROR_IF(cond == NULL, error); - assert(_Py_OPCODE(next_instr[1]) == POP_JUMP_IF_FALSE || - _Py_OPCODE(next_instr[1]) == POP_JUMP_IF_TRUE); - bool jump_on_true = _Py_OPCODE(next_instr[1]) == POP_JUMP_IF_TRUE; - int offset = _Py_OPARG(next_instr[1]); - int err = PyObject_IsTrue(cond); - Py_DECREF(cond); - if (err < 0) { - goto error; - } - if (jump_on_true == (err != 0)) { - JUMPBY(offset); - } + ERROR_IF(res == NULL, error); } - inst(COMPARE_AND_BRANCH_FLOAT, (unused/2, left, right -- )) { + inst(COMPARE_OP_FLOAT, (unused/1, left, right -- res)) { assert(cframe.use_tracing == 0); - DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_AND_BRANCH); - DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_AND_BRANCH); - STAT_INC(COMPARE_AND_BRANCH, hit); + DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); + DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); + STAT_INC(COMPARE_OP, hit); double dleft = PyFloat_AS_DOUBLE(left); double dright = PyFloat_AS_DOUBLE(right); // 1 if NaN, 2 if <, 4 if >, 8 if ==; this matches low four bits of the oparg int sign_ish = COMPARISON_BIT(dleft, dright); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); - if (sign_ish & oparg) { - int offset = _Py_OPARG(next_instr[1]); - JUMPBY(offset); - } + res = (sign_ish & compare_masks[oparg]) ? Py_True : Py_False; + Py_INCREF(res); } - // Similar to COMPARE_AND_BRANCH_FLOAT - inst(COMPARE_AND_BRANCH_INT, (unused/2, left, right -- )) { + // Similar to COMPARE_OP_FLOAT + inst(COMPARE_OP_INT, (unused/1, left, right -- res)) { assert(cframe.use_tracing == 0); - DEOPT_IF(!PyLong_CheckExact(left), COMPARE_AND_BRANCH); - DEOPT_IF(!PyLong_CheckExact(right), COMPARE_AND_BRANCH); - DEOPT_IF((size_t)(Py_SIZE(left) + 1) > 2, COMPARE_AND_BRANCH); - DEOPT_IF((size_t)(Py_SIZE(right) + 1) > 2, COMPARE_AND_BRANCH); - STAT_INC(COMPARE_AND_BRANCH, hit); + DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); + DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); + DEOPT_IF((size_t)(Py_SIZE(left) + 1) > 2, COMPARE_OP); + DEOPT_IF((size_t)(Py_SIZE(right) + 1) > 2, COMPARE_OP); + STAT_INC(COMPARE_OP, hit); assert(Py_ABS(Py_SIZE(left)) <= 1 && Py_ABS(Py_SIZE(right)) <= 1); Py_ssize_t ileft = Py_SIZE(left) * ((PyLongObject *)left)->long_value.ob_digit[0]; Py_ssize_t iright = Py_SIZE(right) * ((PyLongObject *)right)->long_value.ob_digit[0]; @@ -1804,29 +1774,23 @@ dummy_func( int sign_ish = COMPARISON_BIT(ileft, iright); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); - if (sign_ish & oparg) { - int offset = _Py_OPARG(next_instr[1]); - JUMPBY(offset); - } + res = (sign_ish & compare_masks[oparg]) ? Py_True : Py_False; + Py_INCREF(res); } - // Similar to COMPARE_AND_BRANCH_FLOAT, but for ==, != only - inst(COMPARE_AND_BRANCH_STR, (unused/2, left, right -- )) { + // Similar to COMPARE_OP_FLOAT, but for ==, != only + inst(COMPARE_OP_STR, (unused/1, left, right -- res)) { assert(cframe.use_tracing == 0); - DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_AND_BRANCH); - DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_AND_BRANCH); - STAT_INC(COMPARE_AND_BRANCH, hit); - int res = _PyUnicode_Equal(left, right); - assert((oparg >>4) == Py_EQ || (oparg >>4) == Py_NE); + DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); + DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); + STAT_INC(COMPARE_OP, hit); + int eq = _PyUnicode_Equal(left, right); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); - assert(res == 0 || res == 1); - assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); - assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); - if ((res + COMPARISON_NOT_EQUALS) & oparg) { - int offset = _Py_OPARG(next_instr[1]); - JUMPBY(offset); - } + assert(oparg == Py_EQ || oparg == Py_NE); + assert(eq == 0 || eq == 1); + res = (eq == (oparg == Py_EQ)) ? Py_True : Py_False; + Py_INCREF(res); } inst(IS_OP, (left, right -- b)) { diff --git a/Python/ceval.c b/Python/ceval.c index 2e6fed580dede4..c55c661744515e 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -319,6 +319,15 @@ static const binaryfunc binary_ops[] = { [NB_INPLACE_XOR] = PyNumber_InPlaceXor, }; +static int compare_masks[] = { + [Py_LT] = COMPARISON_LESS_THAN, + [Py_LE] = COMPARISON_LESS_THAN | COMPARISON_EQUALS, + [Py_EQ] = COMPARISON_EQUALS, + [Py_NE] = COMPARISON_NOT_EQUALS, + [Py_GT] = COMPARISON_GREATER_THAN, + [Py_GE] = COMPARISON_GREATER_THAN | COMPARISON_EQUALS, +}; + // PEP 634: Structural Pattern Matching diff --git a/Python/compile.c b/Python/compile.c index a11bcc79a6dd10..7189148aa82b6e 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1194,9 +1194,6 @@ stack_effect(int opcode, int oparg, int jump) case POP_JUMP_IF_TRUE: return -1; - case COMPARE_AND_BRANCH: - return -2; - case LOAD_GLOBAL: return (oparg & 1) + 1; @@ -2886,9 +2883,7 @@ static int compiler_addcompare(struct compiler *c, location loc, default: Py_UNREACHABLE(); } - /* cmp goes in top bits of the oparg, while the low bits are used by quickened - * versions of this opcode to store the comparison mask. */ - ADDOP_I(c, loc, COMPARE_OP, cmp << 4); + ADDOP_I(c, loc, COMPARE_OP, cmp); return SUCCESS; } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index e5c5c7e557a37c..dc91d1c61fa938 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2112,89 +2112,64 @@ } TARGET(COMPARE_OP) { + PREDICTED(COMPARE_OP); PyObject *right = PEEK(1); PyObject *left = PEEK(2); PyObject *res; - STAT_INC(COMPARE_OP, deferred); - assert((oparg >> 4) <= Py_GE); - res = PyObject_RichCompare(left, right, oparg>>4); - Py_DECREF(left); - Py_DECREF(right); - if (res == NULL) goto pop_2_error; - STACK_SHRINK(1); - POKE(1, res); - JUMPBY(1); - DISPATCH(); - } - - TARGET(COMPARE_AND_BRANCH) { - PREDICTED(COMPARE_AND_BRANCH); - PyObject *right = PEEK(1); - PyObject *left = PEEK(2); #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); next_instr--; - _Py_Specialize_CompareAndBranch(left, right, next_instr, oparg); + _Py_Specialize_CompareOp(left, right, next_instr, oparg); DISPATCH_SAME_OPARG(); } - STAT_INC(COMPARE_AND_BRANCH, deferred); + STAT_INC(COMPARE_OP, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ - assert((oparg >> 4) <= Py_GE); - PyObject *cond = PyObject_RichCompare(left, right, oparg>>4); + assert(oparg <= Py_GE); + res = PyObject_RichCompare(left, right, oparg); Py_DECREF(left); Py_DECREF(right); - if (cond == NULL) goto pop_2_error; - assert(_Py_OPCODE(next_instr[1]) == POP_JUMP_IF_FALSE || - _Py_OPCODE(next_instr[1]) == POP_JUMP_IF_TRUE); - bool jump_on_true = _Py_OPCODE(next_instr[1]) == POP_JUMP_IF_TRUE; - int offset = _Py_OPARG(next_instr[1]); - int err = PyObject_IsTrue(cond); - Py_DECREF(cond); - if (err < 0) { - goto error; - } - if (jump_on_true == (err != 0)) { - JUMPBY(offset); - } - STACK_SHRINK(2); - JUMPBY(2); + if (res == NULL) goto pop_2_error; + STACK_SHRINK(1); + POKE(1, res); + JUMPBY(1); DISPATCH(); } - TARGET(COMPARE_AND_BRANCH_FLOAT) { + TARGET(COMPARE_OP_FLOAT) { PyObject *right = PEEK(1); PyObject *left = PEEK(2); + PyObject *res; assert(cframe.use_tracing == 0); - DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_AND_BRANCH); - DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_AND_BRANCH); - STAT_INC(COMPARE_AND_BRANCH, hit); + DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); + DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); + STAT_INC(COMPARE_OP, hit); double dleft = PyFloat_AS_DOUBLE(left); double dright = PyFloat_AS_DOUBLE(right); // 1 if NaN, 2 if <, 4 if >, 8 if ==; this matches low four bits of the oparg int sign_ish = COMPARISON_BIT(dleft, dright); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); - if (sign_ish & oparg) { - int offset = _Py_OPARG(next_instr[1]); - JUMPBY(offset); - } - STACK_SHRINK(2); - JUMPBY(2); + res = (sign_ish & compare_masks[oparg]) ? Py_True : Py_False; + Py_INCREF(res); + STACK_SHRINK(1); + POKE(1, res); + JUMPBY(1); DISPATCH(); } - TARGET(COMPARE_AND_BRANCH_INT) { + TARGET(COMPARE_OP_INT) { PyObject *right = PEEK(1); PyObject *left = PEEK(2); + PyObject *res; assert(cframe.use_tracing == 0); - DEOPT_IF(!PyLong_CheckExact(left), COMPARE_AND_BRANCH); - DEOPT_IF(!PyLong_CheckExact(right), COMPARE_AND_BRANCH); - DEOPT_IF((size_t)(Py_SIZE(left) + 1) > 2, COMPARE_AND_BRANCH); - DEOPT_IF((size_t)(Py_SIZE(right) + 1) > 2, COMPARE_AND_BRANCH); - STAT_INC(COMPARE_AND_BRANCH, hit); + DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); + DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); + DEOPT_IF((size_t)(Py_SIZE(left) + 1) > 2, COMPARE_OP); + DEOPT_IF((size_t)(Py_SIZE(right) + 1) > 2, COMPARE_OP); + STAT_INC(COMPARE_OP, hit); assert(Py_ABS(Py_SIZE(left)) <= 1 && Py_ABS(Py_SIZE(right)) <= 1); Py_ssize_t ileft = Py_SIZE(left) * ((PyLongObject *)left)->long_value.ob_digit[0]; Py_ssize_t iright = Py_SIZE(right) * ((PyLongObject *)right)->long_value.ob_digit[0]; @@ -2202,35 +2177,32 @@ int sign_ish = COMPARISON_BIT(ileft, iright); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); - if (sign_ish & oparg) { - int offset = _Py_OPARG(next_instr[1]); - JUMPBY(offset); - } - STACK_SHRINK(2); - JUMPBY(2); + res = (sign_ish & compare_masks[oparg]) ? Py_True : Py_False; + Py_INCREF(res); + STACK_SHRINK(1); + POKE(1, res); + JUMPBY(1); DISPATCH(); } - TARGET(COMPARE_AND_BRANCH_STR) { + TARGET(COMPARE_OP_STR) { PyObject *right = PEEK(1); PyObject *left = PEEK(2); + PyObject *res; assert(cframe.use_tracing == 0); - DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_AND_BRANCH); - DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_AND_BRANCH); - STAT_INC(COMPARE_AND_BRANCH, hit); - int res = _PyUnicode_Equal(left, right); - assert((oparg >>4) == Py_EQ || (oparg >>4) == Py_NE); + DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); + DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); + STAT_INC(COMPARE_OP, hit); + int eq = _PyUnicode_Equal(left, right); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); - assert(res == 0 || res == 1); - assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); - assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); - if ((res + COMPARISON_NOT_EQUALS) & oparg) { - int offset = _Py_OPARG(next_instr[1]); - JUMPBY(offset); - } - STACK_SHRINK(2); - JUMPBY(2); + assert(oparg == Py_EQ || oparg == Py_NE); + assert(eq == 0 || eq == 1); + res = (eq == (oparg == Py_EQ)) ? Py_True : Py_False; + Py_INCREF(res); + STACK_SHRINK(1); + POKE(1, res); + JUMPBY(1); DISPATCH(); } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 96e57be8cf5dea..7fb9ce507c1a1b 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -208,13 +208,11 @@ _PyOpcode_num_popped(int opcode, int oparg) { return 2; case COMPARE_OP: return 2; - case COMPARE_AND_BRANCH: + case COMPARE_OP_FLOAT: return 2; - case COMPARE_AND_BRANCH_FLOAT: + case COMPARE_OP_INT: return 2; - case COMPARE_AND_BRANCH_INT: - return 2; - case COMPARE_AND_BRANCH_STR: + case COMPARE_OP_STR: return 2; case IS_OP: return 2; @@ -554,14 +552,12 @@ _PyOpcode_num_pushed(int opcode, int oparg) { return 0; case COMPARE_OP: return 1; - case COMPARE_AND_BRANCH: - return 0; - case COMPARE_AND_BRANCH_FLOAT: - return 0; - case COMPARE_AND_BRANCH_INT: - return 0; - case COMPARE_AND_BRANCH_STR: - return 0; + case COMPARE_OP_FLOAT: + return 1; + case COMPARE_OP_INT: + return 1; + case COMPARE_OP_STR: + return 1; case IS_OP: return 1; case CONTAINS_OP: @@ -694,7 +690,7 @@ _PyOpcode_num_pushed(int opcode, int oparg) { } #endif enum Direction { DIR_NONE, DIR_READ, DIR_WRITE }; -enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC0, INSTR_FMT_IBC000, INSTR_FMT_IBC00000000, INSTR_FMT_IBIB, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC000 }; +enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC000, INSTR_FMT_IBC00000000, INSTR_FMT_IBIB, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC000 }; struct opcode_metadata { enum Direction dir_op1; enum Direction dir_op2; @@ -803,10 +799,9 @@ struct opcode_metadata { [STORE_ATTR_WITH_HINT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, [STORE_ATTR_SLOT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, [COMPARE_OP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [COMPARE_AND_BRANCH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC0 }, - [COMPARE_AND_BRANCH_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC0 }, - [COMPARE_AND_BRANCH_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC0 }, - [COMPARE_AND_BRANCH_STR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC0 }, + [COMPARE_OP_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, + [COMPARE_OP_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, + [COMPARE_OP_STR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, [IS_OP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [CONTAINS_OP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [CHECK_EG_MATCH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index f1c3f3e0c4ee17..03aaf2346c37fc 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -47,7 +47,7 @@ static void *opcode_targets[256] = { &&TARGET_CALL_NO_KW_STR_1, &&TARGET_CALL_NO_KW_TUPLE_1, &&TARGET_CALL_NO_KW_TYPE_1, - &&TARGET_COMPARE_AND_BRANCH_FLOAT, + &&TARGET_COMPARE_OP_FLOAT, &&TARGET_WITH_EXCEPT_START, &&TARGET_GET_AITER, &&TARGET_GET_ANEXT, @@ -55,8 +55,8 @@ static void *opcode_targets[256] = { &&TARGET_BEFORE_WITH, &&TARGET_END_ASYNC_FOR, &&TARGET_CLEANUP_THROW, - &&TARGET_COMPARE_AND_BRANCH_INT, - &&TARGET_COMPARE_AND_BRANCH_STR, + &&TARGET_COMPARE_OP_INT, + &&TARGET_COMPARE_OP_STR, &&TARGET_FOR_ITER_LIST, &&TARGET_FOR_ITER_TUPLE, &&TARGET_STORE_SUBSCR, @@ -140,9 +140,9 @@ static void *opcode_targets[256] = { &&TARGET_STORE_DEREF, &&TARGET_DELETE_DEREF, &&TARGET_JUMP_BACKWARD, - &&TARGET_COMPARE_AND_BRANCH, - &&TARGET_CALL_FUNCTION_EX, &&TARGET_STORE_FAST__STORE_FAST, + &&TARGET_CALL_FUNCTION_EX, + &&TARGET_STORE_SUBSCR_DICT, &&TARGET_EXTENDED_ARG, &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, @@ -152,15 +152,15 @@ static void *opcode_targets[256] = { &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, - &&TARGET_STORE_SUBSCR_DICT, &&TARGET_STORE_SUBSCR_LIST_INT, + &&TARGET_UNPACK_SEQUENCE_LIST, &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, - &&TARGET_UNPACK_SEQUENCE_LIST, &&TARGET_UNPACK_SEQUENCE_TUPLE, &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, &&_unknown_opcode, + &&_unknown_opcode, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, diff --git a/Python/specialize.c b/Python/specialize.c index 908ad6dceb57f3..63472ed3993f95 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -263,15 +263,6 @@ do { \ #define SPECIALIZATION_FAIL(opcode, kind) ((void)0) #endif -static int compare_masks[] = { - [Py_LT] = COMPARISON_LESS_THAN, - [Py_LE] = COMPARISON_LESS_THAN | COMPARISON_EQUALS, - [Py_EQ] = COMPARISON_EQUALS, - [Py_NE] = COMPARISON_NOT_EQUALS, - [Py_GT] = COMPARISON_GREATER_THAN, - [Py_GE] = COMPARISON_GREATER_THAN | COMPARISON_EQUALS, -}; - // Initialize warmup counters and insert superinstructions. This cannot fail. void _PyCode_Quicken(PyCodeObject *code) @@ -304,19 +295,6 @@ _PyCode_Quicken(PyCodeObject *code) case STORE_FAST << 8 | STORE_FAST: instructions[i - 1].opcode = STORE_FAST__STORE_FAST; break; - case COMPARE_OP << 8 | POP_JUMP_IF_TRUE: - case COMPARE_OP << 8 | POP_JUMP_IF_FALSE: - { - int oparg = instructions[i - 1 - INLINE_CACHE_ENTRIES_COMPARE_OP].oparg; - assert((oparg >> 4) <= Py_GE); - int mask = compare_masks[oparg >> 4]; - if (opcode == POP_JUMP_IF_FALSE) { - mask = mask ^ 0xf; - } - instructions[i - 1 - INLINE_CACHE_ENTRIES_COMPARE_OP].opcode = COMPARE_AND_BRANCH; - instructions[i - 1 - INLINE_CACHE_ENTRIES_COMPARE_OP].oparg = (oparg & 0xf0) | mask; - break; - } } } #endif /* ENABLE_SPECIALIZATION */ @@ -435,19 +413,17 @@ _PyCode_Quicken(PyCodeObject *code) #define SPEC_FAIL_CALL_OPERATOR_WRAPPER 29 /* COMPARE_OP */ -#define SPEC_FAIL_COMPARE_DIFFERENT_TYPES 12 -#define SPEC_FAIL_COMPARE_STRING 13 -#define SPEC_FAIL_COMPARE_NOT_FOLLOWED_BY_COND_JUMP 14 -#define SPEC_FAIL_COMPARE_BIG_INT 15 -#define SPEC_FAIL_COMPARE_BYTES 16 -#define SPEC_FAIL_COMPARE_TUPLE 17 -#define SPEC_FAIL_COMPARE_LIST 18 -#define SPEC_FAIL_COMPARE_SET 19 -#define SPEC_FAIL_COMPARE_BOOL 20 -#define SPEC_FAIL_COMPARE_BASEOBJECT 21 -#define SPEC_FAIL_COMPARE_FLOAT_LONG 22 -#define SPEC_FAIL_COMPARE_LONG_FLOAT 23 -#define SPEC_FAIL_COMPARE_EXTENDED_ARG 24 +#define SPEC_FAIL_COMPARE_OP_DIFFERENT_TYPES 12 +#define SPEC_FAIL_COMPARE_OP_STRING 13 +#define SPEC_FAIL_COMPARE_OP_BIG_INT 14 +#define SPEC_FAIL_COMPARE_OP_BYTES 15 +#define SPEC_FAIL_COMPARE_OP_TUPLE 16 +#define SPEC_FAIL_COMPARE_OP_LIST 17 +#define SPEC_FAIL_COMPARE_OP_SET 18 +#define SPEC_FAIL_COMPARE_OP_BOOL 19 +#define SPEC_FAIL_COMPARE_OP_BASEOBJECT 20 +#define SPEC_FAIL_COMPARE_OP_FLOAT_LONG 21 +#define SPEC_FAIL_COMPARE_OP_LONG_FLOAT 22 /* FOR_ITER */ #define SPEC_FAIL_FOR_ITER_GENERATOR 10 @@ -1943,83 +1919,79 @@ compare_op_fail_kind(PyObject *lhs, PyObject *rhs) { if (Py_TYPE(lhs) != Py_TYPE(rhs)) { if (PyFloat_CheckExact(lhs) && PyLong_CheckExact(rhs)) { - return SPEC_FAIL_COMPARE_FLOAT_LONG; + return SPEC_FAIL_COMPARE_OP_FLOAT_LONG; } if (PyLong_CheckExact(lhs) && PyFloat_CheckExact(rhs)) { - return SPEC_FAIL_COMPARE_LONG_FLOAT; + return SPEC_FAIL_COMPARE_OP_LONG_FLOAT; } - return SPEC_FAIL_COMPARE_DIFFERENT_TYPES; + return SPEC_FAIL_COMPARE_OP_DIFFERENT_TYPES; } if (PyBytes_CheckExact(lhs)) { - return SPEC_FAIL_COMPARE_BYTES; + return SPEC_FAIL_COMPARE_OP_BYTES; } if (PyTuple_CheckExact(lhs)) { - return SPEC_FAIL_COMPARE_TUPLE; + return SPEC_FAIL_COMPARE_OP_TUPLE; } if (PyList_CheckExact(lhs)) { - return SPEC_FAIL_COMPARE_LIST; + return SPEC_FAIL_COMPARE_OP_LIST; } if (PySet_CheckExact(lhs) || PyFrozenSet_CheckExact(lhs)) { - return SPEC_FAIL_COMPARE_SET; + return SPEC_FAIL_COMPARE_OP_SET; } if (PyBool_Check(lhs)) { - return SPEC_FAIL_COMPARE_BOOL; + return SPEC_FAIL_COMPARE_OP_BOOL; } if (Py_TYPE(lhs)->tp_richcompare == PyBaseObject_Type.tp_richcompare) { - return SPEC_FAIL_COMPARE_BASEOBJECT; + return SPEC_FAIL_COMPARE_OP_BASEOBJECT; } return SPEC_FAIL_OTHER; } #endif void -_Py_Specialize_CompareAndBranch(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, +_Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, int oparg) { assert(ENABLE_SPECIALIZATION); - assert(_PyOpcode_Caches[COMPARE_AND_BRANCH] == INLINE_CACHE_ENTRIES_COMPARE_OP); + assert(_PyOpcode_Caches[COMPARE_OP] == INLINE_CACHE_ENTRIES_COMPARE_OP); _PyCompareOpCache *cache = (_PyCompareOpCache *)(instr + 1); -#ifndef NDEBUG - int next_opcode = _Py_OPCODE(instr[INLINE_CACHE_ENTRIES_COMPARE_OP + 1]); - assert(next_opcode == POP_JUMP_IF_FALSE || next_opcode == POP_JUMP_IF_TRUE); -#endif if (Py_TYPE(lhs) != Py_TYPE(rhs)) { - SPECIALIZATION_FAIL(COMPARE_AND_BRANCH, compare_op_fail_kind(lhs, rhs)); + SPECIALIZATION_FAIL(COMPARE_OP, compare_op_fail_kind(lhs, rhs)); goto failure; } if (PyFloat_CheckExact(lhs)) { - _py_set_opcode(instr, COMPARE_AND_BRANCH_FLOAT); + _py_set_opcode(instr, COMPARE_OP_FLOAT); goto success; } if (PyLong_CheckExact(lhs)) { if (Py_ABS(Py_SIZE(lhs)) <= 1 && Py_ABS(Py_SIZE(rhs)) <= 1) { - _py_set_opcode(instr, COMPARE_AND_BRANCH_INT); + _py_set_opcode(instr, COMPARE_OP_INT); goto success; } else { - SPECIALIZATION_FAIL(COMPARE_AND_BRANCH, SPEC_FAIL_COMPARE_BIG_INT); + SPECIALIZATION_FAIL(COMPARE_OP, SPEC_FAIL_COMPARE_OP_BIG_INT); goto failure; } } if (PyUnicode_CheckExact(lhs)) { int cmp = oparg >> 4; if (cmp != Py_EQ && cmp != Py_NE) { - SPECIALIZATION_FAIL(COMPARE_AND_BRANCH, SPEC_FAIL_COMPARE_STRING); + SPECIALIZATION_FAIL(COMPARE_OP, SPEC_FAIL_COMPARE_OP_STRING); goto failure; } else { - _py_set_opcode(instr, COMPARE_AND_BRANCH_STR); + _py_set_opcode(instr, COMPARE_OP_STR); goto success; } } - SPECIALIZATION_FAIL(COMPARE_AND_BRANCH, compare_op_fail_kind(lhs, rhs)); + SPECIALIZATION_FAIL(COMPARE_OP, compare_op_fail_kind(lhs, rhs)); failure: - STAT_INC(COMPARE_AND_BRANCH, failure); - _py_set_opcode(instr, COMPARE_AND_BRANCH); + STAT_INC(COMPARE_OP, failure); + _py_set_opcode(instr, COMPARE_OP); cache->counter = adaptive_counter_backoff(cache->counter); return; success: - STAT_INC(COMPARE_AND_BRANCH, success); + STAT_INC(COMPARE_OP, success); cache->counter = adaptive_counter_cooldown(); } diff --git a/Tools/scripts/summarize_stats.py b/Tools/scripts/summarize_stats.py index 7789c4d3a17d38..ce25374f3a9a52 100644 --- a/Tools/scripts/summarize_stats.py +++ b/Tools/scripts/summarize_stats.py @@ -228,8 +228,6 @@ def kind_to_text(kind, defines, opname): return pretty(defines[kind][0]) if opname.endswith("ATTR"): opname = "ATTR" - if opname in ("COMPARE_OP", "COMPARE_AND_BRANCH"): - opname = "COMPARE" if opname.endswith("SUBSCR"): opname = "SUBSCR" for name in defines[kind]: From 20b59acf0178511cec2ed90945b8cd28d0a34f39 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Wed, 1 Feb 2023 23:10:35 -0800 Subject: [PATCH 2/8] Embed the mask in the oparg again --- Lib/dis.py | 2 +- Lib/test/test_dis.py | 16 ++++++++-------- Python/bytecodes.c | 15 ++++++++------- Python/ceval.c | 9 --------- Python/compile.c | 11 ++++++++++- Python/generated_cases.c.h | 14 ++++++++------ 6 files changed, 35 insertions(+), 32 deletions(-) diff --git a/Lib/dis.py b/Lib/dis.py index 76104c6098d40c..72ab9536a2bf6a 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -483,7 +483,7 @@ def _get_instructions_bytes(code, varname_from_oparg=None, elif deop in haslocal or deop in hasfree: argval, argrepr = _get_name_info(arg, varname_from_oparg) elif deop in hascompare: - argval = cmp_op[arg] + argval = cmp_op[arg>>4] argrepr = argval elif deop == FORMAT_VALUE: argval, argrepr = FORMAT_VALUE_CONVERTERS[arg & 0x3] diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 306085e98c9161..69a45059b5f457 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -46,7 +46,7 @@ def cm(cls, x): %3d LOAD_FAST 1 (x) LOAD_CONST 1 (1) - COMPARE_OP 2 (==) + COMPARE_OP 40 (==) LOAD_FAST 0 (self) STORE_ATTR 0 (x) LOAD_CONST 0 (None) @@ -57,7 +57,7 @@ def cm(cls, x): RESUME 0 LOAD_FAST 1 LOAD_CONST 1 - COMPARE_OP 2 (==) + COMPARE_OP 40 (==) LOAD_FAST 0 STORE_ATTR 0 LOAD_CONST 0 @@ -69,7 +69,7 @@ def cm(cls, x): %3d LOAD_FAST 1 (x) LOAD_CONST 1 (1) - COMPARE_OP 2 (==) + COMPARE_OP 40 (==) LOAD_FAST 0 (cls) STORE_ATTR 0 (x) LOAD_CONST 0 (None) @@ -81,7 +81,7 @@ def cm(cls, x): %3d LOAD_FAST 0 (x) LOAD_CONST 1 (1) - COMPARE_OP 2 (==) + COMPARE_OP 40 (==) STORE_FAST 0 (x) LOAD_CONST 0 (None) RETURN_VALUE @@ -1567,12 +1567,12 @@ def _prepare_test_cases(): Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=58, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=60, starts_line=5, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=62, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=64, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=2, argval='<', argrepr='<', offset=64, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=72, argrepr='to 72', offset=68, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_BACKWARD', opcode=140, arg=22, argval=28, argrepr='to 28', offset=70, starts_line=6, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=72, starts_line=7, is_jump_target=True, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=74, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=76, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=68, argval='>', argrepr='>', offset=76, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=1, argval=84, argrepr='to 84', offset=80, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_BACKWARD', opcode=140, arg=28, argval=28, argrepr='to 28', offset=82, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=84, starts_line=8, is_jump_target=True, positions=None), @@ -1594,12 +1594,12 @@ def _prepare_test_cases(): Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=154, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=156, starts_line=14, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=158, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=160, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=68, argval='>', argrepr='>', offset=160, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=168, argrepr='to 168', offset=164, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_BACKWARD', opcode=140, arg=26, argval=116, argrepr='to 116', offset=166, starts_line=15, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=168, starts_line=16, is_jump_target=True, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=170, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=172, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=2, argval='<', argrepr='<', offset=172, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=180, argrepr='to 180', offset=176, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_FORWARD', opcode=110, arg=16, argval=212, argrepr='to 212', offset=178, starts_line=17, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=180, starts_line=11, is_jump_target=True, positions=None), diff --git a/Python/bytecodes.c b/Python/bytecodes.c index ed8f72385109ae..29acf6379a26eb 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -77,7 +77,6 @@ dummy_func( PyObject *kwnames, int throwflag, binaryfunc binary_ops[], - int compare_masks[], ) { _PyInterpreterFrame entry_frame; @@ -1737,8 +1736,8 @@ dummy_func( STAT_INC(COMPARE_OP, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ - assert(oparg <= Py_GE); - res = PyObject_RichCompare(left, right, oparg); + assert((oparg >> 4) <= Py_GE); + res = PyObject_RichCompare(left, right, oparg>>4); Py_DECREF(left); Py_DECREF(right); ERROR_IF(res == NULL, error); @@ -1755,7 +1754,7 @@ dummy_func( int sign_ish = COMPARISON_BIT(dleft, dright); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); - res = (sign_ish & compare_masks[oparg]) ? Py_True : Py_False; + res = (sign_ish & oparg) ? Py_True : Py_False; Py_INCREF(res); } @@ -1774,7 +1773,7 @@ dummy_func( int sign_ish = COMPARISON_BIT(ileft, iright); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); - res = (sign_ish & compare_masks[oparg]) ? Py_True : Py_False; + res = (sign_ish & oparg) ? Py_True : Py_False; Py_INCREF(res); } @@ -1785,11 +1784,13 @@ dummy_func( DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); int eq = _PyUnicode_Equal(left, right); + assert((oparg >>4) == Py_EQ || (oparg >>4) == Py_NE); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); - assert(oparg == Py_EQ || oparg == Py_NE); assert(eq == 0 || eq == 1); - res = (eq == (oparg == Py_EQ)) ? Py_True : Py_False; + assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); + assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); + res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; Py_INCREF(res); } diff --git a/Python/ceval.c b/Python/ceval.c index c55c661744515e..2e6fed580dede4 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -319,15 +319,6 @@ static const binaryfunc binary_ops[] = { [NB_INPLACE_XOR] = PyNumber_InPlaceXor, }; -static int compare_masks[] = { - [Py_LT] = COMPARISON_LESS_THAN, - [Py_LE] = COMPARISON_LESS_THAN | COMPARISON_EQUALS, - [Py_EQ] = COMPARISON_EQUALS, - [Py_NE] = COMPARISON_NOT_EQUALS, - [Py_GT] = COMPARISON_GREATER_THAN, - [Py_GE] = COMPARISON_GREATER_THAN | COMPARISON_EQUALS, -}; - // PEP 634: Structural Pattern Matching diff --git a/Python/compile.c b/Python/compile.c index 7189148aa82b6e..a9b35f46d79a2d 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -2845,6 +2845,15 @@ check_compare(struct compiler *c, expr_ty e) return SUCCESS; } +static int compare_masks[] = { + [Py_LT] = COMPARISON_LESS_THAN, + [Py_LE] = COMPARISON_LESS_THAN | COMPARISON_EQUALS, + [Py_EQ] = COMPARISON_EQUALS, + [Py_NE] = COMPARISON_NOT_EQUALS, + [Py_GT] = COMPARISON_GREATER_THAN, + [Py_GE] = COMPARISON_GREATER_THAN | COMPARISON_EQUALS, +}; + static int compiler_addcompare(struct compiler *c, location loc, cmpop_ty op) { @@ -2883,7 +2892,7 @@ static int compiler_addcompare(struct compiler *c, location loc, default: Py_UNREACHABLE(); } - ADDOP_I(c, loc, COMPARE_OP, cmp); + ADDOP_I(c, loc, COMPARE_OP, (cmp << 4) | compare_masks[cmp]); return SUCCESS; } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index dc91d1c61fa938..65c3afb93491ca 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2127,8 +2127,8 @@ STAT_INC(COMPARE_OP, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ - assert(oparg <= Py_GE); - res = PyObject_RichCompare(left, right, oparg); + assert((oparg >> 4) <= Py_GE); + res = PyObject_RichCompare(left, right, oparg>>4); Py_DECREF(left); Py_DECREF(right); if (res == NULL) goto pop_2_error; @@ -2152,7 +2152,7 @@ int sign_ish = COMPARISON_BIT(dleft, dright); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); - res = (sign_ish & compare_masks[oparg]) ? Py_True : Py_False; + res = (sign_ish & oparg) ? Py_True : Py_False; Py_INCREF(res); STACK_SHRINK(1); POKE(1, res); @@ -2177,7 +2177,7 @@ int sign_ish = COMPARISON_BIT(ileft, iright); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); - res = (sign_ish & compare_masks[oparg]) ? Py_True : Py_False; + res = (sign_ish & oparg) ? Py_True : Py_False; Py_INCREF(res); STACK_SHRINK(1); POKE(1, res); @@ -2194,11 +2194,13 @@ DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); int eq = _PyUnicode_Equal(left, right); + assert((oparg >>4) == Py_EQ || (oparg >>4) == Py_NE); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); - assert(oparg == Py_EQ || oparg == Py_NE); assert(eq == 0 || eq == 1); - res = (eq == (oparg == Py_EQ)) ? Py_True : Py_False; + assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); + assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); + res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; Py_INCREF(res); STACK_SHRINK(1); POKE(1, res); From 49083fa4e671cb44aedfca18129a31b97a2b3112 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Wed, 1 Feb 2023 23:25:05 -0800 Subject: [PATCH 3/8] fixup --- Python/bytecodes.c | 2 +- Python/compile.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 7336b6e12a4b81..bfcdd8cf213c5f 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -76,7 +76,7 @@ dummy_func( PyObject **stack_pointer, PyObject *kwnames, int throwflag, - binaryfunc binary_ops[], + binaryfunc binary_ops[] ) { _PyInterpreterFrame entry_frame; diff --git a/Python/compile.c b/Python/compile.c index 68bbd5a33176d5..6d13bad79d4707 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -2892,6 +2892,8 @@ static int compiler_addcompare(struct compiler *c, location loc, default: Py_UNREACHABLE(); } + /* cmp goes in top bits of the oparg, while the low bits are used by quickened + * versions of this opcode to store the comparison mask. */ ADDOP_I(c, loc, COMPARE_OP, (cmp << 4) | compare_masks[cmp]); return SUCCESS; } From e93b6fe9014a845b8d4f75c1079ab8dec706749b Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 9 Mar 2023 17:35:47 -0800 Subject: [PATCH 4/8] Bump magic number --- Lib/importlib/_bootstrap_external.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 954401cfa85ed3..2829a6f87d1d92 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -435,6 +435,8 @@ def _write_atomic(path, data, mode=0o666): # Python 3.12a5 3519 (Modify SEND instruction) # Python 3.12a5 3520 (Remove PREP_RERAISE_STAR, add CALL_INTRINSIC_2) +# Python 3.12a7 3522 (Convert COMPARE_AND_BRANCH back to COMPARE_OP) + # Python 3.13 will start with 3550 # MAGIC must change whenever the bytecode emitted by the compiler may no @@ -446,7 +448,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3520).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3522).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c From fd42c6327da18e423afc8a20ffafa7b0c47abb1e Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 9 Mar 2023 17:35:56 -0800 Subject: [PATCH 5/8] Fixup bytecodes.c --- Python/bytecodes.c | 7 +++++++ Python/generated_cases.c.h | 1 + 2 files changed, 8 insertions(+) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 88e908e546c6c3..f9057870095c0f 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1714,6 +1714,13 @@ dummy_func( Py_DECREF(owner); } + family(compare_op, INLINE_CACHE_ENTRIES_COMPARE_OP) = { + COMPARE_OP, + COMPARE_OP_FLOAT, + COMPARE_OP_INT, + COMPARE_OP_STR, + }; + inst(COMPARE_OP, (unused/1, left, right -- res)) { #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index b4ed77e958ded3..46873b574bacfe 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2161,6 +2161,7 @@ TARGET(COMPARE_OP) { PREDICTED(COMPARE_OP); + static_assert(INLINE_CACHE_ENTRIES_COMPARE_OP == 1, "incorrect cache size"); PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; From eaf0fc6680f71e08995153cfaf63002520b89dd1 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Fri, 17 Mar 2023 12:09:54 -0700 Subject: [PATCH 6/8] blurb add --- .../2023-03-17-12-09-45.gh-issue-100982.Pf_BI6.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-100982.Pf_BI6.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-100982.Pf_BI6.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-100982.Pf_BI6.rst new file mode 100644 index 00000000000000..087cabdd656bb2 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-100982.Pf_BI6.rst @@ -0,0 +1 @@ +Replace all occurrences of `COMPARE_AND_BRANCH` with :opcode:`COMPARE_OP`. From e911d60a1e2afa2951c8375ef47389e6aa99123a Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Fri, 17 Mar 2023 12:13:08 -0700 Subject: [PATCH 7/8] fixup --- .../2023-03-17-12-09-45.gh-issue-100982.Pf_BI6.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-100982.Pf_BI6.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-100982.Pf_BI6.rst index 087cabdd656bb2..31a8660836c759 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-100982.Pf_BI6.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-100982.Pf_BI6.rst @@ -1 +1 @@ -Replace all occurrences of `COMPARE_AND_BRANCH` with :opcode:`COMPARE_OP`. +Replace all occurrences of ``COMPARE_AND_BRANCH`` with :opcode:`COMPARE_OP`. From 94b38369e0e321d770c1f0c0a785f19423b71fc1 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sun, 19 Mar 2023 20:34:36 -0700 Subject: [PATCH 8/8] Sorry, Eric! --- Python/compile.c | 2 +- Tools/c-analyzer/cpython/ignored.tsv | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 355f847835ec95..c068b99d31f16e 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -2762,7 +2762,7 @@ check_compare(struct compiler *c, expr_ty e) return SUCCESS; } -static int compare_masks[] = { +static const int compare_masks[] = { [Py_LT] = COMPARISON_LESS_THAN, [Py_LE] = COMPARISON_LESS_THAN | COMPARISON_EQUALS, [Py_EQ] = COMPARISON_EQUALS, diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 048112dd992555..585187b3d4da98 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -350,7 +350,6 @@ Python/pylifecycle.c - INTERPRETER_TRAMPOLINE_CODEDEF - Python/pystate.c - initial - Python/specialize.c - adaptive_opcodes - Python/specialize.c - cache_requirements - -Python/specialize.c - compare_masks - Python/stdlib_module_names.h - _Py_stdlib_module_names - Python/sysmodule.c - _PySys_ImplCacheTag - Python/sysmodule.c - _PySys_ImplName -