faster-cpython / ideas

1.68k stars 48 forks source link

Regression in compiling boolean expressions #596

Closed serhiy-storchaka closed 1 year ago

serhiy-storchaka commented 1 year ago

Boolean expressions produce larger bytecode and are slower in 3.12 than in 3.11.

In 3.11:

$ ./python -m timeit -s 'a=b=c=True' 'x = a and b and c'
20000000 loops, best of 5: 15.4 nsec per loop

In 3.12:

$ ./python -m timeit -s 'a=b=c=True' 'x = a and b and c'
10000000 loops, best of 5: 22 nsec per loop

In 3.11:

$ echo 'x = a and b and c' | ./python -m dis
  0           0 RESUME                   0

  1           2 LOAD_NAME                0 (a)
              4 JUMP_IF_FALSE_OR_POP     3 (to 12)
              6 LOAD_NAME                1 (b)
              8 JUMP_IF_FALSE_OR_POP     1 (to 12)
             10 LOAD_NAME                2 (c)
        >>   12 STORE_NAME               3 (x)
             14 LOAD_CONST               0 (None)
             16 RETURN_VALUE

In 3.12:

$ echo 'x = a and b and c' | ./python -m dis
  0           0 RESUME                   0

  1           2 LOAD_NAME                0 (a)
              4 COPY                     1
              6 POP_JUMP_IF_FALSE        6 (to 20)
              8 POP_TOP
             10 LOAD_NAME                1 (b)
             12 COPY                     1
             14 POP_JUMP_IF_FALSE        2 (to 20)
             16 POP_TOP
             18 LOAD_NAME                2 (c)
        >>   20 STORE_NAME               3 (x)
             22 RETURN_CONST             0 (None)

Furthermore, adding parenthesis affects the generated code in 3.12, unlike to 3.11. Peephole optimization does not work anymore.

$ echo 'x = (a and b) and c' | ./python -m dis
  0           0 RESUME                   0

  1           2 LOAD_NAME                0 (a)
              4 COPY                     1
              6 POP_JUMP_IF_FALSE        2 (to 12)
              8 POP_TOP
             10 LOAD_NAME                1 (b)
        >>   12 COPY                     1
             14 POP_JUMP_IF_FALSE        2 (to 20)
             16 POP_TOP
             18 LOAD_NAME                2 (c)
        >>   20 STORE_NAME               3 (x)
             22 RETURN_CONST             0 (None)