GH-105229: Replace some superinstructions with single instruction equivalent. (GH-105230)

This commit is contained in:
Mark Shannon 2023-06-05 11:07:04 +01:00 committed by GitHub
parent e8ecb9ee6b
commit 0689340366
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 731 additions and 686 deletions

View file

@ -177,8 +177,8 @@ const uint8_t _PyOpcode_Deopt[256] = {
[LOAD_FAST] = LOAD_FAST, [LOAD_FAST] = LOAD_FAST,
[LOAD_FAST_AND_CLEAR] = LOAD_FAST_AND_CLEAR, [LOAD_FAST_AND_CLEAR] = LOAD_FAST_AND_CLEAR,
[LOAD_FAST_CHECK] = LOAD_FAST_CHECK, [LOAD_FAST_CHECK] = LOAD_FAST_CHECK,
[LOAD_FAST_LOAD_FAST] = LOAD_FAST_LOAD_FAST,
[LOAD_FAST__LOAD_CONST] = LOAD_FAST, [LOAD_FAST__LOAD_CONST] = LOAD_FAST,
[LOAD_FAST__LOAD_FAST] = LOAD_FAST,
[LOAD_FROM_DICT_OR_DEREF] = LOAD_FROM_DICT_OR_DEREF, [LOAD_FROM_DICT_OR_DEREF] = LOAD_FROM_DICT_OR_DEREF,
[LOAD_FROM_DICT_OR_GLOBALS] = LOAD_FROM_DICT_OR_GLOBALS, [LOAD_FROM_DICT_OR_GLOBALS] = LOAD_FROM_DICT_OR_GLOBALS,
[LOAD_GLOBAL] = LOAD_GLOBAL, [LOAD_GLOBAL] = LOAD_GLOBAL,
@ -223,8 +223,8 @@ const uint8_t _PyOpcode_Deopt[256] = {
[STORE_ATTR_WITH_HINT] = STORE_ATTR, [STORE_ATTR_WITH_HINT] = STORE_ATTR,
[STORE_DEREF] = STORE_DEREF, [STORE_DEREF] = STORE_DEREF,
[STORE_FAST] = STORE_FAST, [STORE_FAST] = STORE_FAST,
[STORE_FAST__LOAD_FAST] = STORE_FAST, [STORE_FAST_LOAD_FAST] = STORE_FAST_LOAD_FAST,
[STORE_FAST__STORE_FAST] = STORE_FAST, [STORE_FAST_STORE_FAST] = STORE_FAST_STORE_FAST,
[STORE_GLOBAL] = STORE_GLOBAL, [STORE_GLOBAL] = STORE_GLOBAL,
[STORE_NAME] = STORE_NAME, [STORE_NAME] = STORE_NAME,
[STORE_SLICE] = STORE_SLICE, [STORE_SLICE] = STORE_SLICE,
@ -335,7 +335,7 @@ static const char *const _PyOpcode_OpName[267] = {
[SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS",
[LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST", [LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST",
[LOAD_LOCALS] = "LOAD_LOCALS", [LOAD_LOCALS] = "LOAD_LOCALS",
[LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN",
[POP_EXCEPT] = "POP_EXCEPT", [POP_EXCEPT] = "POP_EXCEPT",
[STORE_NAME] = "STORE_NAME", [STORE_NAME] = "STORE_NAME",
[DELETE_NAME] = "DELETE_NAME", [DELETE_NAME] = "DELETE_NAME",
@ -358,9 +358,9 @@ static const char *const _PyOpcode_OpName[267] = {
[IMPORT_NAME] = "IMPORT_NAME", [IMPORT_NAME] = "IMPORT_NAME",
[IMPORT_FROM] = "IMPORT_FROM", [IMPORT_FROM] = "IMPORT_FROM",
[JUMP_FORWARD] = "JUMP_FORWARD", [JUMP_FORWARD] = "JUMP_FORWARD",
[LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN",
[LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE",
[STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE",
[STORE_ATTR_SLOT] = "STORE_ATTR_SLOT",
[POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE", [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE",
[POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE", [POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE",
[LOAD_GLOBAL] = "LOAD_GLOBAL", [LOAD_GLOBAL] = "LOAD_GLOBAL",
@ -395,29 +395,29 @@ static const char *const _PyOpcode_OpName[267] = {
[LIST_APPEND] = "LIST_APPEND", [LIST_APPEND] = "LIST_APPEND",
[SET_ADD] = "SET_ADD", [SET_ADD] = "SET_ADD",
[MAP_ADD] = "MAP_ADD", [MAP_ADD] = "MAP_ADD",
[STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT",
[COPY_FREE_VARS] = "COPY_FREE_VARS", [COPY_FREE_VARS] = "COPY_FREE_VARS",
[YIELD_VALUE] = "YIELD_VALUE", [YIELD_VALUE] = "YIELD_VALUE",
[RESUME] = "RESUME", [RESUME] = "RESUME",
[MATCH_CLASS] = "MATCH_CLASS", [MATCH_CLASS] = "MATCH_CLASS",
[STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT",
[STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT",
[FORMAT_VALUE] = "FORMAT_VALUE", [FORMAT_VALUE] = "FORMAT_VALUE",
[BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP",
[BUILD_STRING] = "BUILD_STRING", [BUILD_STRING] = "BUILD_STRING",
[STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST",
[STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT",
[STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT",
[UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST",
[UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE",
[UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE",
[SEND_GEN] = "SEND_GEN",
[LIST_EXTEND] = "LIST_EXTEND", [LIST_EXTEND] = "LIST_EXTEND",
[SET_UPDATE] = "SET_UPDATE", [SET_UPDATE] = "SET_UPDATE",
[DICT_MERGE] = "DICT_MERGE", [DICT_MERGE] = "DICT_MERGE",
[DICT_UPDATE] = "DICT_UPDATE", [DICT_UPDATE] = "DICT_UPDATE",
[UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", [166] = "<166>",
[UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", [167] = "<167>",
[SEND_GEN] = "SEND_GEN", [LOAD_FAST_LOAD_FAST] = "LOAD_FAST_LOAD_FAST",
[169] = "<169>", [STORE_FAST_LOAD_FAST] = "STORE_FAST_LOAD_FAST",
[170] = "<170>", [STORE_FAST_STORE_FAST] = "STORE_FAST_STORE_FAST",
[CALL] = "CALL", [CALL] = "CALL",
[KW_NAMES] = "KW_NAMES", [KW_NAMES] = "KW_NAMES",
[CALL_INTRINSIC_1] = "CALL_INTRINSIC_1", [CALL_INTRINSIC_1] = "CALL_INTRINSIC_1",
@ -518,8 +518,8 @@ static const char *const _PyOpcode_OpName[267] = {
#endif #endif
#define EXTRA_CASES \ #define EXTRA_CASES \
case 169: \ case 166: \
case 170: \ case 167: \
case 177: \ case 177: \
case 178: \ case 178: \
case 179: \ case 179: \

View file

@ -56,11 +56,8 @@ extern "C" {
(opcode) == RERAISE) (opcode) == RERAISE)
#define IS_SUPERINSTRUCTION_OPCODE(opcode) \ #define IS_SUPERINSTRUCTION_OPCODE(opcode) \
((opcode) == LOAD_FAST__LOAD_FAST || \ ((opcode) == LOAD_FAST__LOAD_CONST || \
(opcode) == LOAD_FAST__LOAD_CONST || \ (opcode) == LOAD_CONST__LOAD_FAST)
(opcode) == LOAD_CONST__LOAD_FAST || \
(opcode) == STORE_FAST__LOAD_FAST || \
(opcode) == STORE_FAST__STORE_FAST)
#define LOG_BITS_PER_INT 5 #define LOG_BITS_PER_INT 5

28
Include/opcode.h generated
View file

@ -114,6 +114,9 @@ extern "C" {
#define SET_UPDATE 163 #define SET_UPDATE 163
#define DICT_MERGE 164 #define DICT_MERGE 164
#define DICT_UPDATE 165 #define DICT_UPDATE 165
#define LOAD_FAST_LOAD_FAST 168
#define STORE_FAST_LOAD_FAST 169
#define STORE_FAST_STORE_FAST 170
#define CALL 171 #define CALL 171
#define KW_NAMES 172 #define KW_NAMES 172
#define CALL_INTRINSIC_1 173 #define CALL_INTRINSIC_1 173
@ -203,20 +206,17 @@ extern "C" {
#define LOAD_ATTR_METHOD_WITH_VALUES 82 #define LOAD_ATTR_METHOD_WITH_VALUES 82
#define LOAD_CONST__LOAD_FAST 84 #define LOAD_CONST__LOAD_FAST 84
#define LOAD_FAST__LOAD_CONST 86 #define LOAD_FAST__LOAD_CONST 86
#define LOAD_FAST__LOAD_FAST 88 #define LOAD_GLOBAL_BUILTIN 88
#define LOAD_GLOBAL_BUILTIN 111 #define LOAD_GLOBAL_MODULE 111
#define LOAD_GLOBAL_MODULE 112 #define STORE_ATTR_INSTANCE_VALUE 112
#define STORE_ATTR_INSTANCE_VALUE 113 #define STORE_ATTR_SLOT 113
#define STORE_ATTR_SLOT 148 #define STORE_ATTR_WITH_HINT 148
#define STORE_ATTR_WITH_HINT 153 #define STORE_SUBSCR_DICT 153
#define STORE_FAST__LOAD_FAST 154 #define STORE_SUBSCR_LIST_INT 154
#define STORE_FAST__STORE_FAST 158 #define UNPACK_SEQUENCE_LIST 158
#define STORE_SUBSCR_DICT 159 #define UNPACK_SEQUENCE_TUPLE 159
#define STORE_SUBSCR_LIST_INT 160 #define UNPACK_SEQUENCE_TWO_TUPLE 160
#define UNPACK_SEQUENCE_LIST 161 #define SEND_GEN 161
#define UNPACK_SEQUENCE_TUPLE 166
#define UNPACK_SEQUENCE_TWO_TUPLE 167
#define SEND_GEN 168
#define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\
|| ((op) == JUMP) \ || ((op) == JUMP) \

View file

@ -46,6 +46,9 @@ LOAD_ATTR = opmap['LOAD_ATTR']
LOAD_SUPER_ATTR = opmap['LOAD_SUPER_ATTR'] LOAD_SUPER_ATTR = opmap['LOAD_SUPER_ATTR']
CALL_INTRINSIC_1 = opmap['CALL_INTRINSIC_1'] CALL_INTRINSIC_1 = opmap['CALL_INTRINSIC_1']
CALL_INTRINSIC_2 = opmap['CALL_INTRINSIC_2'] CALL_INTRINSIC_2 = opmap['CALL_INTRINSIC_2']
LOAD_FAST_LOAD_FAST = opmap['LOAD_FAST_LOAD_FAST']
STORE_FAST_LOAD_FAST = opmap['STORE_FAST_LOAD_FAST']
STORE_FAST_STORE_FAST = opmap['STORE_FAST_STORE_FAST']
CACHE = opmap["CACHE"] CACHE = opmap["CACHE"]
@ -493,6 +496,13 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
argval = offset + 2 + signed_arg*2 argval = offset + 2 + signed_arg*2
argval += 2 * caches argval += 2 * caches
argrepr = "to " + repr(argval) argrepr = "to " + repr(argval)
elif deop in (LOAD_FAST_LOAD_FAST, STORE_FAST_LOAD_FAST, STORE_FAST_STORE_FAST):
arg1 = arg >> 4
arg2 = arg & 15
val1, argrepr1 = _get_name_info(arg1, varname_from_oparg)
val2, argrepr2 = _get_name_info(arg2, varname_from_oparg)
argrepr = argrepr1 + ", " + argrepr2
argval = val1, val2
elif deop in haslocal or deop in hasfree: elif deop in haslocal or deop in hasfree:
argval, argrepr = _get_name_info(arg, varname_from_oparg) argval, argrepr = _get_name_info(arg, varname_from_oparg)
elif deop in hascompare: elif deop in hascompare:

View file

@ -446,6 +446,7 @@ _code_type = type(_write_atomic.__code__)
# Python 3.12b1 3530 (Shrink the LOAD_SUPER_ATTR caches) # Python 3.12b1 3530 (Shrink the LOAD_SUPER_ATTR caches)
# Python 3.12b1 3531 (Add PEP 695 changes) # Python 3.12b1 3531 (Add PEP 695 changes)
# Python 3.13a1 3550 (Plugin optimizer support) # Python 3.13a1 3550 (Plugin optimizer support)
# Python 3.13a1 3551 (Compact superinstructions)
# Python 3.14 will start with 3600 # Python 3.14 will start with 3600
@ -462,7 +463,7 @@ _code_type = type(_write_atomic.__code__)
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
# in PC/launcher.c must also be updated. # in PC/launcher.c must also be updated.
MAGIC_NUMBER = (3550).to_bytes(2, 'little') + b'\r\n' MAGIC_NUMBER = (3551).to_bytes(2, 'little') + b'\r\n'
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c

View file

@ -222,6 +222,9 @@ def_op('SET_UPDATE', 163)
def_op('DICT_MERGE', 164) def_op('DICT_MERGE', 164)
def_op('DICT_UPDATE', 165) def_op('DICT_UPDATE', 165)
def_op('LOAD_FAST_LOAD_FAST', 168)
def_op('STORE_FAST_LOAD_FAST', 169)
def_op('STORE_FAST_STORE_FAST', 170)
def_op('CALL', 171) def_op('CALL', 171)
def_op('KW_NAMES', 172) def_op('KW_NAMES', 172)
hasconst.append(172) hasconst.append(172)
@ -411,7 +414,6 @@ _specializations = {
], ],
"LOAD_FAST": [ "LOAD_FAST": [
"LOAD_FAST__LOAD_CONST", "LOAD_FAST__LOAD_CONST",
"LOAD_FAST__LOAD_FAST",
], ],
"LOAD_GLOBAL": [ "LOAD_GLOBAL": [
"LOAD_GLOBAL_BUILTIN", "LOAD_GLOBAL_BUILTIN",
@ -422,10 +424,6 @@ _specializations = {
"STORE_ATTR_SLOT", "STORE_ATTR_SLOT",
"STORE_ATTR_WITH_HINT", "STORE_ATTR_WITH_HINT",
], ],
"STORE_FAST": [
"STORE_FAST__LOAD_FAST",
"STORE_FAST__STORE_FAST",
],
"STORE_SUBSCR": [ "STORE_SUBSCR": [
"STORE_SUBSCR_DICT", "STORE_SUBSCR_DICT",
"STORE_SUBSCR_LIST_INT", "STORE_SUBSCR_LIST_INT",

View file

@ -760,15 +760,12 @@ def load_test(x, y=0):
dis_load_test_quickened_code = """\ dis_load_test_quickened_code = """\
%3d 0 RESUME 0 %3d 0 RESUME 0
%3d 2 LOAD_FAST__LOAD_FAST 0 (x) %3d 2 LOAD_FAST_LOAD_FAST 1 (x, y)
4 LOAD_FAST 1 (y) 4 STORE_FAST_STORE_FAST 50 (b, a)
6 STORE_FAST__STORE_FAST 3 (b)
8 STORE_FAST__LOAD_FAST 2 (a)
%3d 10 LOAD_FAST__LOAD_FAST 2 (a) %3d 6 LOAD_FAST_LOAD_FAST 35 (a, b)
12 LOAD_FAST 3 (b) 8 BUILD_TUPLE 2
14 BUILD_TUPLE 2 10 RETURN_VALUE
16 RETURN_VALUE
""" % (load_test.__code__.co_firstlineno, """ % (load_test.__code__.co_firstlineno,
load_test.__code__.co_firstlineno + 1, load_test.__code__.co_firstlineno + 1,
load_test.__code__.co_firstlineno + 2) load_test.__code__.co_firstlineno + 2)
@ -811,9 +808,8 @@ dis_extended_arg_quick_code = """\
%3d 2 LOAD_CONST 1 (Ellipsis) %3d 2 LOAD_CONST 1 (Ellipsis)
4 EXTENDED_ARG 1 4 EXTENDED_ARG 1
6 UNPACK_EX 256 6 UNPACK_EX 256
8 STORE_FAST 0 (_) 8 STORE_FAST_STORE_FAST 0 (_, _)
10 STORE_FAST 0 (_) 10 RETURN_CONST 0 (None)
12 RETURN_CONST 0 (None)
"""% (extended_arg_quick.__code__.co_firstlineno, """% (extended_arg_quick.__code__.co_firstlineno,
extended_arg_quick.__code__.co_firstlineno + 1,) extended_arg_quick.__code__.co_firstlineno + 1,)
@ -1026,26 +1022,28 @@ class DisTests(DisTestBase):
s = ['''\ s = ['''\
1 %*d RESUME 0 1 %*d RESUME 0
''' % (w, 0)] 2 %*d LOAD_FAST 0 (x)
s += ['''\
%*d LOAD_FAST 0 (x)
%*d LOAD_CONST 1 (1) %*d LOAD_CONST 1 (1)
%*d BINARY_OP 0 (+) %*d BINARY_OP 0 (+)
%*d STORE_FAST 0 (x) ''' % (w, 0, w, 2, w, 4, w, 6)]
''' % (w, 10*i + 2, w, 10*i + 4, w, 10*i + 6, w, 10*i + 10)
for i in range(count)]
s += ['''\ s += ['''\
%*d STORE_FAST_LOAD_FAST 0 (x, x)
%*d LOAD_CONST 1 (1)
%*d BINARY_OP 0 (+)
''' % (w, 8*i + 10, w, 8*i + 12, w, 8*i + 14)
for i in range(count-1)]
s += ['''\
%*d STORE_FAST 0 (x)
3 %*d LOAD_FAST 0 (x) 3 %*d LOAD_FAST 0 (x)
%*d RETURN_VALUE %*d RETURN_VALUE
''' % (w, 10*count + 2, w, 10*count + 4)] ''' % (w, 8*count + 2, w, 8*count + 4, w, 8*count + 6)]
s[1] = ' 2' + s[1][3:]
return ''.join(s) return ''.join(s)
for i in range(1, 5): for i in range(1, 5):
self.do_disassembly_test(func(i), expected(i, 4), True) self.do_disassembly_test(func(i), expected(i, 4), True)
self.do_disassembly_test(func(999), expected(999, 4), True) self.do_disassembly_test(func(1200), expected(1200, 4), True)
self.do_disassembly_test(func(1000), expected(1000, 5), True) self.do_disassembly_test(func(1300), expected(1300, 5), True)
def test_disassemble_str(self): def test_disassemble_str(self):
self.do_disassembly_test(expr_str, dis_expr_str) self.do_disassembly_test(expr_str, dis_expr_str)
@ -1646,11 +1644,10 @@ expected_opinfo_inner = [
Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='b', argrepr='b', offset=16, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='b', argrepr='b', offset=16, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='c', argrepr='c', offset=18, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='c', argrepr='c', offset=18, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_DEREF', opcode=137, arg=5, argval='d', argrepr='d', offset=20, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_DEREF', opcode=137, arg=5, argval='d', argrepr='d', offset=20, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='e', argrepr='e', offset=22, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST_LOAD_FAST', opcode=168, arg=1, argval=('e', 'f'), argrepr='e, f', offset=22, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='f', argrepr='f', offset=24, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=6, argval=6, argrepr='', offset=24, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=6, argval=6, argrepr='', offset=26, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=32, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=34, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RETURN_CONST', opcode=121, arg=0, argval=None, argrepr='None', offset=34, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RETURN_CONST', opcode=121, arg=0, argval=None, argrepr='None', offset=36, starts_line=None, is_jump_target=False, positions=None),
] ]

View file

@ -1158,8 +1158,8 @@ class TestBranchAndJumpEvents(CheckEvents):
('line', 'func', 5), ('line', 'func', 5),
('line', 'meth', 1), ('line', 'meth', 1),
('jump', 'func', 5, 5), ('jump', 'func', 5, 5),
('jump', 'func', 5, '[offset=114]'), ('jump', 'func', 5, '[offset=112]'),
('branch', 'func', '[offset=120]', '[offset=122]'), ('branch', 'func', '[offset=118]', '[offset=120]'),
('line', 'check_events', 11)]) ('line', 'check_events', 11)])
self.check_events(func, recorders = FLOW_AND_LINE_RECORDERS, expected = [ self.check_events(func, recorders = FLOW_AND_LINE_RECORDERS, expected = [
@ -1174,8 +1174,8 @@ class TestBranchAndJumpEvents(CheckEvents):
('line', 'meth', 1), ('line', 'meth', 1),
('return', None), ('return', None),
('jump', 'func', 5, 5), ('jump', 'func', 5, 5),
('jump', 'func', 5, '[offset=114]'), ('jump', 'func', 5, '[offset=112]'),
('branch', 'func', '[offset=120]', '[offset=122]'), ('branch', 'func', '[offset=118]', '[offset=120]'),
('return', None), ('return', None),
('line', 'check_events', 11)]) ('line', 'check_events', 11)])

View file

@ -686,7 +686,7 @@ class TestMarkingVariablesAsUnKnown(BytecodeTestCase):
def f(): def f():
x = 1 x = 1
y = x + x y = x + x
self.assertInBytecode(f, 'LOAD_FAST') self.assertInBytecode(f, 'LOAD_FAST_LOAD_FAST')
def test_load_fast_unknown_simple(self): def test_load_fast_unknown_simple(self):
def f(): def f():
@ -790,7 +790,10 @@ class TestMarkingVariablesAsUnKnown(BytecodeTestCase):
print(a00, a01, a62, a63) print(a00, a01, a62, a63)
print(a64, a65, a78, a79) print(a64, a65, a78, a79)
for i in 0, 1, 62, 63: self.assertInBytecode(f, 'LOAD_FAST_LOAD_FAST', ("a00", "a01"))
self.assertNotInBytecode(f, 'LOAD_FAST_CHECK', "a00")
self.assertNotInBytecode(f, 'LOAD_FAST_CHECK', "a01")
for i in 62, 63:
# First 64 locals: analyze completely # First 64 locals: analyze completely
self.assertInBytecode(f, 'LOAD_FAST', f"a{i:02}") self.assertInBytecode(f, 'LOAD_FAST', f"a{i:02}")
self.assertNotInBytecode(f, 'LOAD_FAST_CHECK', f"a{i:02}") self.assertNotInBytecode(f, 'LOAD_FAST_CHECK', f"a{i:02}")
@ -1071,7 +1074,16 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase):
('POP_TOP', 0, 4), ('POP_TOP', 0, 4),
('RETURN_VALUE', 5) ('RETURN_VALUE', 5)
] ]
self.cfg_optimization_test(insts, insts, consts=list(range(3)), nlocals=1) expected_insts = [
('LOAD_CONST', 0, 1),
('LOAD_CONST', 1, 2),
('LOAD_CONST', 2, 3),
('SWAP', 3, 4),
('STORE_FAST_STORE_FAST', 17, 4),
('POP_TOP', 0, 4),
('RETURN_VALUE', 5)
]
self.cfg_optimization_test(insts, expected_insts, consts=list(range(3)), nlocals=1)
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -0,0 +1 @@
Replace some dynamic superinstructions with single instruction equivalents.

View file

@ -201,6 +201,15 @@ dummy_func(
GETLOCAL(oparg) = NULL; GETLOCAL(oparg) = NULL;
} }
inst(LOAD_FAST_LOAD_FAST, ( -- value1, value2)) {
uint32_t oparg1 = oparg >> 4;
uint32_t oparg2 = oparg & 15;
value1 = GETLOCAL(oparg1);
value2 = GETLOCAL(oparg2);
Py_INCREF(value1);
Py_INCREF(value2);
}
inst(LOAD_CONST, (-- value)) { inst(LOAD_CONST, (-- value)) {
value = GETITEM(frame->f_code->co_consts, oparg); value = GETITEM(frame->f_code->co_consts, oparg);
Py_INCREF(value); Py_INCREF(value);
@ -210,10 +219,22 @@ dummy_func(
SETLOCAL(oparg, value); SETLOCAL(oparg, value);
} }
super(LOAD_FAST__LOAD_FAST) = LOAD_FAST + LOAD_FAST; inst(STORE_FAST_LOAD_FAST, (value1 -- value2)) {
uint32_t oparg1 = oparg >> 4;
uint32_t oparg2 = oparg & 15;
SETLOCAL(oparg1, value1);
value2 = GETLOCAL(oparg2);
Py_INCREF(value2);
}
inst(STORE_FAST_STORE_FAST, (value2, value1 --)) {
uint32_t oparg1 = oparg >> 4;
uint32_t oparg2 = oparg & 15;
SETLOCAL(oparg1, value1);
SETLOCAL(oparg2, value2);
}
super(LOAD_FAST__LOAD_CONST) = LOAD_FAST + LOAD_CONST; super(LOAD_FAST__LOAD_CONST) = LOAD_FAST + LOAD_CONST;
super(STORE_FAST__LOAD_FAST) = STORE_FAST + LOAD_FAST;
super(STORE_FAST__STORE_FAST) = STORE_FAST + STORE_FAST;
super(LOAD_CONST__LOAD_FAST) = LOAD_CONST + LOAD_FAST; super(LOAD_CONST__LOAD_FAST) = LOAD_CONST + LOAD_FAST;
inst(POP_TOP, (value --)) { inst(POP_TOP, (value --)) {
@ -386,8 +407,7 @@ dummy_func(
// At the end we just skip over the STORE_FAST. // At the end we just skip over the STORE_FAST.
op(_BINARY_OP_INPLACE_ADD_UNICODE, (left, right --)) { op(_BINARY_OP_INPLACE_ADD_UNICODE, (left, right --)) {
_Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP]; _Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP];
assert(true_next.op.code == STORE_FAST || assert(true_next.op.code == STORE_FAST);
true_next.op.code == STORE_FAST__LOAD_FAST);
PyObject **target_local = &GETLOCAL(true_next.op.arg); PyObject **target_local = &GETLOCAL(true_next.op.arg);
DEOPT_IF(*target_local != left, BINARY_OP); DEOPT_IF(*target_local != left, BINARY_OP);
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
@ -3484,5 +3504,3 @@ dummy_func(
} }
// Future families go below this point // // Future families go below this point //
family(store_fast) = { STORE_FAST, STORE_FAST__LOAD_FAST, STORE_FAST__STORE_FAST };

View file

@ -1586,6 +1586,56 @@ optimize_cfg(cfg_builder *g, PyObject *consts, PyObject *const_cache)
return SUCCESS; return SUCCESS;
} }
static void
make_super_instruction(cfg_instr *inst1, cfg_instr *inst2, int super_op)
{
int32_t line1 = inst1->i_loc.lineno;
int32_t line2 = inst2->i_loc.lineno;
/* Skip if instructions are on different lines */
if (line1 >= 0 && line2 >= 0 && line1 != line2) {
return;
}
if (inst1->i_oparg >= 16 || inst2->i_oparg >= 16) {
return;
}
INSTR_SET_OP1(inst1, super_op, (inst1->i_oparg << 4) | inst2->i_oparg);
INSTR_SET_OP0(inst2, NOP);
}
static void
insert_superinstructions(cfg_builder *g)
{
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
for (int i = 0; i < b->b_iused; i++) {
cfg_instr *inst = &b->b_instr[i];
int nextop = i+1 < b->b_iused ? b->b_instr[i+1].i_opcode : 0;
switch(inst->i_opcode) {
case LOAD_FAST:
if (nextop == LOAD_FAST) {
make_super_instruction(inst, &b->b_instr[i + 1], LOAD_FAST_LOAD_FAST);
}
break;
case STORE_FAST:
switch (nextop) {
case LOAD_FAST:
make_super_instruction(inst, &b->b_instr[i + 1], STORE_FAST_LOAD_FAST);
break;
case STORE_FAST:
make_super_instruction(inst, &b->b_instr[i + 1], STORE_FAST_STORE_FAST);
break;
}
break;
}
}
}
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
remove_redundant_nops(b);
}
eliminate_empty_basic_blocks(g);
assert(no_redundant_nops(g));
}
// helper functions for add_checks_for_loads_of_unknown_variables // helper functions for add_checks_for_loads_of_unknown_variables
static inline void static inline void
maybe_push(basicblock *b, uint64_t unsafe_mask, basicblock ***sp) maybe_push(basicblock *b, uint64_t unsafe_mask, basicblock ***sp)
@ -2181,6 +2231,7 @@ _PyCfg_OptimizeCodeUnit(cfg_builder *g, PyObject *consts, PyObject *const_cache,
RETURN_IF_ERROR( RETURN_IF_ERROR(
add_checks_for_loads_of_uninitialized_variables( add_checks_for_loads_of_uninitialized_variables(
g->g_entryblock, nlocals, nparams)); g->g_entryblock, nlocals, nparams));
insert_superinstructions(g);
RETURN_IF_ERROR(push_cold_blocks_to_end(g, code_flags)); RETURN_IF_ERROR(push_cold_blocks_to_end(g, code_flags));
RETURN_IF_ERROR(resolve_line_numbers(g, firstlineno)); RETURN_IF_ERROR(resolve_line_numbers(g, firstlineno));

File diff suppressed because it is too large Load diff

View file

@ -1488,10 +1488,7 @@ update_instrumentation_data(PyCodeObject *code, PyInterpreterState *interp)
} }
static const uint8_t super_instructions[256] = { static const uint8_t super_instructions[256] = {
[LOAD_FAST__LOAD_FAST] = 1,
[LOAD_FAST__LOAD_CONST] = 1, [LOAD_FAST__LOAD_CONST] = 1,
[STORE_FAST__LOAD_FAST] = 1,
[STORE_FAST__STORE_FAST] = 1,
[LOAD_CONST__LOAD_FAST] = 1, [LOAD_CONST__LOAD_FAST] = 1,
}; };

View file

@ -23,18 +23,18 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
return 0; return 0;
case LOAD_FAST_AND_CLEAR: case LOAD_FAST_AND_CLEAR:
return 0; return 0;
case LOAD_FAST_LOAD_FAST:
return 0;
case LOAD_CONST: case LOAD_CONST:
return 0; return 0;
case STORE_FAST: case STORE_FAST:
return 1; return 1;
case LOAD_FAST__LOAD_FAST: case STORE_FAST_LOAD_FAST:
return 0+0; return 1;
case STORE_FAST_STORE_FAST:
return 2;
case LOAD_FAST__LOAD_CONST: case LOAD_FAST__LOAD_CONST:
return 0+0; return 0+0;
case STORE_FAST__LOAD_FAST:
return 1+0;
case STORE_FAST__STORE_FAST:
return 1+1;
case LOAD_CONST__LOAD_FAST: case LOAD_CONST__LOAD_FAST:
return 0+0; return 0+0;
case POP_TOP: case POP_TOP:
@ -421,18 +421,18 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
return 1; return 1;
case LOAD_FAST_AND_CLEAR: case LOAD_FAST_AND_CLEAR:
return 1; return 1;
case LOAD_FAST_LOAD_FAST:
return 2;
case LOAD_CONST: case LOAD_CONST:
return 1; return 1;
case STORE_FAST: case STORE_FAST:
return 0; return 0;
case LOAD_FAST__LOAD_FAST: case STORE_FAST_LOAD_FAST:
return 1+1; return 1;
case STORE_FAST_STORE_FAST:
return 0;
case LOAD_FAST__LOAD_CONST: case LOAD_FAST__LOAD_CONST:
return 1+1; return 1+1;
case STORE_FAST__LOAD_FAST:
return 0+1;
case STORE_FAST__STORE_FAST:
return 0+0;
case LOAD_CONST__LOAD_FAST: case LOAD_CONST__LOAD_FAST:
return 1+1; return 1+1;
case POP_TOP: case POP_TOP:
@ -816,12 +816,12 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = {
[LOAD_FAST_CHECK] = { true, INSTR_FMT_IB }, [LOAD_FAST_CHECK] = { true, INSTR_FMT_IB },
[LOAD_FAST] = { true, INSTR_FMT_IB }, [LOAD_FAST] = { true, INSTR_FMT_IB },
[LOAD_FAST_AND_CLEAR] = { true, INSTR_FMT_IB }, [LOAD_FAST_AND_CLEAR] = { true, INSTR_FMT_IB },
[LOAD_FAST_LOAD_FAST] = { true, INSTR_FMT_IB },
[LOAD_CONST] = { true, INSTR_FMT_IB }, [LOAD_CONST] = { true, INSTR_FMT_IB },
[STORE_FAST] = { true, INSTR_FMT_IB }, [STORE_FAST] = { true, INSTR_FMT_IB },
[LOAD_FAST__LOAD_FAST] = { true, INSTR_FMT_IBIB }, [STORE_FAST_LOAD_FAST] = { true, INSTR_FMT_IB },
[STORE_FAST_STORE_FAST] = { true, INSTR_FMT_IB },
[LOAD_FAST__LOAD_CONST] = { true, INSTR_FMT_IBIB }, [LOAD_FAST__LOAD_CONST] = { true, INSTR_FMT_IBIB },
[STORE_FAST__LOAD_FAST] = { true, INSTR_FMT_IBIB },
[STORE_FAST__STORE_FAST] = { true, INSTR_FMT_IBIB },
[LOAD_CONST__LOAD_FAST] = { true, INSTR_FMT_IBIB }, [LOAD_CONST__LOAD_FAST] = { true, INSTR_FMT_IBIB },
[POP_TOP] = { true, INSTR_FMT_IX }, [POP_TOP] = { true, INSTR_FMT_IX },
[PUSH_NULL] = { true, INSTR_FMT_IX }, [PUSH_NULL] = { true, INSTR_FMT_IX },

View file

@ -87,7 +87,7 @@ static void *opcode_targets[256] = {
&&TARGET_SETUP_ANNOTATIONS, &&TARGET_SETUP_ANNOTATIONS,
&&TARGET_LOAD_FAST__LOAD_CONST, &&TARGET_LOAD_FAST__LOAD_CONST,
&&TARGET_LOAD_LOCALS, &&TARGET_LOAD_LOCALS,
&&TARGET_LOAD_FAST__LOAD_FAST, &&TARGET_LOAD_GLOBAL_BUILTIN,
&&TARGET_POP_EXCEPT, &&TARGET_POP_EXCEPT,
&&TARGET_STORE_NAME, &&TARGET_STORE_NAME,
&&TARGET_DELETE_NAME, &&TARGET_DELETE_NAME,
@ -110,9 +110,9 @@ static void *opcode_targets[256] = {
&&TARGET_IMPORT_NAME, &&TARGET_IMPORT_NAME,
&&TARGET_IMPORT_FROM, &&TARGET_IMPORT_FROM,
&&TARGET_JUMP_FORWARD, &&TARGET_JUMP_FORWARD,
&&TARGET_LOAD_GLOBAL_BUILTIN,
&&TARGET_LOAD_GLOBAL_MODULE, &&TARGET_LOAD_GLOBAL_MODULE,
&&TARGET_STORE_ATTR_INSTANCE_VALUE, &&TARGET_STORE_ATTR_INSTANCE_VALUE,
&&TARGET_STORE_ATTR_SLOT,
&&TARGET_POP_JUMP_IF_FALSE, &&TARGET_POP_JUMP_IF_FALSE,
&&TARGET_POP_JUMP_IF_TRUE, &&TARGET_POP_JUMP_IF_TRUE,
&&TARGET_LOAD_GLOBAL, &&TARGET_LOAD_GLOBAL,
@ -147,29 +147,29 @@ static void *opcode_targets[256] = {
&&TARGET_LIST_APPEND, &&TARGET_LIST_APPEND,
&&TARGET_SET_ADD, &&TARGET_SET_ADD,
&&TARGET_MAP_ADD, &&TARGET_MAP_ADD,
&&TARGET_STORE_ATTR_SLOT, &&TARGET_STORE_ATTR_WITH_HINT,
&&TARGET_COPY_FREE_VARS, &&TARGET_COPY_FREE_VARS,
&&TARGET_YIELD_VALUE, &&TARGET_YIELD_VALUE,
&&TARGET_RESUME, &&TARGET_RESUME,
&&TARGET_MATCH_CLASS, &&TARGET_MATCH_CLASS,
&&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_STORE_SUBSCR_DICT,
&&TARGET_STORE_FAST__LOAD_FAST, &&TARGET_STORE_SUBSCR_LIST_INT,
&&TARGET_FORMAT_VALUE, &&TARGET_FORMAT_VALUE,
&&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_CONST_KEY_MAP,
&&TARGET_BUILD_STRING, &&TARGET_BUILD_STRING,
&&TARGET_STORE_FAST__STORE_FAST,
&&TARGET_STORE_SUBSCR_DICT,
&&TARGET_STORE_SUBSCR_LIST_INT,
&&TARGET_UNPACK_SEQUENCE_LIST, &&TARGET_UNPACK_SEQUENCE_LIST,
&&TARGET_UNPACK_SEQUENCE_TUPLE,
&&TARGET_UNPACK_SEQUENCE_TWO_TUPLE,
&&TARGET_SEND_GEN,
&&TARGET_LIST_EXTEND, &&TARGET_LIST_EXTEND,
&&TARGET_SET_UPDATE, &&TARGET_SET_UPDATE,
&&TARGET_DICT_MERGE, &&TARGET_DICT_MERGE,
&&TARGET_DICT_UPDATE, &&TARGET_DICT_UPDATE,
&&TARGET_UNPACK_SEQUENCE_TUPLE,
&&TARGET_UNPACK_SEQUENCE_TWO_TUPLE,
&&TARGET_SEND_GEN,
&&_unknown_opcode, &&_unknown_opcode,
&&_unknown_opcode, &&_unknown_opcode,
&&TARGET_LOAD_FAST_LOAD_FAST,
&&TARGET_STORE_FAST_LOAD_FAST,
&&TARGET_STORE_FAST_STORE_FAST,
&&TARGET_CALL, &&TARGET_CALL,
&&TARGET_KW_NAMES, &&TARGET_KW_NAMES,
&&TARGET_CALL_INTRINSIC_1, &&TARGET_CALL_INTRINSIC_1,

View file

@ -289,15 +289,6 @@ _PyCode_Quicken(PyCodeObject *code)
case LOAD_FAST << 8 | LOAD_CONST: case LOAD_FAST << 8 | LOAD_CONST:
instructions[i - 1].op.code = LOAD_FAST__LOAD_CONST; instructions[i - 1].op.code = LOAD_FAST__LOAD_CONST;
break; break;
case LOAD_FAST << 8 | LOAD_FAST:
instructions[i - 1].op.code = LOAD_FAST__LOAD_FAST;
break;
case STORE_FAST << 8 | LOAD_FAST:
instructions[i - 1].op.code = STORE_FAST__LOAD_FAST;
break;
case STORE_FAST << 8 | STORE_FAST:
instructions[i - 1].op.code = STORE_FAST__STORE_FAST;
break;
} }
} }
#endif /* ENABLE_SPECIALIZATION */ #endif /* ENABLE_SPECIALIZATION */
@ -1914,8 +1905,7 @@ _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
} }
if (PyUnicode_CheckExact(lhs)) { if (PyUnicode_CheckExact(lhs)) {
_Py_CODEUNIT next = instr[INLINE_CACHE_ENTRIES_BINARY_OP + 1]; _Py_CODEUNIT next = instr[INLINE_CACHE_ENTRIES_BINARY_OP + 1];
bool to_store = (next.op.code == STORE_FAST || bool to_store = (next.op.code == STORE_FAST);
next.op.code == STORE_FAST__LOAD_FAST);
if (to_store && locals[next.op.arg] == lhs) { if (to_store && locals[next.op.arg] == lhs) {
instr->op.code = BINARY_OP_INPLACE_ADD_UNICODE; instr->op.code = BINARY_OP_INPLACE_ADD_UNICODE;
goto success; goto success;