Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Code returned from generated function calls behaves incorrectly #25055

Closed
maleadt opened this issue Dec 13, 2017 · 8 comments
Closed

Code returned from generated function calls behaves incorrectly #25055

maleadt opened this issue Dec 13, 2017 · 8 comments
Assignees
Labels
regression Regression in behavior compared to a previous version

Comments

@maleadt
Copy link
Member

maleadt commented Dec 13, 2017

Caused by #24113 (cc @JeffBezanson), breaks CUDAnative. Repro:

function inner(val::T) where {T}
    println("inner($T)")
end

@generated function outer(val::T) where T
    Core.println("outer($T)")

    ex = quote end

    if T <: Number
        Core.println("-> call inner(val)")
        push!(ex.args, :( inner(val) ))
    elseif T <: Tuple
        Core.println("-> call outer(val[1]) -> inner(val[1])")
        push!(ex.args, :( outer(val[1])) )
    end

    return ex
end

outer(1)
println()
outer((1,))

Before:

outer(Int64)
-> call inner(val)
inner(Int64)

outer(Tuple{Int64})
-> call outer(val[1]) -> inner(val[1])
inner(Int64)

After:

outer(Int64)
-> call inner(val)
inner(Int64)

outer(Tuple{Int64})
-> call outer(val[1]) -> inner(val[1])
inner(Tuple{Int64})
inner(Int64)

ie. the inner function is called on a Tuple{Int64}, while the code returned by outer contains a call to outer(val[1]) where val[1] is a plain integer, and thus should result in a call to inner(val[1]).

Couple of things that change this behavior:

  • change to ex = Expr(:block) or return expressions instead of pushing to a block
  • not calling/inferring outer(1) first causes infinite recursion
@maleadt maleadt added the regression Regression in behavior compared to a previous version label Dec 13, 2017
maleadt added a commit to JuliaGPU/CUDAnative.jl that referenced this issue Dec 13, 2017
maleadt added a commit to JuliaGPU/CUDAnative.jl that referenced this issue Dec 13, 2017
@martinholters
Copy link
Member

Looks like the quote end is evaluated only once:

julia> @generated function foo(::Val{N}) where N
           ex = quote end
           println(object_id(ex))
           println(length(ex.args))
           push!(ex.args, :nothing)
           if N > 0
               :(foo(Val(N-1)))
           else
               :(nothing)
           end
       end
foo (generic function with 1 method)

julia> foo(Val(3))
12108886621498232131
1
12108886621498232131
2
12108886621498232131
3
12108886621498232131
4

@martinholters
Copy link
Member

Um, I thought one could inspect the lowered generator, but

julia> code_lowered(foo, Tuple{Val{3}}, false)
ERROR: Method is @generated; try `code_lowered` instead.

Julia bug or user bug?

@JeffBezanson
Copy link
Member

See if this fixes it:

--- a/base/inference.jl
+++ b/base/inference.jl
@@ -4387,8 +4387,6 @@ function effect_free(@nospecialize(e), src::CodeInfo, mod::Module, allow_vola
             return allow_volatile
         elseif head === :the_exception
             return allow_volatile
-        elseif head === :copyast
-            return true
         else
             return false
         end

@maleadt
Copy link
Member Author

maleadt commented Dec 13, 2017

See if this fixes it

Thanks, but no that doesn't seem to fix the original issue, or what @martinholters reduced it to.

@JeffBezanson
Copy link
Member

Somehow (likely in the new allocation elimination pass) this transformation is happening:

julia> function f()
       x = quote end
       return x
       end
f (generic function with 1 method)

julia> @code_typed f()
CodeInfo(:(begin
        #= line 3 =#
        return $(QuoteNode(quote
    #= REPL[3]:2 =#
end))
    end)) => Expr

I haven't figured out how yet, though.

@martinholters
Copy link
Member

Bisection confirms 4e81b9c as the point where this regressed.

@quinnj
Copy link
Member

quinnj commented Dec 16, 2017

Anyone have any clues here? I miss generated functions 😢 . Happy to help dig in if anyone can give some pointers.

@maleadt
Copy link
Member Author

maleadt commented Dec 16, 2017

I miss generated functions 😢

Where are you running into this issue? Using an Expr(:block) seems to work around it, so maybe it's related to the LineNumberNode that quot end generates.

# example from Jeff
julia> function f()
       x = quote end
       return x
       end
f (generic function with 1 method)

julia> @code_typed f()
CodeInfo(:(begin
        #= line 3 =#
        return $(QuoteNode(quote
    #= REPL[1]:2 =#
end))
    end)) => Expr

# workaround?
julia> function g()
       x = Expr(:block)
       return x
       end
g (generic function with 1 method)

julia> @code_typed g()
CodeInfo(:(begin
        # meta: location boot.jl Type 197
        SSAValue(1) = (Core._expr)(:block)::Expr
        # meta: pop location
        #= line 3 =#
        return SSAValue(1)
    end)) => Expr

@JeffBezanson JeffBezanson self-assigned this Dec 19, 2017
maleadt added a commit to JuliaGPU/CUDAnative.jl that referenced this issue Dec 20, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
regression Regression in behavior compared to a previous version
Projects
None yet
Development

No branches or pull requests

4 participants