[Python-Dev] Wither PEP 335 (Overloadable Boolean Operators)?
Guido van Rossum
guido at python.org
Fri May 25 04:53:40 CEST 2007
On 5/24/07, Greg Ewing <greg.ewing at canterbury.ac.nz> wrote:
> Guido van Rossum wrote:
>
> > Last call for discussion! I'm tempted to reject this -- the ability to
> > generate optimized code based on the shortcut semantics of and/or is
> > pretty important to me.
>
> Please don't be hasty. I've had to think about this issue
> a bit.
>
> The conclusion I've come to is that there may be a small loss
> in the theoretical amount of optimization opportunity available,
> but not much. Furthermore, if you take into account some other
> improvements that can be made (which I'll explain below) the
> result is actually *better* than what 2.5 currently generates.
>
> For example, Python 2.5 currently compiles
>
> if a and b:
> <stats>
>
> into
>
> <evaluate a>
> JUMP_IF_FALSE L1
> POP_TOP
> <evaluate b>
> JUMP_IF_FALSE L1
> POP_TOP
> <stats>
> JUMP_FORWARD L2
> L1:
> 15 POP_TOP
> L2:
>
> Under my PEP, without any other changes, this would become
>
> <evaluate a>
> LOGICAL_AND_1 L1
> <evaluate b>
> LOGICAL_AND_2
> L1:
> JUMP_IF_FALSE L2
> POP_TOP
> <stats>
> JUMP_FORWARD L3
> L2:
> 15 POP_TOP
> L3:
>
> The fastest path through this involves executing one extra
> bytecode. However, since we're not using JUMP_IF_FALSE to
> do the short-circuiting any more, there's no need for it
> to leave its operand on the stack. So let's redefine it and
> change its name to POP_JUMP_IF_FALSE. This allows us to
> get rid of all the POP_TOPs, plus the jump at the end of
> the statement body. Now we have
>
> <evaluate a>
> LOGICAL_AND_1 L1
> <evaluate b>
> LOGICAL_AND_2
> L1:
> POP_JUMP_IF_FALSE L2
> <stats>
> L2:
>
> The fastest path through this executes one *less* bytecode
> than in the current 2.5-generated code. Also, any path that
> ends up executing the body benefits from the lack of a
> jump at the end.
>
> The same benefits also result when the boolean expression is
> more complex, e.g.
>
> if a or b and c:
> <stats>
>
> becomes
>
> <evaluate a>
> LOGICAL_OR_1 L1
> <evaluate b>
> LOGICAL_AND_1 L2
> <evaluate c>
> LOGICAL_AND_2
> L2:
> LOGICAL_OR_2
> L1:
> POP_JUMP_IF_FALSE L3
> <stats>
> L3:
>
> which contains 3 fewer instructions overall than the
> corresponding 2.5-generated code.
>
> So I contend that optimization is not an argument for
> rejecting this PEP, and may even be one for accepting
> it.
Do you have an implementation available to measure this? In most cases
the cost is not in the number of bytecode instructions executed but in
the total amount of work. Two cheap bytecodes might well be cheaper
than one expensive one.
However, I'm happy to keep your PEP open until you have code that we
can measure. (However, adding additional optimizations elsewhere to
make up for the loss wouldn't be fair -- we would have to compare with
a 2.5 or trunk (2.6) interpreter with the same additional
optimizations added.)
--
--Guido van Rossum (home page: http://www.python.org/~guido/)
More information about the Python-Dev
mailing list