LoopVectorization.jl icon indicating copy to clipboard operation
LoopVectorization.jl copied to clipboard

`@turbo` and destructuring assignments

Open matthias314 opened this issue 2 years ago • 1 comments

Discussed in https://github.com/JuliaSIMD/LoopVectorization.jl/discussions/421

Originally posted by matthias314 August 16, 2022 It seems that destructuring assignments inside a loop may lead to wrong results. The example

function swap(v, w)
    @turbo for i in axes(v, 1)
        v[i], w[i] = w[i], v[i]
    end
end

gives

julia> v = [0, 0];
julia> w = [1, 1];
julia> swap(v, w);
julia> v[1], w[1]
(1, 1)     # wrong

I don't know if this is a bug or part of the "don't rely on a specific execution order" rule. In the latter case, would it make sense to mention this case explicitly in the documentation? After all, it's formally a single statement.

It has been confirmed that it's a bug.

matthias314 avatar Aug 16 '22 23:08 matthias314

This may be a good first issue for someone who wants to give this a try.

julia> using LoopVectorization

julia> function swap_debug(v, w)
           LoopVectorization.@turbo_debug for i in axes(v, 1)
               v[i], w[i] = w[i], v[i]
           end
       end
swap_debug (generic function with 1 method)

julia> v = [0, 0];

julia> w = [1, 1];

julia> ls = swap_debug(v, w);

julia> ls.operations
5-element Vector{LoopVectorization.Operation}:
 var"##op#226" = w[i]
 var"##op#227" = LoopVectorization.identity(var"##op#226")
 v[i] = var"##op#227"
 var"##op#229" = LoopVectorization.identity(var"##op#227")
 w[i] = var"##op#229"

The problem is in parsing. Basically, LV is reading this expression as (look at the operations)

temp0 = w[i]
temp1 = identity(temp0)
v[i] = temp1
temp2 = identity(temp1)
w[i] = temp2

What may be happening is that it's getting parsed in the wrong order. It sees the store into v[i] and that we load from v[i], and then thinks that we're reloading the same value that we stored.

Something like this:

function swap_debug_sa(v, w)
    LoopVectorization.@turbo_debug for i in axes(v, 1)
        wi = w[i]
        w[i] = v[i]
        v[i] = wi
    end
end
ls_sa = swap_debug_sa(v, w);

With this, we get

julia> ls_sa.operations
6-element Vector{LoopVectorization.Operation}:
 var"##op#234" = w[i]
 var"##op#235" = v[i]
 var"##op#236" = LoopVectorization.identity(var"##op#235")
 w[i] = var"##op#236"
 var"##op#238" = LoopVectorization.identity(var"##op#234")
 v[i] = var"##op#238"

So the fix is probably just to make sure things get parsed in the right order.

chriselrod avatar Aug 17 '22 14:08 chriselrod