Trying to understand what LoopVectorization does/doesn’t like.If I broadcast-add

Trying to understand what LoopVectorization does/doesn’t like.

If I broadcast-add elements of tuples

function bcast_add(x::NTuple{N,T},y::NTuple{N,T}) where {N,T}
    @avx for i = 1:length(first(x))
        x_i = getindex.(x,i) .+ getindex.(y,i)
        setindex!.(x,x_i,i)
    end
end

using @avx gives an Expression not recognized error which disappears if I remove getindex.(...) or setindex.(...). Are these operations not supported?

Note that the original poster on Slack cannot see your response here on Discourse. Consider transcribing the appropriate answer back to Slack, or pinging the poster here on Discourse so they can follow this thread.
(Original message :slack:) (More Info)

1 Like

from @Mason on Slack:

That’s correct, @avx doesn’t know how to deal with broadcasting, though this would be a conceivable feature to add. Perhaps open an issue in LoopVectorization.jl?

2 Likes

More in-detail response to a related Github issue Broadcasted indexing · Issue #197 · JuliaSIMD/LoopVectorization.jl · GitHub

Solution using code generation

using LoopVectorization, Base.Cartesian
@generated function foo!(x::Tuple{Vararg{Array,N}}) where {N}
    quote
        @nextract $N x x
        @avx for i = 1:length(first(x))
            @nexprs $N n -> x_n[i] = exp(x_n[i])
        end
    end
end
using Random
x = (rand(100), randn(100), randexp(100))
foo!(x)
x
1 Like

Helpful comments from @mcabbott on Slack:

I could be wrong but don’t think any kind of two-deep indexing is going to work […] I think things like x[n][i] also won’t work, it needs to know what arrays it’s dealing with. You could generate code though, for each N build the unrolled expression with all N loops visible. Either just a loop for N in 1:10 @eval fun!(x::NTuple{$N,T}, y::...) or a generated function.

1 Like