🌐 AI搜索 & 代理 主页
Skip to content
Next Next commit
Add COMPARE_AND_BRANCH instruction
  • Loading branch information
markshannon committed Jan 12, 2023
commit e5059b293f5bf8253178126e264d57bb09d61bca
2 changes: 2 additions & 0 deletions Include/internal/pycore_code.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,8 @@ extern void _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *
int oparg, PyObject **locals);
extern void _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs,
_Py_CODEUNIT *instr, int oparg);
extern void _Py_Specialize_CompareAndBranch(PyObject *lhs, PyObject *rhs,
_Py_CODEUNIT *instr, int oparg);
extern void _Py_Specialize_UnpackSequence(PyObject *seq, _Py_CODEUNIT *instr,
int oparg);
extern void _Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr, int oparg);
Expand Down
23 changes: 12 additions & 11 deletions Include/internal/pycore_opcode.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 10 additions & 9 deletions Include/opcode.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Lib/importlib/_bootstrap_external.py
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ def _write_atomic(path, data, mode=0o666):
# Python 3.12a1 3513 (Add CALL_INTRINSIC_1 instruction, removed STOPITERATION_ERROR, PRINT_EXPR, IMPORT_STAR)
# Python 3.12a1 3514 (Remove ASYNC_GEN_WRAP, LIST_TO_TUPLE, and UNARY_POSITIVE)
# Python 3.12a1 3515 (Embed jump mask in COMPARE_OP oparg)
# Python 3.12a1 3516 (Add COMAPRE_AND_BRANCH instruction)

# Python 3.13 will start with 3550

Expand All @@ -441,7 +442,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 = (3515).to_bytes(2, 'little') + b'\r\n'
MAGIC_NUMBER = (3516).to_bytes(2, 'little') + b'\r\n'

_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c

Expand Down
14 changes: 9 additions & 5 deletions Lib/opcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,8 @@ 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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This opcode needs to be in hasjrel as well.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that dis sees COMPARE_AND_BRANCH, then POP_JUMP_IF_. The POP_JUMP_IF_ is where we jump from.
So marking COMPARE_AND_BRANCH as a jump confuses dis, it thinks the operator is a jump offset. COMPARE_AND_BRANCH is effectively a superinstruction.

I could special case COMPARE_AND_BRANCH in dis, but I think it might be better to wait for proper support for longer instructions.

def_op('CALL_FUNCTION_EX', 142) # Flags

def_op('EXTENDED_ARG', 144)
Expand Down Expand Up @@ -309,10 +310,10 @@ def pseudo_op(name, op, real_ops):
"CALL_NO_KW_TUPLE_1",
"CALL_NO_KW_TYPE_1",
],
"COMPARE_OP": [
"COMPARE_OP_FLOAT_JUMP",
"COMPARE_OP_INT_JUMP",
"COMPARE_OP_STR_JUMP",
"COMPARE_AND_BRANCH": [
"COMPARE_AND_BRANCH_FLOAT",
"COMPARE_AND_BRANCH_INT",
"COMPARE_AND_BRANCH_STR",
],
"FOR_ITER": [
"FOR_ITER_LIST",
Expand Down Expand Up @@ -392,6 +393,9 @@ def pseudo_op(name, op, real_ops):
"COMPARE_OP": {
"counter": 1,
},
"COMPARE_AND_BRANCH": {
"counter": 1,
},
"BINARY_SUBSCR": {
"counter": 1,
"type_version": 2,
Expand Down
14 changes: 7 additions & 7 deletions Lib/test/test_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -1121,11 +1121,11 @@ def aug():
check_op_count(aug, "BUILD_SLICE", 0)

def test_compare_positions(self):
for opname, op in [
("COMPARE_OP", "<"),
("COMPARE_OP", "<="),
("COMPARE_OP", ">"),
("COMPARE_OP", ">="),
for opname_prefix, op in [
("COMPARE_", "<"),
("COMPARE_", "<="),
("COMPARE_", ">"),
("COMPARE_", ">="),
("CONTAINS_OP", "in"),
("CONTAINS_OP", "not in"),
("IS_OP", "is"),
Expand All @@ -1140,7 +1140,7 @@ def test_compare_positions(self):
actual_positions = [
instruction.positions
for instruction in dis.get_instructions(code)
if instruction.opname == opname
if instruction.opname.startswith(opname_prefix)
]
with self.subTest(source):
self.assertEqual(actual_positions, expected_positions)
Expand Down Expand Up @@ -1270,7 +1270,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_OP',
self.assertOpcodeSourcePositionIs(compiled_code, 'COMPARE_AND_BRANCH',
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',
Expand Down
8 changes: 4 additions & 4 deletions Lib/test/test_dis.py
Original file line number Diff line number Diff line change
Expand Up @@ -1561,12 +1561,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=13, argval='<', argrepr='<', offset=64, 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='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=68, argval='>', argrepr='>', offset=76, 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='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),
Expand All @@ -1588,12 +1588,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=75, argval='>', argrepr='>', offset=160, 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='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=13, argval='<', argrepr='<', offset=172, 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='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),
Expand Down
8 changes: 8 additions & 0 deletions Objects/frameobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,14 @@ 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);
Expand Down
Loading