constant folding - why not more

Terry Reedy tjreedy at udel.edu
Tue Nov 10 15:03:40 EST 2020


On 11/10/2020 1:03 PM, Barry Scott wrote:
> 
> 
>> On 10 Nov 2020, at 14:45, David Kolovratník <david at kolovratnik.net> wrote:
>>
>> Dear all,
>>
>> I would like to learn about constant folding optimisation in Python. It seems
>> to be implemented in Python/ast_opt.c. In order to get impression I used
>> python3 and dis module:
>>
>> $ python3 -V
>> Python 3.7.3
> 
> I do not have answers to your questions, but I would suggest that you look at 3.9
> or even 3.10a2 to see if this is still the case.

Checking with 3.10...

>> Arithmetics expression is folded as expected:
>>
>>>>> dis.dis(compile('1 * 2', filename='<string>', mode='eval',
>>>>> optimize=2))
>>   1           0 LOAD_CONST               0 (2)
>>               2 RETURN_VALUE
>>
>> On the contrary, comparison remains for runtime:
>>>>> dis.dis(compile('1 < 2', filename='<string>', mode='eval',
>>>>> optimize=2))
>>   1           0 LOAD_CONST               0 (1)
>>               2 LOAD_CONST               1 (2)
>>               4 COMPARE_OP               0 (<)
>>               6 RETURN_VALUE

Same.

>> In function fold_unaryop (though comparison is a binary operation) in
>> Python/ast_opt.c is remark: /* Fold not into comparison */

Use git blame to find out who and when made that remark.

>> Is there a reason why comparison (== != < > <= >=) is not folded? I would
>> expect it handled in fold_binop.
>>
>> Besides comparison there are other expressions that might be optimized out
>> due to constant expression. Ternary operator with constant condition True
>> has IF optimized out (just some dead code remains):
>>>>> dis.dis(compile('"a" if True else "b"', filename='<string>',
>>>>> mode='eval', optimize=2))
>>   1           0 LOAD_CONST               1 ('a')
>>               2 RETURN_VALUE

Remains.

>>               4 LOAD_CONST               2 ('b')
>>               6 RETURN_VALUE

Gone.

>> On the contrary, the same ternary operator with constant condition False
>> still loads the constat and contains POP_JUMP_IF_FALSE:
>>>>> dis.dis(compile('"a" if False else "b"', filename='<string>',
>>>>> mode='eval', optimize=2))
>>   1           0 LOAD_CONST               0 (False)
>>               2 POP_JUMP_IF_FALSE        8
>>               4 LOAD_CONST               1 ('a')
>>               6 RETURN_VALUE
>>         >>    8 LOAD_CONST               2 ('b')
>>              10 RETURN_VALUE

Same.  You could file issue for this, but one guess is that else clause 
might spill over to another line, and current decision is that for 
tracing, every line of code that naively should be executed is executed 
rather than optimized away.  But I would first try to find the file that 
produces bytecode and then use git blame to find issue where the True 
else part was removed.

-- 
Terry Jan Reedy




More information about the Python-list mailing list