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

Found unhandled active variable in tuple splat #1255

Closed
aplavin opened this issue Jan 28, 2024 · 11 comments
Closed

Found unhandled active variable in tuple splat #1255

aplavin opened this issue Jan 28, 2024 · 11 comments

Comments

@aplavin
Copy link

aplavin commented Jan 28, 2024

Constructing tuples larger than a certain length throws this error that I couldn't even understand. MWE:

using Enzyme

function f(x)
	res = NTuple{40}(x)
	return res[1]
end

x = ones(40)
δδx = zeros(40)

(_, y) = Enzyme.autodiff(Enzyme.ReverseWithPrimal, f, Enzyme.Active, Enzyme.Duplicated(x, δδx))

# error:
AssertionError: Found unhandled active variable in tuple splat, jl_apply_iterate Tuple{Float64}
error_if_active_iter(::Base.RefValue{Tuple{Float64}})@jitrules.jl:775
_totuple@tuple.jl:410[inlined]
_totuple@tuple.jl:409[inlined]
Tuple@tuple.jl:391
...

The same code works if 40 is replaced with, say, 20.

How can this be fixed?

@wsmoses
Copy link
Member

wsmoses commented Jan 28, 2024 via email

@aplavin
Copy link
Author

aplavin commented Jan 28, 2024

The example code should be fully type-stable though, it just creates a tuple with comp-time known length and eltype. Indeed, code_warntype doesn't show any instabilities.

@wsmoses
Copy link
Member

wsmoses commented Jan 28, 2024 via email

@wsmoses
Copy link
Member

wsmoses commented Jan 28, 2024 via email

@wsmoses
Copy link
Member

wsmoses commented Jan 28, 2024 via email

@wsmoses
Copy link
Member

wsmoses commented Jan 28, 2024

Oh also this is in the wrong repository. This is the core Enzyme code, not the Julia bindings.

I mean you're welcome to use Enzyme on C++, JaX, etc where this error cannot occur (being Julia-specific), but probably this isn't where this should go. Moving the issue.

@wsmoses wsmoses transferred this issue from EnzymeAD/Enzyme Jan 28, 2024
@wsmoses
Copy link
Member

wsmoses commented Jan 28, 2024

Oh also even though codewarntype doesn't yell, it is clearly type unstable.

julia> @code_warntype f(x)
MethodInstance for f(::Vector{Float64})
  from f(x) @ Main REPL[4]:1
Arguments
  #self#::Core.Const(f)
  x::Vector{Float64}
Locals
  res::NTuple{40, Float64}
Body::Float64
1 ─ %1 = Core.apply_type(Main.NTuple, 40)::Core.Const(NTuple{40, T} where T)
│        (res = (%1)(x))
│   %3 = Base.getindex(res, 1)::Float64
└──      return %3

%1 = Core.apply_type(Main.NTuple, 40)::Core.Const(NTuple{40, T} where T) <- this returns an abstract type
as is (res = (%1)(x)) <- this is type unstable

If you change it to be slightly more type stable (and not an abstract type):

using Enzyme

function f(x)
   res = NTuple{40, Float64}(x)
   return res[1]
end

x = ones(40)
δδx = zeros(40)

(_, y) = Enzyme.autodiff(Enzyme.ReverseWithPrimal, f, Enzyme.Active, Enzyme.Duplicated(x, δδx))
julia> @code_warntype f(x)
MethodInstance for f(::Vector{Float64})
  from f(x) @ Main REPL[10]:1
Arguments
  #self#::Core.Const(f)
  x::Vector{Float64}
Locals
  res::**Tuple{Vararg{Float64}}**.  <- this is type unstable
Body::Float64
1 ─ %1 = Core.apply_type(Main.NTuple, 40, Main.Float64)::Core.Const(NTuple{40, Float64})
│        (res = (%1)(x))
│   %3 = Base.getindex(res, 1)::Float64
└──      return %3

@wsmoses
Copy link
Member

wsmoses commented Jan 28, 2024

If you actually make this type stable, like below, it does not error:

using Enzyme


function f(x)
	res = ntuple(Val(40)) do i
		Base.@_inline_meta
		x[i]
	end
	return res[1]
end

x = ones(40)
δδx = zeros(40)

(_, y) = Enzyme.autodiff(Enzyme.ReverseWithPrimal, f, Enzyme.Active, Enzyme.Duplicated(x, δδx))

((nothing,), 1.0)

@wsmoses
Copy link
Member

wsmoses commented Jan 28, 2024

Now closing as duplicate of #1235

If you'd like, feel free to open an issue on the Julia compiler itself (https://github.com/JuliaLang/julia) for the NTuple constructor not being type stable

@wsmoses wsmoses closed this as not planned Won't fix, can't repro, duplicate, stale Jan 28, 2024
@aplavin
Copy link
Author

aplavin commented Jan 28, 2024

%1 = Core.apply_type(Main.NTuple, 40)::Core.Const(NTuple{40, T} where T) <- this returns an abstract type
as is (res = (%1)(x)) <- this is type unstable

code_warntype for my original example looks totally the same for 20 and for 40 (aside from the number of course). However, for N=20 Enzyme can autodiff through, for N=40 it cannot...

@wsmoses
Copy link
Member

wsmoses commented Jan 28, 2024

Yeah this is a question better posed to JuliaLang/julia at this point. All I can tell you is that the llvm the Julia compiler makes is type unstable by the time Enzyme gets it for your test case.

Feel free to cc me though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants