Peephole Optimizer

Peephole optimizer: optimize Python code objects. It is implemented with the BytecodeBlocks class.

It is based on the peephole optimizer of CPython 3.6 which is written in C.


Content of the bytecode.peephole_opt module:

class PeepholeOptimizer
optimize(code: types.CodeType) → types.CodeType

Optimize a Python code object.

Return a new optimized Python code object.

class CodeTransformer

Code transformer for the API of the PEP 511 (API for code transformers).

code_transformer(code, context)

Run the PeepholeOptimizer optimizer on the code.

Return a new optimized Python code object.



import dis
from bytecode.peephole_opt import PeepholeOptimizer

code = compile('print(5+5)', '<string>', 'exec')

code = PeepholeOptimizer().optimize(code)

Output of Python 3.6 patched with the PEP 511 with python -o noopt (to disable the builtin peephole optimizer):

  1           0 LOAD_NAME                0 (print)
              3 LOAD_CONST               0 (5)
              6 LOAD_CONST               0 (5)
              9 BINARY_ADD
             10 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             13 POP_TOP
             14 LOAD_CONST               1 (None)
             17 RETURN_VALUE

  1           0 LOAD_NAME                0 (print)
              3 LOAD_CONST               0 (10)
              6 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
              9 POP_TOP
             10 LOAD_CONST               1 (None)
             13 RETURN_VALUE


Optimizations implemented in the peephole optimizer:

  • Constant folding
    • unary operations: +a, -a, ~a
    • binary operations:
      • a + b, a - b, a * b, a / b, a // b, a % b, a ** b
      • a << b, a >> b, a & b, a | b, a ^ b
    • BUILD_TUPLE: convert to a constant
    • Replace BUILD_TUPLE <n> + UNPACK_SEQUENCE <n> and BUILD_LIST <n> + UNPACK_SEQUENCE <n> with ROT_TWO (2 arguments) or ROT_THREE+ROT_TWO (3 arguments). For BUILD_LIST, if inputs are LOAD_CONST, rewrite LOAD_CONST in the reverse order.
    • BUILD_LIST + COMPARE_OP(in/not in): convert list to tuple
    • BUILD_SET + COMPARE_OP(in/not in): convert set to frozenset
      • replace not(a is b) with a is not b
      • replace not(a is not b) with a is b
      • replace not(a in b) with a not in b
      • replace not(a not in b) with a in b
  • Remove NOP instructions
  • Dead code elimination
    • Remove unreachable code after a final operation (Instr.is_final())
    • Remove unreachable blocks (Block)
  • Optimize jumps
    • Replace unconditional jumps to RETURN_VALUE with RETURN_VALUE
    • Replace jumps to unconditional jumps with jumps to the final target
    • Remove unconditional jumps to the following block

For tuples, constant folding is only run if the result has 20 items or less.

By design, only basic optimizations can be implemented. A peephole optimizer has a narrow view on the bytecode (a few instructions) and only a very limited knownledge of the code.


3 < 5 or (1, 2, 3)[1] are not optimized.