IfElse doesn't work properly when using @turbo

function iftest(x)
    bestIndex = 0
    minValue = Inf
    @turbo for i in eachindex(x)
        bestIndex = ifelse(x[i] < minValue, i, bestIndex)
        minValue = min(x[i], minValue)
    end
    return minValue, bestIndex
end

Running iftest(collect(1:1000) |> reverse) throws an error

ERROR: LoadError: "Failed to find matching reduction to select"
Stacktrace:
  [1] ifelse_reduction(f::LoopVectorization.var"#71#72"{Expr}, rsym::Symbol, op::LoopVectorization.Operation)
    @ LoopVectorization C:\Users\gag\.julia\packages\LoopVectorization\XbdFG\src\modeling\operations.jl:548
  [2] outer_reduction_to_scalar_reduceq!(q::Expr, op::LoopVectorization.Operation, var::Symbol)
    @ LoopVectorization C:\Users\gag\.julia\packages\LoopVectorization\XbdFG\src\condense_loopset.jl:1082
  [3] outer_reduction_to_scalar_reduceq!
    @ C:\Users\gag\.julia\packages\LoopVectorization\XbdFG\src\condense_loopset.jl:1072 [inlined]
  [4] setup_outerreduct_preserve(ls::LoopVectorization.LoopSet, call::Expr, preserve::Vector{Symbol})
    @ LoopVectorization C:\Users\gag\.julia\packages\LoopVectorization\XbdFG\src\condense_loopset.jl:1103
  [5] generate_call_types(ls::LoopVectorization.LoopSet, preserve::Vector{Symbol}, shouldindbyind::Vector{Bool}, roots::Vector{Bool}, extra_args::Expr, ::Tuple{Bool, Int8, Int8, Int8}, thread::UInt64, warncheckarg::Int64, safe::Bool, debug::Bool)
    @ LoopVectorization C:\Users\gag\.julia\packages\LoopVectorization\XbdFG\src\condense_loopset.jl:908
  [6] generate_call_split(ls::LoopVectorization.LoopSet, preserve::Vector{Symbol}, shouldindbyind::Vector{Bool}, roots::Vector{Bool}, extra_args::Expr, inlineu₁u₂::Tuple{Bool, Int8, Int8, Int8}, thread::UInt64, warncheckarg::Int64, safe::Bool, debug::Bool)
    @ LoopVectorization C:\Users\gag\.julia\packages\LoopVectorization\XbdFG\src\condense_loopset.jl:794
  [7] generate_call(ls::LoopVectorization.LoopSet, inlineu₁u₂::Tuple{Bool, Int8, Int8, Int8}, thread::UInt64, warncheckarg::Int64, safe::Bool, debug::Bool)
    @ LoopVectorization C:\Users\gag\.julia\packages\LoopVectorization\XbdFG\src\condense_loopset.jl:749
  [8] setup_call(ls::LoopVectorization.LoopSet, q::Expr, source::LineNumberNode, inline::Bool, check_empty::Bool, u₁::Int8, u₂::Int8, v::Int8, thread::Int64, warncheckarg::Int64, safe::Bool)
    @ LoopVectorization C:\Users\gag\.julia\packages\LoopVectorization\XbdFG\src\condense_loopset.jl:1143
  [9] turbo_macro(::Module, ::LineNumberNode, ::Expr)      
    @ LoopVectorization C:\Users\gag\.julia\packages\LoopVectorization\XbdFG\src\constructors.jl:277
 [10] var"@turbo"(__source__::LineNumberNode, __module__::Module, args::Vararg{Any})
    @ LoopVectorization C:\Users\gag\.julia\packages\LoopVectorization\XbdFG\src\constructors.jl:404

But changing the ifelse to ifelse(x[i] < minValue, i, bestIndex+0) makes the function run fine.
Is there a reason that the original code doesn’t work?

A simpler example that doesn’t depend on order of execution is

function iftest(x)
    bestIndex = 0
    minValue = 4
    @turbo for i in eachindex(x)
        bestIndex = x[i] < minValue ? i : bestIndex
    end
    return bestIndex
end

I just realised that the returned value for bestIndex has been wrong in all of the functions I’ve given, not sure what’s going on there as even doing bestIndex = x[i] < minValue ? i : 4 gives the wrong value.

All of the iterations in eachindex are trying to read and write bestIndex at the same time, no? There is a race condition so I don’t think it can be vectorized.

See this comment also:

I just realised that the returned value for bestIndex has been wrong in all of the functions I’ve given, not sure what’s going on there as even doing bestIndex = x[i] < minValue ? i : 4 gives the wrong value.

What do you mean? Removing turbo from your last version seems to do what it should.

1 Like

I meant with turbo they were all returning the wrong results, but the commit you linked clears up what I’ve been doing wrong. Thanks

1 Like