Skip to content

Improper inlining of function in loop condition #2284

@DWesl

Description

@DWesl

Given this input:

def is_even(n: int) -> int:
    return (n & 1) == 0

#pythran export trailing_zero_bits(int)
def trailing_zero_bits(n: int) -> int:
    result = 0
    while is_even(n):
        n >>= 1
        result += 1
    return result

pythran -P produces

def is_even(n):
    return ((n & 1) == 0)
def trailing_zero_bits(n):
    n_ = n
    result = 0
    __pythran_inlineis_evenn0 = n_
    while ((__pythran_inlineis_evenn0 & 1) == 0):
        n_ >>= 1
        result += 1
    return result

The problem is the creation of the __pythran_inlineis_evenn0, specifically the loop whose condition it is used in.

I suspect this catches a corner case on the function inliner: to avoid duplicate side effects from evaluating an expression every place the argument appears in the inlined function, it creates a variable to hold the value of that expression, assigns that value to that variable on the previous line, and uses the new variable in the inlined function body.

If the function is used anywhere other than an elif or while condition, this works very well. If it occurs in an elif condition, one need merely move the assignment before the corresponding if (and ensure there are no name collisions with functions inlined in the if or preceeding elif conditions) or separate out elif into else and if, providing a space for the assignment to happen between the two.

If a function is to be inlined into a while condition, the assignment must be duplicated: placed not merely on the previous line, but also as the last line of the while loop body. It seems pythran 0.17.0, at least on Cygwin, does not perform that second assignment.

I don't know enough of the pythran internals to be sure where in the optimizers the inliner lives, nor with Python ASTs to be able to insert the second assignment at the required location.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions