JuliaSIMD / JuliaSIMD/LoopVectorization.jl

`@turbo` gives wrong output with `%()` (in some cases) but correct with `mod()`

Aperta
#542 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub
Lingua principale
Julia
Stelle
789
Fork
73
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Descrizione

Hi,

I've run into a weird issue with some modulo operations in ***some*** loops using `@turbo`.

The loop is essentially this:
```Julia
@turbo for kk in eachindex(results)
results[kk] = (results[kk] * bases[kk]) % m
end
```

It works most of the time (and with most inputs) but not always. Here's a script below with some test cases:

```Julia
using LoopVectorization
using Test

function test!(f!::Function, results::AbstractVector{UInt32})
bases = copy(results)
results .= UInt32(1)
e, m = 437, 6059

for ii in 1 : Int(ceil(log(Float64(e)) / log(2)))
if (e >> (ii - 1)) & 1 == 1
f!(results, bases, m)
end

# For some loop in this loop @turbo works fine, even if it also has mod(x, m)
@turbo for jj in eachindex(bases)
v = bases[jj]
bases[jj] = (v * v) % m
end
end

return results
end
function f1!(results::AbstractVector{UInt32}, bases::AbstractVector{UInt32}, m::Integer)
@turbo for kk in eachindex(results)
results[kk] = (results[kk] * bases[kk]) % m
end
end
function f2!(results::AbstractVector{UInt32}, bases::AbstractVector{UInt32}, m::Integer)
@turbo for kk in eachindex(results)
results[kk] *= bases[kk]
end
@turbo for kk in eachindex(results)
results[kk] %= m
end
end
function f3!(results::AbstractVector{UInt32}, bases::AbstractVector{UInt32}, m::Integer)
@turbo for kk in eachindex(results)
results[kk] *= bases[kk]
end

# Somehow adding @turbo to this loop makes it give wrong result
for kk in eachindex(results)
results[kk] %= m
end
end
function f4!(results::AbstractVector{UInt32}, bases::AbstractVector{UInt32}, m::Integer)
@turbo for kk in eachindex(results)
results[kk] = mod(results[kk] * bases[kk], m) # !!! using mod() instead of % gives correct result
end
end

@testset "tests" begin
@test powermod(82, 437, 6059) == 5394 # Validation

@test Int.(test!(f1!, UInt32.([82]))) == [5394] # <- Wrong
@test Int.(test!(f2!, UInt32.([82]))) == [5394] # <- Still wrong

@test Int.(test!(f3!, UInt32.([82]))) == [5394] # This one is correct
@test Int.(test!(f4!, UInt32.([82]))) == [5394] # !!!Somehow this is also correct

# Below (different input) is correct for all
@test powermod(80, 437, 6059) == 3667 # Validation
@test Int.(test!(f1!, UInt32.([80]))) == [3667]
@test Int.(test!(f2!, UInt32.([80]))) == [3667]
@test Int.(test!(f3!, UInt32.([80]))) == [3667]
@test Int.(test!(f4!, UInt32.([80]))) == [3667]
end
```

- In the `test!` function there's 2 loops doing similar operations (just different inputs), I haven't found an issue with the 2nd loop yet
- I've separated operations into separate loops to track down (`f2!` and `f3!`) - the issue seems to come from modulo operation
- Wrong result seems to be rare (most inputs are ok) but they do happen
- Using `mod()` instead of `%()` fixes the issue

Results on my laptop below (although I see the same on 2 different machines - different CPUs, both on windows)
```Julia
tests: Test Failed at c:\Users\titas\Code\AeroMap.jl\WIP\test.jl:66
Expression: Int.(test!(f1!, UInt32.([82]))) == [5394]
Evaluated: [2068] == [5394]

tests: Test Failed at c:\Users\titas\Code\AeroMap.jl\WIP\test.jl:67
Expression: Int.(test!(f2!, UInt32.([82]))) == [5394]
Evaluated: [2068] == [5394]

Test Summary: | Pass Fail Total Time
tests | 8 2 10 0.4s
ERROR: Some tests did not pass: 8 passed, 2 failed, 0 errored, 0 broken.
```

Guida per i contributori

Nessuna guida per i contributori indicizzata per questo repository

Direzione di ricerca

Inizia eseguendo il riproduttore Julia fornito e confronta f1!, f2!, f3! e f4!, in particolare i cicli @turbo che usano % rispetto a mod(). Traccia la gestione delle espressioni modulo nell’entry point di LoopVectorization e aggiungi un test di regressione che mostri il risultato previsto per l’input UInt32 che fallisce. Il lavoro è completato quando il riproduttore passa senza modificare i casi corretti.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
julia
Ambito
performance
Tipo di issue
Bug
Difficoltà
4/5
Tempo stimato
3-5 giorni
Stato di attività
Ferma
Chiarezza
Abbastanza chiara
Idoneità per principianti
42/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.