LoopVectorization.jl
LoopVectorization.jl copied to clipboard
no method matching similar in broadcasting expression
On LV v0.8.1
julia> using StaticArrays, LoopVectorization
julia> function softmin_avx(a::T, b, c, γ) where T
γ = -γ
v = SVector(a, b, c, zero(T))
v = @avx v ./ γ
maxv = maximum(v)
ve = @avx exp.(v .- maxv) #.* SVector(one(T), one(T), one(T), zero(T))
γ*(log(sum(ve)) + maxv)
end
softmin_avx (generic function with 1 method)
julia> softmin_avx(1.0, 1.0, 1.0, 1.0)
ERROR: MethodError: no method matching similar(::Base.Broadcast.Broadcasted{StaticArrays.StaticArrayStyle{1},Nothing,typeof(/),Tuple{SArray{Tuple{4},Float64,1,4},Float64}}, ::Type{Float64})
Closest candidates are:
similar(::JuliaInterpreter.Compiled, ::Any) at /home/fredrikb/.julia/packages/JuliaInterpreter/sZur5/src/types.jl:7
similar(::Array{T,1}, ::Type) where T at array.jl:358
similar(::Array{T,2}, ::Type) where T at array.jl:359
...
Stacktrace:
[1] vmaterialize at /home/fredrikb/.julia/packages/LoopVectorization/lmGAZ/src/broadcast.jl:316 [inlined]
[2] softmin_avx(::Float64, ::Float64, ::Float64, ::Float64) at ./none:4
[3] top-level scope at none:0
Trying the same thing with vmap
produces another error
jjulia> function softmin_avx(a::T, b, c, γ) where T
γ = -γ
v = SVector(a, b, c, zero(T))
v = vmap(v->v / γ, v)
maxv = maximum(v)
ve = vmap(v->exp(v - maxv), v) #.* SVector(one(T), one(T), one(T), zero(T))
γ*(log(sum(ve)) + maxv)
end
softmin_avx (generic function with 1 method)
julia> softmin_avx(1.0, 1.0, 1.0, 1.0)
ERROR: Abstract type Any does not have a definite size.
Stacktrace:
[1] sizeof(::Type{T} where T) at ./essentials.jl:451
[2] #s19#58(::Any, ::Any, ::Any) at /home/fredrikb/.julia/packages/VectorizationBase/e8k1q/src/vector_width.jl:26
[3] (::Core.GeneratedFunctionStub)(::Any, ::Vararg{Any,N} where N) at ./boot.jl:526
[4] #s18#60(::Any, ::Any, ::Any) at /home/fredrikb/.julia/packages/VectorizationBase/e8k1q/src/vector_width.jl:33
[5] (::Core.GeneratedFunctionStub)(::Any, ::Vararg{Any,N} where N) at ./boot.jl:526
[6] vmap_quote(::Int64, ::Type{Any}) at /home/fredrikb/.julia/packages/LoopVectorization/lmGAZ/src/map.jl:3
[7] #s16#5(::Any, ::Any, ::Any, ::Any, ::Any, ::Any, ::Any) at /home/fredrikb/.julia/packages/LoopVectorization/lmGAZ/src/map.jl:32
[8] (::Core.GeneratedFunctionStub)(::Any, ::Vararg{Any,N} where N) at ./boot.jl:526
[9] vmap_call at /home/fredrikb/.julia/packages/LoopVectorization/lmGAZ/src/map.jl:165 [inlined]
[10] vmap at /home/fredrikb/.julia/packages/LoopVectorization/lmGAZ/src/map.jl:175 [inlined]
[11] softmin_avx(::Float64, ::Float64, ::Float64, ::Float64) at ./none:4
[12] top-level scope at none:0
This is reminiscent of: https://github.com/chriselrod/LoopVectorization.jl/issues/7
But I'll make that one about supporting StaticArrays
, and this one about not throwing an error and instead using a fallback.
The problem here is because broadcasting falls back via dispatch, and I guess it does so on the wrong level with respect to StaticArrays
.
vmaterialize
constructs a similar
array here, and then calls vmaterialize!
on it.
Fall back behavior is achieved by dispatch selecting a method that forwards to Base.Broadcast.materialize!.
The problem, of course, is that StaticArrays doesn't write into a destination, you can't materialize!
into one. The error comes when trying to allocate that destination in the first place, inside vmaterialize
.
So, the check for compatibility has to look at all the inputs (like @avx
applied to loops does), and not just on the destination. I'll make broadcasting use the same mechanism as loops for this.