8000 gh-126835: Make CFG optimizer skip over NOP's when looking for const … · python/cpython@91d9544 · GitHub
[go: up one dir, main page]

Skip to content

Commit 91d9544

Browse files
gh-126835: Make CFG optimizer skip over NOP's when looking for const sequence construction (#129703)
Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com>
1 parent 8f9c6fa commit 91d9544

File tree

2 files changed

+290
-73
lines changed

2 files changed

+290
-73
lines changed

Lib/test/test_peepholer.py

Lines changed: 202 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@ def count_instr_recursively(f, opname):
3636
return count
3737

3838

39+
def get_binop_argval(arg):
40+
for i, nb_op in enumerate(opcode._nb_ops):
41+
if arg == nb_op[0]:
42+
return i
43+
assert False, f"{arg} is not a valid BINARY_OP argument."
44+
45+
3946
class TestTranforms(BytecodeTestCase):
4047

4148
def check_jump_targets(self, code):
@@ -518,8 +525,7 @@ def test_folding_subscript(self):
518525
('("a" * 10)[10]', True),
519526
('(1, (1, 2))[2:6][0][2-1]', True),
520527
]
521-
subscr_argval = 26
522-
assert opcode._nb_ops[subscr_argval][0] == 'NB_SUBSCR'
528+
subscr_argval = get_binop_argval('NB_SUBSCR')
523529
for expr, has_error in tests:
524530
with self.subTest(expr=expr, has_error=has_error):
525531
code = compile(expr, '', 'single')
@@ -1062,6 +1068,200 @@ def test_conditional_jump_forward_non_const_condition(self):
10621068
consts=[0, 1, 2, 3, 4],
10631069
expected_consts=[0, 2, 3])
10641070

