Skip to content

Commit 2c7b401

Browse files
committed
merge binaryop folding tests
1 parent c03252c commit 2c7b401

1 file changed

Lines changed: 104 additions & 132 deletions

File tree

Lib/test/test_peepholer.py

Lines changed: 104 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -235,78 +235,6 @@ def g(a):
235235
self.assertTrue(g(4))
236236
self.check_lnotab(g)
237237

238-
239-
def test_folding_of_binops_on_constants(self):
240-
for line, elem in (
241-
('a = 2+3+4', 9), # chained fold
242-
('"@"*4', '@@@@'), # check string ops
243-
('a="abc" + "def"', 'abcdef'), # check string ops
244-
('a = 3**4', 81), # binary power
245-
('a = 3*4', 12), # binary multiply
246-
('a = 13//4', 3), # binary floor divide
247-
('a = 14%4', 2), # binary modulo
248-
('a = 2+3', 5), # binary add
249-
('a = 13-4', 9), # binary subtract
250-
('a = (12,13)[1]', 13), # binary subscr
251-
('a = 13 << 2', 52), # binary lshift
252-
('a = 13 >> 2', 3), # binary rshift
253-
('a = 13 & 7', 5), # binary and
254-
('a = 13 ^ 7', 10), # binary xor
255-
('a = 13 | 7', 15), # binary or
256-
):
257-
with self.subTest(line=line):
258-
code = compile(line, '', 'single')
259-
if isinstance(elem, int):
260-
self.assertInBytecode(code, 'LOAD_SMALL_INT', elem)
261-
else:
262-
self.assertInBytecode(code, 'LOAD_CONST', elem)
263-
for instr in dis.get_instructions(code):
264-
self.assertFalse(instr.opname.startswith('BINARY_'))
265-
self.check_lnotab(code)
266-
267-
# Verify that unfoldables are skipped
268-
code = compile('a=2+"b"', '', 'single')
269-
self.assertInBytecode(code, 'LOAD_SMALL_INT', 2)
270-
self.assertInBytecode(code, 'LOAD_CONST', 'b')
271-
self.check_lnotab(code)
272-
273-
# Verify that large sequences do not result from folding
274-
code = compile('a="x"*10000', '', 'single')
275-
self.assertInBytecode(code, 'LOAD_CONST', 10000)
276-
self.assertNotIn("x"*10000, code.co_consts)
277-
self.check_lnotab(code)
278-
code = compile('a=1<<1000', '', 'single')
279-
self.assertInBytecode(code, 'LOAD_CONST', 1000)
280-
self.assertNotIn(1<<1000, code.co_consts)
281-
self.check_lnotab(code)
282-
code = compile('a=2**1000', '', 'single')
283-
self.assertInBytecode(code, 'LOAD_CONST', 1000)
284-
self.assertNotIn(2**1000, code.co_consts)
285-
self.check_lnotab(code)
286-
287-
def test_binary_subscr_on_unicode(self):
288-
# valid code get optimized
289-
code = compile('"foo"[0]', '', 'single')
290-
self.assertInBytecode(code, 'LOAD_CONST', 'f')
291-
self.assertNotInBytecode(code, 'BINARY_OP')
292-
self.check_lnotab(code)
293-
code = compile('"\u0061\uffff"[1]', '', 'single')
294-
self.assertInBytecode(code, 'LOAD_CONST', '\uffff')
295-
self.assertNotInBytecode(code,'BINARY_OP')
296-
self.check_lnotab(code)
297-
298-
# With PEP 393, non-BMP char get optimized
299-
code = compile('"\U00012345"[0]', '', 'single')
300-
self.assertInBytecode(code, 'LOAD_CONST', '\U00012345')
301-
self.assertNotInBytecode(code, 'BINARY_OP')
302-
self.check_lnotab(code)
303-
304-
# invalid code doesn't get optimized
305-
# out of range
306-
code = compile('"fuu"[10]', '', 'single')
307-
self.assertInBytecode(code, 'BINARY_OP')
308-
self.check_lnotab(code)
309-
310238
def test_elim_extra_return(self):
311239
# RETURN LOAD_CONST None RETURN --> RETURN
312240
def f(x):
@@ -523,73 +451,117 @@ def negzero():
523451

