# Why is LLVM missing this constant in a loop?

**URL:** <https://discourse.julialang.org/t/why-is-llvm-missing-this-constant-in-a-loop/72941>\
**Category:** Performance\
**Tags:** performance, llvm\
**Created:** [December 11, 2021, 5:18pm UTC](https://discourse.julialang.org/t/why-is-llvm-missing-this-constant-in-a-loop/72941 "2021-12-11T17:18:06Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![Bardo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bardo/32/21601_2.png) [@Bardo](https://discourse.julialang.org/u/Bardo)\
**Post date:** [December 11, 2021, 5:18pm UTC](https://discourse.julialang.org/t/why-is-llvm-missing-this-constant-in-a-loop/72941/1 "2021-12-11T17:18:06Z")

</div>

```julia
using BenchmarkTools
using LinearAlgebra

function f(x,y)
    z = 0.0
    for i in 1:10
        xy = x .* y
        z += norm(xy)
    end
    z
end

function fopt(x,y)
    z = 0.0
    xy = x .* y
    for i in 1:10
        z += norm(xy)
    end
    z
end

x=rand(2); y=rand(2)
@btime f($x,$y)
@btime fopt($x,$y)

```

```julia
  464.467 ns (10 allocations: 800 bytes)
  146.643 ns (1 allocation: 80 bytes)

```

---

<div class="post-metadata">

**Author:** ![roflmaostc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/roflmaostc/32/30123_2.png) [@roflmaostc](https://discourse.julialang.org/u/roflmaostc)\
**Post date:** [December 11, 2021, 6:59pm UTC](https://discourse.julialang.org/t/why-is-llvm-missing-this-constant-in-a-loop/72941/2 "2021-12-11T18:59:47Z")

</div>

Is it a constant?  
I’m not familiar with LLVM but `x` and `y` are references to arrays which could change during execution of the loop.

See:

```julia
using BenchmarkTools
using LinearAlgebra

function f(x,y)
    z = 0.0 
    for i in 1:10
        xy = x .* y
        @show norm(xy) 
        z += norm(xy)
    end 
    z   
end

function g(x,y)
    for i = 1:10000000
        x .= rand(2)
        y .= rand(2)
    end
end

function f()
    x=rand(2); y=rand(2)
    Threads.@spawn g(x,y)
    f(x,y)
end

julia> f()
norm(xy) = 0.26590433662552576
norm(xy) = 0.603214499437178
norm(xy) = 1.0494104231262562
norm(xy) = 0.6612645779226971
norm(xy) = 0.3619931631859387
norm(xy) = 0.59579143483913
norm(xy) = 0.02516422097763711
norm(xy) = 0.6709932485823076
norm(xy) = 0.4531504941054873
norm(xy) = 0.19392321674706448
4.880809615549222

```

If you change that to Tuples (which are immutable), you’ll see the wanted behaviour:

```julia
function main()
    x=Tuple(rand(2)); y=Tuple(rand(2))
    @btime f($x,$y)
    @btime fopt($x,$y)
end 

# REPL
julia> main()
  42.424 ns (0 allocations: 0 bytes)
  41.396 ns (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

**Author:** ![Bardo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bardo/32/21601_2.png) [@Bardo](https://discourse.julialang.org/u/Bardo)\
**Post date:** [December 11, 2021, 7:12pm UTC](https://discourse.julialang.org/t/why-is-llvm-missing-this-constant-in-a-loop/72941/3 "2021-12-11T19:12:57Z")

</div>

> [@roflmaostc](#):
>
> Is it a constant?

In my code, yes:

```julia
using LinearAlgebra

function f(x,y)
    z = 0.0
    for i in 1:10
        @show xy = x .* y
        z += norm(xy)
    end
    z
end

x=rand(2); y=rand(2)
f(x,y)

```

```julia
xy = x .* y = [0.6666109828718713, 0.35500370844922313]
xy = x .* y = [0.6666109828718713, 0.35500370844922313]
xy = x .* y = [0.6666109828718713, 0.35500370844922313]
xy = x .* y = [0.6666109828718713, 0.35500370844922313]
xy = x .* y = [0.6666109828718713, 0.35500370844922313]
xy = x .* y = [0.6666109828718713, 0.35500370844922313]
xy = x .* y = [0.6666109828718713, 0.35500370844922313]
xy = x .* y = [0.6666109828718713, 0.35500370844922313]
xy = x .* y = [0.6666109828718713, 0.35500370844922313]
xy = x .* y = [0.6666109828718713, 0.35500370844922313]

```

---

<div class="post-metadata">

**Author:** ![ToucheSir](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/touchesir/32/14411_2.png) [@ToucheSir](https://discourse.julialang.org/u/ToucheSir)\
**Post date:** [December 11, 2021, 7:38pm UTC](https://discourse.julialang.org/t/why-is-llvm-missing-this-constant-in-a-loop/72941/4 "2021-12-11T19:38:17Z")

</div>

It may well be in practice, but to @roflmaostc’s point the _compiler_ can’t prove it is. Arrays in particular are a bit of a black box right now (there has been a lot of work recently on changing this, but that hasn’t made it to stable Julia yet).

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [December 11, 2021, 7:43pm UTC](https://discourse.julialang.org/t/why-is-llvm-missing-this-constant-in-a-loop/72941/5 "2021-12-11T19:43:01Z")

</div>

In theory it could optimize that to:

```julia
function fopt2(x,y)
    xy = x .* y
    z = 10*norm(xy)
    z
end;

```

But it doesn’t. (And by hand you can avoid calculating and allocating `xy`, if that is performance critical)

---

<div class="post-metadata">

**Author:** ![Bardo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bardo/32/21601_2.png) [@Bardo](https://discourse.julialang.org/u/Bardo)\
**Post date:** [December 11, 2021, 7:43pm UTC](https://discourse.julialang.org/t/why-is-llvm-missing-this-constant-in-a-loop/72941/6 "2021-12-11T19:43:10Z")

</div>

Thanks to both of you!  
One more reason to use tuples whenever possible.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [December 11, 2021, 7:58pm UTC](https://discourse.julialang.org/t/why-is-llvm-missing-this-constant-in-a-loop/72941/7 "2021-12-11T19:58:27Z")

</div>

> [@roflmaostc](#):
>
> I’m not familiar with LLVM but `x` and `y` are references to arrays which could change during execution of the loop.

The spawn example is very interesting and educative. Before that I would think that the compiler **should** optimize that out, and the fact that it doesn’t was an implementation detail.

Now, unlikely it is that any funcional code does what you have shown, such a change would be breaking.

What is the opinion of core developers on this? Can such optimizations be implemented in 1.x?

---

<div class="post-metadata">

**Author:** ![roflmaostc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/roflmaostc/32/30123_2.png) [@roflmaostc](https://discourse.julialang.org/u/roflmaostc)\
**Post date:** [December 11, 2021, 8:00pm UTC](https://discourse.julialang.org/t/why-is-llvm-missing-this-constant-in-a-loop/72941/8 "2021-12-11T20:00:02Z")

</div>

A new immutable Array type could fix that?  
That would be just a new non-breaking feature, wouldn’t it be?

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [December 11, 2021, 8:03pm UTC](https://discourse.julialang.org/t/why-is-llvm-missing-this-constant-in-a-loop/72941/9 "2021-12-11T20:03:58Z")

</div>

I cannot test now, but what happens with the mutable static arrays, `MArray`, of `StaticArrays`?

If in that case the optimization occurs, the behavior is inconsistent already.

(The immutable static arrays will behave like tuples here of course)

---

<div class="post-metadata">

**Author:** ![roflmaostc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/roflmaostc/32/30123_2.png) [@roflmaostc](https://discourse.julialang.org/u/roflmaostc)\
**Post date:** [December 11, 2021, 8:10pm UTC](https://discourse.julialang.org/t/why-is-llvm-missing-this-constant-in-a-loop/72941/10 "2021-12-11T20:10:15Z")

</div>

```julia
function main()
    x=rand(2); y=rand(2)

    xR, yR = ReadOnlyArray.((x,y))
    xS, yS = SVector(x...), SVector(y...)
    xM, yM = MVector(x...), MVector(y...)
    @btime f($xR,$yR)
    @btime fopt($xR,$yR)
    @btime f($xS,$yS)
    @btime fopt($xS,$yS)
    @btime f($xM,$yM)
    @btime fopt($xM,$yM)
end

# REPL
julia> main()
  597.750 ns (10 allocations: 800 bytes)
  126.113 ns (1 allocation: 80 bytes)
  3.245 ns (0 allocations: 0 bytes)
  3.245 ns (0 allocations: 0 bytes)
  4.823 ns (0 allocations: 0 bytes)
  4.851 ns (0 allocations: 0 bytes)
3.523747450734117

```

Strange, that `MVector` does not make a difference?

---

<div class="post-metadata">

**Author:** ![ToucheSir](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/touchesir/32/14411_2.png) [@ToucheSir](https://discourse.julialang.org/u/ToucheSir)\
**Post date:** [December 11, 2021, 8:16pm UTC](https://discourse.julialang.org/t/why-is-llvm-missing-this-constant-in-a-loop/72941/11 "2021-12-11T20:16:11Z")

</div>

It’s being worked on: [https://github.com/JuliaLang/julia/pull/41777](https://github.com/JuliaLang/julia/pull/41777)

`MArray` uses a backing `NTuple` for data storage, so presumably the optimizer has far more transparency to work with.