1071+
def test_list_exceeding_stack_use_guideline(self):
1072+
def f():
1073+
return [
1074+
0, 1, 2, 3, 4,
1075+
5, 6, 7, 8, 9,
1076+
10, 11, 12, 13, 14,
1077+
15, 16, 17, 18, 19,
1078+
20, 21, 22, 23, 24,
1079+
25, 26, 27, 28, 29,
1080+
30, 31, 32, 33, 34,
1081+
35, 36, 37, 38, 39
1082+
]
1083+
self.assertEqual(f(), list(range(40)))
1084+
1085+
def test_set_exceeding_stack_use_guideline(self):
1086+
def f():
1087+
return {
1088+
0, 1, 2, 3, 4,
1089+
5, 6, 7, 8, 9,
1090+
10, 11, 12, 13, 14,
1091+
15, 16, 17, 18, 19,
1092+
20, 21, 22, 23, 24,
1093+
25, 26, 27, 28, 29,
1094+
30, 31, 32, 33, 34,
1095+
35, 36, 37, 38, 39
1096+
}
1097+
self.assertEqual(f(), frozenset(range(40)))
1098+
1099+
def test_multiple_foldings(self):
1100+
before = [
1101+
('LOAD_SMALL_INT', 1, 0),
1102+
('LOAD_SMALL_INT', 2, 0),
1103+
('BUILD_TUPLE', 1, 0),
1104+
('LOAD_SMALL_INT', 0, 0),
1105+
('BINARY_OP', get_binop_argval('NB_SUBSCR'), 0),
1106+
('BUILD_TUPLE', 2, 0),
1107+
('RETURN_VALUE', None, 0)
1108+
]
1109+
after = [
1110+
('LOAD_CONST', 1, 0),
1111+
('RETURN_VALUE', None, 0)
1112+
]
1113+
self.cfg_optimization_test(before, after, consts=[], expected_consts=[(2,), (1, 2)])
1114+
1115+
def test_build_empty_tuple(self):
1116+
before = [
1117+
('BUILD_TUPLE', 0, 0),
1118+
('RETURN_VALUE', None, 0),
1119+
]
1120+
after = [
1121+
('LOAD_CONST', 0, 0),
1122+
('RETURN_VALUE', None, 0),
1123+
]
1124+
self.cfg_optimization_test(before, after, consts=[], expected_consts=[()])
1125+
1126+
def test_fold_tuple_of_constants(self):
1127+
before = [
1128+
('NOP', None, 0),
1129+
('LOAD_SMALL_INT', 1, 0),
1130+
('NOP', None, 0),
1131+
('LOAD_SMALL_INT', 2, 0),
1132+
('NOP', None, 0),
1133+
('NOP', None, 0),
1134+
('LOAD_SMALL_INT', 3, 0),
1135+
('NOP', None, 0),
1136+
('BUILD_TUPLE', 3, 0),
1137+
('RETURN_VALUE', None, 0),
1138+
]
1139+
after = [
1140+
('LOAD_CONST', 0, 0),
1141+
('RETURN_VALUE', None, 0),
1142+
]
1143+
self.cfg_optimization_test(before, after, consts=[], expected_consts=[(1, 2, 3)])
1144+
1145+
# not enough consts
1146+
same = [
1147+
('LOAD_SMALL_INT', 1, 0),
1148+
('LOAD_SMALL_INT', 2, 0),
1149+
('BUILD_TUPLE', 3, 0),
1150+
('RETURN_VALUE', None, 0)
1151+
]
1152+
self.cfg_optimization_test(same, same, consts=[])
1153+
1154+
# not all consts
1155+
same = [
1156+
('LOAD_SMALL_INT', 1, 0),
1157+
('LOAD_NAME', 0, 0),
1158+
('LOAD_SMALL_INT', 2, 0),
1159+
('BUILD_TUPLE', 3, 0),
1160+
('RETURN_VALUE', None, 0)
1161+
]
1162+
self.cfg_optimization_test(same, same, consts=[])
1163+
1164+
def test_optimize_if_const_list(self):
1165+
before = [
1166+
('NOP', None, 0),
1167+
('LOAD_SMALL_INT', 1, 0),
1168+
('NOP', None, 0),
1169+
('LOAD_SMALL_INT', 2, 0),
1170+
('NOP', None, 0),
1171+
('NOP', None, 0),
1172+
('LOAD_SMALL_INT', 3, 0),
1173+
('NOP', None, 0),
1174+
('BUILD_LIST', 3, 0),
1175+
('RETURN_VALUE', None, 0),
1176+
]
1177+
after = [
1178+
('BUILD_LIST', 0, 0),
1179+
('LOAD_CONST', 0, 0),
1180+
('LIST_EXTEND', 1, 0),
1181+
('RETURN_VALUE', None, 0),
1182+
]
1183+
self.cfg_optimization_test(before, after, consts=[], expected_consts=[(1, 2, 3)])
1184+
1185+
# need minimum 3 consts to optimize
1186+
same = [
1187+
('LOAD_SMALL_INT', 1, 0),
1188+
('LOAD_SMALL_INT', 2, 0),
1189+
('BUILD_LIST', 2, 0),
1190+
('RETURN_VALUE', None, 0),
1191+
]
1192+
self.cfg_optimization_test(same, same, consts=[])
1193+
1194+
# not enough consts
1195+
same = [
1196+
('LOAD_SMALL_INT', 1, 0),
1197+
('LOAD_SMALL_INT', 2, 0),
1198+
('LOAD_SMALL_INT', 3, 0),
1199+
('BUILD_LIST', 4, 0),
1200+
('RETURN_VALUE', None, 0),
1201+
]
1202+
self.cfg_optimization_test(same, same, consts=[])
1203+
1204+
# not all consts
1205+
same = [
1206+
('LOAD_SMALL_INT', 1, 0),
1207+
('LOAD_NAME', 0, 0),
1208+
('LOAD_SMALL_INT', 3, 0),
1209+
('BUILD_LIST', 3, 0),
1210+
('RETURN_VALUE', None, 0),
1211+
]
1212+
self.cfg_optimization_test(same, same, consts=[])
1213+
1214+
def test_optimize_if_const_set(self):
1215+
before = [
1216+
('NOP', None, 0),
1217+
('LOAD_SMALL_INT', 1, 0),
1218+
('NOP', None, 0),
1219+
('LOAD_SMALL_INT', 2, 0),
1220+
('NOP', None, 0),
1221+
('NOP', None, 0),
1222+
('LOAD_SMALL_INT', 3, 0),
1223+
('NOP', None, 0),
1224+
('BUILD_SET', 3, 0),
1225+
('RETURN_VALUE', None, 0),
1226+
]
1227+
after = [
1228+
('BUILD_SET', 0, 0),
1229+
('LOAD_CONST', 0, 0),
1230+
('SET_UPDATE', 1, 0),
1231+
('RETURN_VALUE', None, 0),
1232+
]
1233+
self.cfg_optimization_test(before, after, consts=[], expected_consts=[frozenset({1, 2, 3})])
1234+
1235+
# need minimum 3 consts to optimize
1236+
same = [
1237+
('LOAD_SMALL_INT', 1, 0),
1238+
('LOAD_SMALL_INT', 2, 0),
1239+
('BUILD_SET', 2, 0),
1240+
('RETURN_VALUE', None, 0),
1241+
]
1242+
self.cfg_optimization_test(same, same, consts=[])
1243+
1244+
# not enough consts
1245+
same = [
1246+
('LOAD_SMALL_INT', 1, 0),
1247+
('LOAD_SMALL_INT', 2, 0),
1248+
('LOAD_SMALL_INT', 3, 0),
1249+
('BUILD_SET', 4, 0),
1250+
('RETURN_VALUE', None, 0),
1251+
]
1252+
self.cfg_optimization_test(same, same, consts=[])
1253+
1254+
# not all consts
1255+
same = [
1256+
('LOAD_SMALL_INT', 1, 0),
1257+
('LOAD_NAME', 0, 0),
1258+
('LOAD_SMALL_INT', 3, 0),
1259+
('BUILD_SET', 3, 0),
1260+
('RETURN_VALUE', None, 0),
1261+
]
1262+
self.cfg_optimization_test(same, same, consts=[])
1263+
1264+
10651265
def test_conditional_jump_forward_const_condition(self):
10661266
# The unreachable branch of the jump is removed, the jump
10671267
# becomes redundant and is replaced by a NOP (for the lineno)

0 commit comments

Comments
 (0)
0