524452
def test_folding_binop(self):
525453
tests = [
526-
('1 + 2', False, 'NB_ADD'),
527-
('1 + 2 + 3', False, 'NB_ADD'),
528-
('1 + ""', True, 'NB_ADD'),
529-
('1 - 2', False, 'NB_SUBTRACT'),
530-
('1 - 2 - 3', False, 'NB_SUBTRACT'),
531-
('1 - ""', True, 'NB_SUBTRACT'),
532-
('2 * 2', False, 'NB_MULTIPLY'),
533-
('2 * 2 * 2', False, 'NB_MULTIPLY'),
534-
('2 / 2', False, 'NB_TRUE_DIVIDE'),
535-
('2 / 2 / 2', False, 'NB_TRUE_DIVIDE'),
536-
('2 / ""', True, 'NB_TRUE_DIVIDE'),
537-
('2 // 2', False, 'NB_FLOOR_DIVIDE'),
538-
('2 // 2 // 2', False, 'NB_FLOOR_DIVIDE'),
539-
('2 // ""', True, 'NB_FLOOR_DIVIDE'),
540-
('2 % 2', False, 'NB_REMAINDER'),
541-
('2 % 2 % 2', False, 'NB_REMAINDER'),
542-
('2 % ()', True, 'NB_REMAINDER'),
543-
('2 ** 2', False, 'NB_POWER'),
544-
('2 ** 2 ** 2', False, 'NB_POWER'),
545-
('2 ** ""', True, 'NB_POWER'),
546-
('2 << 2', False, 'NB_LSHIFT'),
547-
('2 << 2 << 2', False, 'NB_LSHIFT'),
548-
('2 << ""', True, 'NB_LSHIFT'),
549-
('2 >> 2', False, 'NB_RSHIFT'),
550-
('2 >> 2 >> 2', False, 'NB_RSHIFT'),
551-
('2 >> ""', True, 'NB_RSHIFT'),
552-
('2 | 2', False, 'NB_OR'),
553-
('2 | 2 | 2', False, 'NB_OR'),
554-
('2 | ""', True, 'NB_OR'),
555-
('2 & 2', False, 'NB_AND'),
556-
('2 & 2 & 2', False, 'NB_AND'),
557-
('2 & ""', True, 'NB_AND'),
558-
('2 ^ 2', False, 'NB_XOR'),
559-
('2 ^ 2 ^ 2', False, 'NB_XOR'),
560-
('2 ^ ""', True, 'NB_XOR'),
561-
('(1, )[0]', False, 'NB_SUBSCR'),
562-
('(1, )[-1]', False, 'NB_SUBSCR'),
563-
('(1 + 2, )[0]', False, 'NB_SUBSCR'),
564-
('(1, (1, 2))[1][1]', False, 'NB_SUBSCR'),
565-
('(1, 2)[2-1]', False, 'NB_SUBSCR'),
566-
('(1, (1, 2))[1][2-1]', False, 'NB_SUBSCR'),
567-
('(1, (1, 2))[1:6][0][2-1]', False, 'NB_SUBSCR'),
568-
('"a"[0]', False, 'NB_SUBSCR'),
569-
('("a" + "b")[1]', False, 'NB_SUBSCR'),
570-
('("a" + "b", )[0][1]', False, 'NB_SUBSCR'),
571-
('("a" * 10)[9]', False, 'NB_SUBSCR'),
572-
('(1, )[1]', True, 'NB_SUBSCR'),
573-
('(1, )[-2]', True, 'NB_SUBSCR'),
574-
('"a"[1]', True, 'NB_SUBSCR'),
575-
('"a"[-2]', True, 'NB_SUBSCR'),
576-
('("a" + "b")[2]', True, 'NB_SUBSCR'),
577-
('("a" + "b", )[0][2]', True, 'NB_SUBSCR'),
578-
('("a" + "b", )[1][0]', True, 'NB_SUBSCR'),
579-
('("a" * 10)[10]', True, 'NB_SUBSCR'),
580-
('(1, (1, 2))[2:6][0][2-1]', True, 'NB_SUBSCR'),
581-
582-
]
583-
for expr, has_error, nb_op in tests:
584-
with self.subTest(expr=expr, has_error=has_error):
454+
('1 + 2', 'NB_ADD', True, 'LOAD_SMALL_INT', 3),
455+
('1 + 2 + 3', 'NB_ADD', True, 'LOAD_SMALL_INT', 6),
456+
('1 + ""', 'NB_ADD', False, None, None),
457+
('1 - 2', 'NB_SUBTRACT', True, 'LOAD_CONST', -1),
458+
('1 - 2 - 3', 'NB_SUBTRACT', True, 'LOAD_CONST', -4),
459+
('1 - ""', 'NB_SUBTRACT', False, None, None),
460+
('2 * 2', 'NB_MULTIPLY', True, 'LOAD_SMALL_INT', 4),
461+
('2 * 2 * 2', 'NB_MULTIPLY', True, 'LOAD_SMALL_INT', 8),
462+
('2 / 2', 'NB_TRUE_DIVIDE', True, 'LOAD_CONST', 1.0),
463+
('2 / 2 / 2', 'NB_TRUE_DIVIDE', True, 'LOAD_CONST', 0.5),
464+
('2 / ""', 'NB_TRUE_DIVIDE', False, None, None),
465+
('2 // 2', 'NB_FLOOR_DIVIDE', True, 'LOAD_SMALL_INT', 1),
466+
('2 // 2 // 2', 'NB_FLOOR_DIVIDE', True, 'LOAD_SMALL_INT', 0),
467+
('2 // ""', 'NB_FLOOR_DIVIDE', False, None, None),
468+
('2 % 2', 'NB_REMAINDER', True, 'LOAD_SMALL_INT', 0),
469+
('2 % 2 % 2', 'NB_REMAINDER', True, 'LOAD_SMALL_INT', 0),
470+
('2 % ()', 'NB_REMAINDER', False, None, None),
471+
('2 ** 2', 'NB_POWER', True, 'LOAD_SMALL_INT', 4),
472+
('2 ** 2 ** 2', 'NB_POWER', True, 'LOAD_SMALL_INT', 16),
473+
('2 ** ""', 'NB_POWER', False, None, None),
474+
('2 << 2', 'NB_LSHIFT', True, 'LOAD_SMALL_INT', 8),
475+
('2 << 2 << 2', 'NB_LSHIFT', True, 'LOAD_SMALL_INT', 32),
476+
('2 << ""', 'NB_LSHIFT', False, None, None),
477+
('2 >> 2', 'NB_RSHIFT', True, 'LOAD_SMALL_INT', 0),
478+
('2 >> 2 >> 2', 'NB_RSHIFT', True, 'LOAD_SMALL_INT', 0),
479+
('2 >> ""', 'NB_RSHIFT', False, None, None),
480+
('2 | 2', 'NB_OR', True, 'LOAD_SMALL_INT', 2),
481+
('2 | 2 | 2', 'NB_OR', True, 'LOAD_SMALL_INT', 2),
482+
('2 | ""', 'NB_OR', False, None, None),
483+
('2 & 2', 'NB_AND', True, 'LOAD_SMALL_INT', 2),
484+
('2 & 2 & 2', 'NB_AND', True, 'LOAD_SMALL_INT', 2),
485+
('2 & ""', 'NB_AND', False, None, None),
486+
('2 ^ 2', 'NB_XOR', True, 'LOAD_SMALL_INT', 0),
487+
('2 ^ 2 ^ 2', 'NB_XOR', True, 'LOAD_SMALL_INT', 2),
488+
('2 ^ ""', 'NB_XOR', False, None, None),
489+
('(1, )[0]', 'NB_SUBSCR', True, 'LOAD_SMALL_INT', 1),
490+
('(1, )[-1]', 'NB_SUBSCR', True, 'LOAD_SMALL_INT', 1),
491+
('(1 + 2, )[0]', 'NB_SUBSCR', True, 'LOAD_SMALL_INT', 3),
492+
('(1, (1, 2))[1][1]', 'NB_SUBSCR', True, 'LOAD_SMALL_INT', 2),
493+
('(1, 2)[2-1]', 'NB_SUBSCR', True, 'LOAD_SMALL_INT', 2),
494+
('(1, (1, 2))[1][2-1]', 'NB_SUBSCR', True, 'LOAD_SMALL_INT', 2),
495+
('(1, (1, 2))[1:6][0][2-1]', 'NB_SUBSCR', True, 'LOAD_SMALL_INT', 2),
496+
('"a"[0]', 'NB_SUBSCR', True, 'LOAD_CONST', 'a'),
497+
('("a" + "b")[1]', 'NB_SUBSCR', True, 'LOAD_CONST', 'b'),
498+
('("a" + "b", )[0][1]', 'NB_SUBSCR', True, 'LOAD_CONST', 'b'),
499+
('("a" * 10)[9]', 'NB_SUBSCR', True, 'LOAD_CONST', 'a'),
500+
('(1, )[1]', 'NB_SUBSCR', False, None, None),
501+
('(1, )[-2]', 'NB_SUBSCR', False, None, None),
502+
('"a"[1]', 'NB_SUBSCR', False, None, None),
503+
('"a"[-2]', 'NB_SUBSCR', False, None, None),
504+
('("a" + "b")[2]', 'NB_SUBSCR', False, None, None),
505+
('("a" + "b", )[0][2]', 'NB_SUBSCR', False, None, None),
506+
('("a" + "b", )[1][0]', 'NB_SUBSCR', False, None, None),
507+
('("a" * 10)[10]', 'NB_SUBSCR', False, None, None),
508+
('(1, (1, 2))[2:6][0][2-1]', 'NB_SUBSCR', False, None, None),
509+
]
510+
for (
511+
expr,
512+
nb_op,
513+
is_optimized,
514+
optimized_opcode,
515+
optimized_argval
516+
) in tests:
517+
with self.subTest(expr=expr, is_optimized=is_optimized):
585518
code = compile(expr, '', 'single')
586519
nb_op_val = get_binop_argval(nb_op)
587-
if not has_error:
520+
if is_optimized:
588521
self.assertNotInBytecode(code, 'BINARY_OP', argval=nb_op_val)
522+
self.assertInBytecode(code, optimized_opcode, argval=optimized_argval)
589523
else:
590524
self.assertInBytecode(code, 'BINARY_OP', argval=nb_op_val)
591525
self.check_lnotab(code)
592526

