# Why the compiler can't optimize this simple code?

**URL:** <https://discourse.julialang.org/t/why-the-compiler-cant-optimize-this-simple-code/122504>\
**Category:** Performance\
**Created:** [November 11, 2024, 4:31pm UTC](https://discourse.julialang.org/t/why-the-compiler-cant-optimize-this-simple-code/122504 "2024-11-11T16:31:53Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![guoyongzhi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/guoyongzhi/32/28306_2.png) [@guoyongzhi](https://discourse.julialang.org/u/guoyongzhi)\
**Post date:** [November 11, 2024, 4:31pm UTC](https://discourse.julialang.org/t/why-the-compiler-cant-optimize-this-simple-code/122504/1 "2024-11-11T16:31:53Z")

</div>

In the following minimum example, the function `f1` is optimized, but the function `f2` is not. Is there any essential difficulty that hinders the compiler to do so? Can I make the `setfield!(a, a.i, v)` pattern faster?  
And [here](https://github.com/guo-yong-zhi/Stuffing.jl/blob/main/src/common_datatypes.jl#L213-L214) is my actual code which need that pattern.

The minimum example is as following:

```julia
mutable struct A
	val::Int
	i::Int
end
function f1(v)
	a = A(v, 1)
	i = 1 # <- 
	setfield!(a, i, v)
	a.val
end
function f2(v)
	a = A(v, 1)
	# a.i = 1 # optional
	i = a.i # <- 
	setfield!(a, i, v)
	a.val
end

```

```julia
@code_llvm f1(1)

```

> ; Function Signature: f1(Int64)  
> ; @ path within `f1`  
> ; Function Attrs: uwtable  
> define i64 @julia\_f1\_28558(i64 signext %“v::Int64”) #0 {  
> top:  
> ret i64 %“v::Int64”  
> }

```julia
@code_llvm f2(1)

```

> ; Function Signature: f2(Int64)  
> ; @ path within `f2`  
> ; Function Attrs: uwtable  
> define i64 @julia\_f2\_28289(i64 signext %“v::Int64”) #0 {  
> top:  
> %jlcallframe1 = alloca [3 x ptr], align 8  
> %gcframe2 = alloca [5 x ptr], align 16  
> call void @llvm.memset.p0.i64(ptr align 16 %gcframe2, i8 0, i64 40, i1 true)  
> %pgcstack = call ptr inttoptr (i64 140735906416704 to ptr)() #9  
> store i64 12, ptr %gcframe2, align 16  
> %frame.prev = getelementptr inbounds ptr, ptr %gcframe2, i64 1  
> %task.gcstack = load ptr, ptr %pgcstack, align 8  
> store ptr %task.gcstack, ptr %frame.prev, align 8  
> store ptr %gcframe2, ptr %pgcstack, align 8  
> ; @ path within `f2`  
> ; ┌ @ path within `A`  
> %ptls\_field = getelementptr inbounds ptr, ptr %pgcstack, i64 2  
> %ptls\_load = load ptr, ptr %ptls\_field, align 8  
> %“new::A” = call noalias nonnull align 8 dereferenceable(32) ptr @ijl\_gc\_pool\_alloc\_instrumented(ptr %ptls\_load, i32 800, i32 32, i64 1468019289872) #7  
> %“new::A.tag\_addr” = getelementptr inbounds i64, ptr %“new::A”, i64 -1  
> store atomic i64 1468019289872, ptr %“new::A.tag\_addr” unordered, align 8  
> store i64 %“v::Int64”, ptr %“new::A”, align 8  
> %“new::A.i\_ptr” = getelementptr inbounds i8, ptr %“new::A”, i64 8  
> store i64 1, ptr %“new::A.i\_ptr”, align 8  
> %gc\_slot\_addr\_2 = getelementptr inbounds ptr, ptr %gcframe2, i64 4  
> store ptr %“new::A”, ptr %gc\_slot\_addr\_2, align 16  
> ; └  
> ; @ path within `f2`  
> %box\_Int64 = call nonnull align 8 dereferenceable(8) ptr @ijl\_box\_int64(i64 signext 1) #2  
> %gc\_slot\_addr\_1 = getelementptr inbounds ptr, ptr %gcframe2, i64 3  
> store ptr %box\_Int64, ptr %gc\_slot\_addr\_1, align 8  
> %box\_Int642 = call nonnull align 8 dereferenceable(8) ptr @ijl\_box\_int64(i64 signext %“v::Int64”) #2  
> %gc\_slot\_addr\_0 = getelementptr inbounds ptr, ptr %gcframe2, i64 2  
> store ptr %box\_Int642, ptr %gc\_slot\_addr\_0, align 16  
> store ptr %“new::A”, ptr %jlcallframe1, align 8  
> %0 = getelementptr inbounds ptr, ptr %jlcallframe1, i64 1  
> store ptr %box\_Int64, ptr %0, align 8  
> %1 = getelementptr inbounds ptr, ptr %jlcallframe1, i64 2  
> store ptr %box\_Int642, ptr %1, align 8  
> %jl\_f\_setfield\_ret = call nonnull ptr @jl\_f\_setfield(ptr null, ptr nonnull %jlcallframe1, i32 3)  
> ; @ path within `f2`  
> ; ┌ @ Base.jl:49 within `getproperty`  
> %“new::A.val” = load i64, ptr %“new::A”, align 8  
> %frame.prev11 = load ptr, ptr %frame.prev, align 8  
> store ptr %frame.prev11, ptr %pgcstack, align 8  
> ret i64 %“new::A.val”  
> ; └  
> }

---

<div class="post-metadata">

**Author:** ![aviatesk](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aviatesk/32/7610_2.png) [@aviatesk](https://discourse.julialang.org/u/aviatesk)\
**Post date:** [November 11, 2024, 4:47pm UTC](https://discourse.julialang.org/t/why-the-compiler-cant-optimize-this-simple-code/122504/2 "2024-11-11T16:47:53Z")

</div>

The compiler can’t propagate fields of mutable struct as constant unless they are declared as `const`. Marking the `i::Int` as `const` would allow the compiler to optimize it.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [November 11, 2024, 5:00pm UTC](https://discourse.julialang.org/t/why-the-compiler-cant-optimize-this-simple-code/122504/3 "2024-11-11T17:00:01Z")

</div>

We are constant propagating (or concretely evaluating?) through non-const fields in `f1` though, so I don’t think it’s that unreasonable to be surprised that `f1` worked but `f2` didn’t.

There’s not really any reason why we’d need to promise to the compiler that `i` is a `const` field since the compiler could just see and know that nothing can mutate that field and propagate through it.

---

<div class="post-metadata">

**Author:** ![aviatesk](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aviatesk/32/7610_2.png) [@aviatesk](https://discourse.julialang.org/u/aviatesk)\
**Post date:** [November 11, 2024, 5:11pm UTC](https://discourse.julialang.org/t/why-the-compiler-cant-optimize-this-simple-code/122504/4 "2024-11-11T17:11:54Z")

</div>

The value of the third argument of `setfield!` in `f1` is a literal constant but that in `f2` isn’t. We would need escape analysis to prove that field remains to be the literal constant in f2.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [November 11, 2024, 5:17pm UTC](https://discourse.julialang.org/t/why-the-compiler-cant-optimize-this-simple-code/122504/5 "2024-11-11T17:17:36Z")

</div>

What I mean is that in `f1`, the compiler is able to know that

```julia
a = A(v, 1)
setfield(a, 1, v)
a.val

```

returns `v`, which also requires the compiler to know that nothing else is modifying `a.val` during the function’s execution.

This means that there already is _some_ level of analysis about what can and cannot change inside a mutable struct without explicitly using `const.`

---

<div class="post-metadata">

**Author:** ![guoyongzhi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/guoyongzhi/32/28306_2.png) [@guoyongzhi](https://discourse.julialang.org/u/guoyongzhi)\
**Post date:** [November 11, 2024, 5:25pm UTC](https://discourse.julialang.org/t/why-the-compiler-cant-optimize-this-simple-code/122504/6 "2024-11-11T17:25:36Z")

</div>

> [@aviatesk](#):
>
> Marking the `i::Int` as `const` would allow the compiler to optimize it

I tried

```julia
mutable struct A
	const val::Ref{Int}
	const i::Ref{Int}
end
function f3(v)
	a = A(0, 1)
	@inbounds i = a.i[]
	@inbounds getfield(a, i)[]=v
	@inbounds a.val[]
end

```

It seems to take effect. The llvm code is much shorter (maybe faster than `f2`?) It simply `ret i64 %“v::Int64”` at the end just like the `f1` does, but still has some other checking code.

```julia
@code_llvm f3(1)

```

> ; Function Signature: f3(Int64)  
> ; @ path within `f3`  
> ; Function Attrs: uwtable  
> define i64 @julia\_f3\_33901(i64 signext %“v::Int64”) #0 {  
> pass:  
> %gcframe1 = alloca [4 x ptr], align 16  
> call void @llvm.memset.p0.i64(ptr align 16 %gcframe1, i8 0, i64 32, i1 true)  
> %pgcstack = call ptr inttoptr (i64 140735906416704 to ptr)() #6  
> store i64 8, ptr %gcframe1, align 16  
> %frame.prev = getelementptr inbounds ptr, ptr %gcframe1, i64 1  
> %task.gcstack = load ptr, ptr %pgcstack, align 8  
> store ptr %task.gcstack, ptr %frame.prev, align 8  
> store ptr %gcframe1, ptr %pgcstack, align 8  
> ; @ path within `f3`  
> call void @llvm.assume(i1 icmp ne (ptr @“+Main.Base.RefValue#33903.jit”, ptr @“+Core.GenericMemoryRef#33907.jit”))  
> %frame.prev35 = load ptr, ptr %frame.prev, align 8  
> store ptr %frame.prev35, ptr %pgcstack, align 8  
> ; @ path within `f3`  
> ; ┌ @ refvalue.jl:59 within `getindex`  
> ; │┌ @ Base.jl:49 within `getproperty`  
> ret i64 %“v::Int64”  
> ; └└  
> }

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [November 11, 2024, 5:36pm UTC](https://discourse.julialang.org/t/why-the-compiler-cant-optimize-this-simple-code/122504/7 "2024-11-11T17:36:37Z")

</div>

> [@guoyongzhi](#):
>
> ```julia
> mutable struct A
> const val::Ref{Int}
> const i::Ref{Int}
> end
> 
> ```

That’s not what @aviatesk was suggesting, you’ve just shunted the non-const-ness off by a extra layer of indirection (also `Ref` is an abstract type).

His suggestion was rather that you should write

```julia
mutable struct A
    val::Int
    const i::Int
end

```

and then your `f2` will optimize away.

---

<div class="post-metadata">

**Author:** ![guoyongzhi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/guoyongzhi/32/28306_2.png) [@guoyongzhi](https://discourse.julialang.org/u/guoyongzhi)\
**Post date:** [November 11, 2024, 5:45pm UTC](https://discourse.julialang.org/t/why-the-compiler-cant-optimize-this-simple-code/122504/8 "2024-11-11T17:45:55Z")

</div>

> [@Mason](#):
>
> nothing else is modifying `a.val` during the function’s execution

I think the `a = A(0, 1)` is a local variable within the `f2`, so nothing outside the `f2` can modify it. (Right? Is there any edge case? Multi threading? I’m not sure…)  
If it’s impossible theoretically or just because of the imperfection of the compiler?

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [November 11, 2024, 5:46pm UTC](https://discourse.julialang.org/t/why-the-compiler-cant-optimize-this-simple-code/122504/9 "2024-11-11T17:46:28Z")

</div>

Why isn’t LLVM escape analysis able to prove that `A` doesn’t need to exist?

---

<div class="post-metadata">

**Author:** ![guoyongzhi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/guoyongzhi/32/28306_2.png) [@guoyongzhi](https://discourse.julialang.org/u/guoyongzhi)\
**Post date:** [November 11, 2024, 5:53pm UTC](https://discourse.julialang.org/t/why-the-compiler-cant-optimize-this-simple-code/122504/10 "2024-11-11T17:53:29Z")

</div>

> [@Mason](#):
>
> His suggestion was rather that …

Yes. I tried. And `f2` is optimized away. But a mutable `A.i` is [what I need](https://github.com/guo-yong-zhi/Stuffing.jl/blob/main/src/common_datatypes.jl#L213-L214) and I want to make it faster.

---

<div class="post-metadata">

**Author:** ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)\
**Post date:** [November 11, 2024, 8:30pm UTC](https://discourse.julialang.org/t/why-the-compiler-cant-optimize-this-simple-code/122504/11 "2024-11-11T20:30:45Z")

</div>

For your type, I’d change implementation altogether to

```julia
mutable struct SVector4{T}<:AbstractVector{T}
    len::Int8
    vec::NTuple{4,T}
    SVector4{T}() where {T} = new{T}(0)
    SVector4{T}(x) where T = new{T}(1, (x, x, x, x))
    SVector4{T}(x, y) where T = new{T}(2, (x, y, y, y))
    SVector4{T}(x, y, z) where T = new{T}(3, (x, y, z, z))
    SVector4{T}(e1, e2, e3, e4) where T = new{T}(4, (e1, e2, e3, e4))
end

SVector4(e1::T, e2::T, e3::T, e4::T) where T = SVector4{T}(e1, e2, e3, e4)
function SVector4(x, y, z, q)
    e1, e2, e3, e4 = promote(x, y, z, q)
    return SVector4(e1, e2, e3, e4)
end

function Base.getindex(v::SVector4, i::Integer)
    i in Base.OneTo(v.len) || throw(BoundsError(v, i))
    return v.vec[i]
end

function Base.setindex!(v::SVector4{T}, x, i) where T
    i in Base.OneTo(v.len) || throw(BoundsError(v, i))
    v.vec = Base.setindex(v.vec, convert(T, x), i)
    return x
end

function Base.push!(v::SVector4{T}, x) where T
    v.len < 4 || error("Cannot `push!`: vector reached maximum capacity")
    y = convert(T, x)
    if isdefined(v, :vec)
        v.len += 1
        v[v.len] = y
    else
        v.vec = (y, y, y, y)
        v.len = 1
    end
    return v
end

Base.length(v::SVector4) = v.len
Base.size(v::SVector4) = (v.len,)
Base.iterate(v::SVector4, i=1) = i in Base.OneTo(v.len) ? (v[i], i+1) : nothing
Base.eltype(::Type{SVector4{T}}) where T = T
Base.empty!(v::SVector4) = (v.len = 0; v)
Base.isempty(v::SVector4) = v.len == 0

```

On my machine, `push!` for this implementation is ~40% faster than yours, indexing is a bit slower due to bounds checks, the same if checks are removed.

---

<div class="post-metadata">

**Author:** ![matthias314](https://avatars.discourse-cdn.com/v4/letter/m/a88e4f/32.png) [@matthias314](https://discourse.julialang.org/u/matthias314)\
**Post date:** [November 11, 2024, 9:32pm UTC](https://discourse.julialang.org/t/why-the-compiler-cant-optimize-this-simple-code/122504/12 "2024-11-11T21:32:06Z")

</div>

This looks very much like [`MutableSmallVector{N,T}`](https://matthias314.github.io/SmallCollections.jl/dev/capacityvector/#SmallCollections.MutableSmallVector) from my package SmallCollections.jl. While the immutable [`SmallVector{N,T}`](https://matthias314.github.io/SmallCollections.jl/dev/capacityvector/#SmallCollections.SmallVector) is already in the published version, `MutableSmallVector` is only in master. I’m planning to publish a new release soon. If you want to try out the mutable variant, you need to say `add SmallCollections#master` in the Julia package manager.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [November 12, 2024, 3:30am UTC](https://discourse.julialang.org/t/why-the-compiler-cant-optimize-this-simple-code/122504/13 "2024-11-12T03:30:24Z")

</div>

```julia
julia> @code_typed f1(3)
CodeInfo(
1 ─ return v
) => Int64

julia> @code_typed f2(3)
CodeInfo(
1 ─ %1 = %new(Main.A, v, 1)::A
│ %2 = Base.getfield(%1, :i)::Int64
│ Main.setfield!(%1, %2, v)::Int64
│ %4 = Base.getfield(%1, :val)::Int64
└── return %4
) => Int64

```

Yeah it really feels like `getfield(a, :i)` right after `a = A(v, 1)` could’ve been known to be `1` and propagated, the same way `A.val` is known to be `v` by the end. Strictly speaking, `v` wasn’t a constant either. Maybe the difference is `v` isn’t reassigned, but `a` was mutated (one of its fields was reassigned), so there’s extra work to check for effective constants that isn’t being done now? There is a balance between the amount (read: latency) of compiler optimization and trimming of the source code that is not satisfactory in all cases.

---

<div class="post-metadata">

**Author:** ![guoyongzhi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/guoyongzhi/32/28306_2.png) [@guoyongzhi](https://discourse.julialang.org/u/guoyongzhi)\
**Post date:** [November 12, 2024, 3:39am UTC](https://discourse.julialang.org/t/why-the-compiler-cant-optimize-this-simple-code/122504/14 "2024-11-12T03:39:59Z")

</div>

> [@Vasily\_Pisarev](#):
>
> `v.vec = Base.setindex(v.vec, convert(T, x), i)`

Wonderful! The compiler can optimize the `Base.setindex` correctly and there are no redundant copy in the last llvm code!  
I can’t find the doc of `Base.setindex` on the [doc website](https://docs.julialang.org/en/v1/). Is it a public api?

* * *

My test code:

```julia
function fv1(v)
	a = SVector4(1,2,3,4)
	a[2] = 1
	a[a[2]] = v
	a[a[2]]
end

```

> ; Function Signature: fv1(Int64)  
> ; @ path within `fv1`  
> define i64 @julia\_fv1\_9799(i64 signext %“v::Int64”) #0 {  
> L44:  
> ; @ path within `fv1`  
> ; ┌ @ path within `getindex` @ tuple.jl:31  
> ret i64 %“v::Int64”  
> ; └  
> }

(I also add two `@inbounds` within the definition of the functions `getindex` and `push` of @Vasily_Pisarev’s `SVector4`)

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [November 12, 2024, 3:44am UTC](https://discourse.julialang.org/t/why-the-compiler-cant-optimize-this-simple-code/122504/15 "2024-11-12T03:44:02Z")

</div>

> [@guoyongzhi](#):
>
> I can’t find the doc of `Base.setindex` on the [doc website](https://docs.julialang.org/en/v1/). Is it a public api?

v1.11 introduces the `public` keyword to mark API vs internals, so you can do reflection instead of poring over the documentation:

```julia
julia> Base.ispublic(Base, :setindex)
false

```

You also get a warning in help mode:

```julia
help?> Base.setindex
  │ Warning
  │
  │ The following bindings may be internal; they may change or be removed in future versions:
  │
  │ • Base.setindex

```

It only says “may be internal” because some packages may not have caught up to using `public`, so their documentation is still the last word.

---

<div class="post-metadata">

**Author:** ![guoyongzhi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/guoyongzhi/32/28306_2.png) [@guoyongzhi](https://discourse.julialang.org/u/guoyongzhi)\
**Post date:** [November 12, 2024, 3:54am UTC](https://discourse.julialang.org/t/why-the-compiler-cant-optimize-this-simple-code/122504/16 "2024-11-12T03:54:11Z")

</div>

> [@matthias314](#):
>
> very much like [`MutableSmallVector{N,T}`](https://matthias314.github.io/SmallCollections.jl/dev/capacityvector/#SmallCollections.MutableSmallVector)

It use the `unsafe_load` trick to get around the type system, which is another way to make fast small collections. I am hope for a smarter compiler instead.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [November 12, 2024, 5:33am UTC](https://discourse.julialang.org/t/why-the-compiler-cant-optimize-this-simple-code/122504/17 "2024-11-12T05:33:17Z")

</div>

> [@guoyongzhi](#):
>
> It use the `unsafe_load` trick to get around the type system

That’s not what it’s for, in fact it’s documented to specifically take a pointer’s type into account. It’s just a low level function when you need to implement a type and its `getindex` from scratch instead of using Base types that have their own low level code. In this case, a vector with a known maximum number of elements cannot be built on `Vector`s with an unfixed number of elements, and compilers won’t do that for you, although mutables with known maximum sizes do share possible optimizations from escape analysis. Heap-to-stack allocation isn’t happening here though:

```julia
julia> @btime f2($3)
  23.631 ns (1 allocation: 32 bytes)
3

```

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [November 12, 2024, 6:22am UTC](https://discourse.julialang.org/t/why-the-compiler-cant-optimize-this-simple-code/122504/18 "2024-11-12T06:22:05Z")

</div>

> [@guoyongzhi](#):
>
> I can’t find the doc of `Base.setindex` on the [doc website](https://docs.julialang.org/en/v1/). Is it a public api?

Not yey but soon.

> <https://github.com/JuliaLang/julia/pull/55129>
>
> setindex() is a widely used well-documented function, it should be marked public…, right?
> 
> Not sure what's the right way to make a function with multiple methods public, please correct me if I'm wrong here!

---

<div class="post-metadata">

**Author:** ![vchuravy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vchuravy/32/8_2.png) [@vchuravy](https://discourse.julialang.org/u/vchuravy)\
**Post date:** [November 12, 2024, 3:51pm UTC](https://discourse.julialang.org/t/why-the-compiler-cant-optimize-this-simple-code/122504/19 "2024-11-12T15:51:02Z")

</div>

> [@Oscar\_Smith](#):
>
> Why isn’t LLVM escape analysis able to prove that `A` doesn’t need to exist?

It probably could, but this is a phase-ordering problem. In `setfield(a, field, val)` if `field` is non-const inference and codegen don’t know which field is being targeted and thus this will likely emit a runtime call. LLVM could remove `A` and then propagate the value there, but at that point it is too late. We would have needed to codegen a “union-split” over the possible fields.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [November 12, 2024, 4:02pm UTC](https://discourse.julialang.org/t/why-the-compiler-cant-optimize-this-simple-code/122504/20 "2024-11-12T16:02:07Z")

</div>

> [@vchuravy](#):
>
> It probably could, but this is a phase-ordering problem.

I was a bit confused by this at first, but now I think I get it. The argument is basically that LLVM could understand it in theory, but by the time LLVM gets it, we’ve already inserted a runtime dispatch on the julia-side so it’s too late for LLVM to optimize it, is that right?

[Next page](https://discourse.julialang.org/t/why-the-compiler-cant-optimize-this-simple-code/122504.md?page=2)
