I don’t get it. I used to believe that the following two versions are lowered identically (I just made all scopes and loops explicit):
julia> function v5a(n :: Int)
prime = Array{Bool}(undef, n)
fill!(prime, true)
rr=2:n
it = iterate(rr)
@label loopstart
(it === nothing) && @goto loopend
let (i,s) = it
if any(i%j==0 for j in 2:i-1)
prime[i]=false
end
it = iterate(rr,s)
@goto loopstart
end
@label loopend
return prime
end
julia> function v5b(n :: Int)
prime = Array{Bool}(undef, n)
fill!(prime, true)
rr=2:n
it = iterate(rr)
@label loopstart
(it === nothing) && @goto loopend
let
(i,s) = it
if any(i%j==0 for j in 2:i-1)
prime[i]=false
end
it = iterate(rr,s)
@goto loopstart
end
@label loopend
return prime
end
However,
julia> N=1000; v5a(N);v5b(N);@time v5a(N);@time v5b(N);
0.000459 seconds (5 allocations: 1.219 KiB)
0.007087 seconds (22.20 k allocations: 379.313 KiB)
Imo both variants should be identical after lowering (before inference)?
Or is there any difference in semantics between let a = b \n body end
and let \n a = b \n body end
, under the assumption that the identifier a
is not present in the outer function scope (which is know during lowering!)?
If there is no semantic difference, then there is quite a bit of pre-inference optimization potential.