527+
# Verify that large sequences do not result from folding
528+
code = compile('"x"*10000', '', 'single')
529+
self.assertInBytecode(code, 'LOAD_CONST', 10000)
530+
self.assertNotIn("x"*10000, code.co_consts)
531+
self.check_lnotab(code)
532+
code = compile('1<<1000', '', 'single')
533+
self.assertInBytecode(code, 'LOAD_CONST', 1000)
534+
self.assertNotIn(1<<1000, code.co_consts)
535+
self.check_lnotab(code)
536+
code = compile('2**1000', '', 'single')
537+
self.assertInBytecode(code, 'LOAD_CONST', 1000)
538+
self.assertNotIn(2**1000, code.co_consts)
539+
self.check_lnotab(code)
540+
541+
# Test binary subscript on unicode
542+
# valid code get optimized
543+
code = compile('"foo"[0]', '', 'single')
544+
self.assertInBytecode(code, 'LOAD_CONST', 'f')
545+
self.assertNotInBytecode(code, 'BINARY_OP')
546+
self.check_lnotab(code)
547+
code = compile('"\u0061\uffff"[1]', '', 'single')
548+
self.assertInBytecode(code, 'LOAD_CONST', '\uffff')
549+
self.assertNotInBytecode(code,'BINARY_OP')
550+
self.check_lnotab(code)
551+
552+
# With PEP 393, non-BMP char get optimized
553+
code = compile('"\U00012345"[0]', '', 'single')
554+
self.assertInBytecode(code, 'LOAD_CONST', '\U00012345')
555+
self.assertNotInBytecode(code, 'BINARY_OP')
556+
self.check_lnotab(code)
557+
558+
# invalid code doesn't get optimized
559+
# out of range
560+
code = compile('"fuu"[10]', '', 'single')
561+
self.assertInBytecode(code, 'BINARY_OP')
562+
self.check_lnotab(code)
563+
564+
593565
def test_constant_folding_remove_nop_location(self):
594566
sources = [
595567
"""

0 commit comments

Comments
 (0)