[Python-Dev] JUMP_ABSOLUTE in nested if statements

2016-06-18 Thread Obiesie ike-nwosu via Python-Dev
Hi, 

Could some one give a hand with explaining to me why we have a JUMP_ABSOLUTE 
followed by a JUMP_FORWARD op code when this function is disassembled.

>>> def f1():
... a, b = 10, 11
... if a >= 10:
... if b >= 11:
... print("hello world")
… 

The disassembled function is shown below.
>>> dis(f1)
  2   0 LOAD_CONST   4 ((10, 11))
  3 UNPACK_SEQUENCE  2
  6 STORE_FAST   0 (a)
  9 STORE_FAST   1 (b)

  312 LOAD_FAST0 (a)
15 LOAD_CONST   1 (10)
18 COMPARE_OP   5 (>=)
21 POP_JUMP_IF_FALSE   47

  424 LOAD_FAST1 (b)
27 LOAD_CONST   2 (11)
30 COMPARE_OP   5 (>=)
33 POP_JUMP_IF_FALSE   47

  536 LOAD_CONST   3 ('hello world')
39 PRINT_ITEM  
40 PRINT_NEWLINE   
41 JUMP_ABSOLUTE   47
44 JUMP_FORWARD 0 (to 47)
 >>   47 LOAD_CONST   0 (None)
50 RETURN_VALUE  

From my understanding, once JUMP_ABSOLUTE is executed, then JUMP_FORWARD is 
never gotten to so must be dead code so why is it being generated?
Furthermore why is JUMP_ABSOLUTE rather than JUMP_FORWARD used in this 
particular case of nested if statements? I have tried other types of nested if 
statements and it has always been JUMP_FORWARD that 
is generated.
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] JUMP_ABSOLUTE in nested if statements

2016-06-18 Thread Obiesie ike-nwosu via Python-Dev
That is much clearer now. 
Thanks a lot Raymond for taking the time out to explain this to me.
 On a closing note, is this mailing list the right place to ask these kinds of 
n00b questions?

Obi.
> On 18 Jun 2016, at 23:10, Raymond Hettinger  
> wrote:
> 
> 
>> On Jun 18, 2016, at 2:04 PM, Obiesie ike-nwosu via Python-Dev 
>>  wrote:
>> 
>> Hi, 
>> 
>> Could some one give a hand with explaining to me why we have a JUMP_ABSOLUTE 
>> followed by a JUMP_FORWARD op code when this function is disassembled.
>> < snipped>
>> From my understanding, once JUMP_ABSOLUTE is executed, then JUMP_FORWARD is 
>> never gotten to so must be dead code so why is it being generated?
>> Furthermore why is JUMP_ABSOLUTE rather than JUMP_FORWARD used in this 
>> particular case of nested if statements? I have tried other types of nested 
>> if statements and it has always been JUMP_FORWARD that 
>> is generated.
> 
> The AST compilation step generates code with two JUMP_FORWARDs (see below).  
> Then, the peephole optimizer recognizes a jump-to-an-unconditional-jump and 
> replaces the first one with a JUMP_ABSOLUTE to save an unnecessary step.
> 
> The reason that it uses JUMP_ABSOLUTE instead of JUMP_FORWARD is that the 
> former is more general (it can jump backwards).  Using the more general form 
> reduces the complexity of the optimizer.
> 
> The reason that the remaining jump-to-jump isn't optimized is that the 
> peepholer is intentionally kept simplistic, making only a single pass over 
> the opcodes.  That misses some optimizations but gets the most common cases.
> 
> FWIW, the jump opcodes are very fast, so missing the final jump-to-jump isn't 
> much of a loss.
> 
> If you're curious, the relevant code is in Python/compile.c and 
> Python/peephole.c.  The compile.c code generated opcodes in the most 
> straight-forward way possible and then the peephole optimizer gets some of 
> the low-hanging fruit by making a few simple transformations.
> 
> 
> Raymond
> 
> 
>  AST generated code before peephole optimization -
> 
> 
>  5   0 LOAD_CONST   1 (10)
>  3 LOAD_CONST   2 (11)
>  6 BUILD_TUPLE  2
>  9 UNPACK_SEQUENCE  2
> 12 STORE_FAST   0 (a)
> 15 STORE_FAST   1 (b)
> 
>  6  18 LOAD_FAST0 (a)
> 21 LOAD_CONST   1 (10)
> 24 COMPARE_OP   5 (>=)
> 27 POP_JUMP_IF_FALSE   53
> 
>  7  30 LOAD_FAST1 (b)
> 33 LOAD_CONST   2 (11)
> 36 COMPARE_OP   5 (>=)
> 39 POP_JUMP_IF_FALSE   50
> 
>  8  42 LOAD_CONST   3 ('hello world')
> 45 PRINT_ITEM
> 46 PRINT_NEWLINE
> 47 JUMP_FORWARD 0 (to 50)
>>>  50 JUMP_FORWARD 0 (to 53)
>>>  53 LOAD_CONST   0 (None)
> 56 RETURN_VALUE
> 

___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] Python CFG Basic blocks

2016-07-11 Thread Obiesie ike-nwosu via Python-Dev
Hi,

I am looking into how the python compiler generates basic blocks during the CFG 
generation process and my expectations from CFG theory seems to be at odds with 
how the python compiler actually generates its CFG. Take the following code 
snippet for example:

def median(pool):
copy = sorted(pool)
size = len(copy)
if size % 2 == 1:
return copy[(size - 1) / 2]
else:
return (copy[size/2 - 1] + copy[size/2]) / 2

From my understanding of basic blocks in compilers, the above code snippet 
should have at least 3 basic blocks as follows:
1. Block 1 - all instructions up to and including those for the if test.
2. Block 2 - all instructions for the if body i.e the first return 
statement.
3. Block 3 - instructions for the else block i.e. the second return 
statement.

My understanding of the the section on Control flow Graphs in the “Design of 
the CPython Compiler” also alludes to this - 
 
>> As an example, consider an ‘if’ statement with an ‘else’ block. The guard on 
>> the ‘if’ is a basic block which is pointed to by the basic block containing 
>> the code leading to the ‘if’ statement. The ‘if’ statement block contains 
>> jumps (which are exit points) to the true body of the ‘if’ and the ‘else’ 
>> body (which may be NULL), each of which are their own basic blocks. Both of 
>> those blocks in turn point to the basic block representing the code 
>> following the entire ‘if’ statement.


The CPython compiler however seems to generate 2 basic blocks for the above 
snippets - 
1. Block 1 - all instructions up to and including the if statement and 
the body of the if statement (the first return statement in this case)
2. Block 2 - instructions for the else block (the second return 
statement)

Is there any reason for this or have I somehow missed something in the CFG 
generation process?

Regards,

Obi___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com