Which variable initialization is optimized away when variable unused?

I have a method where x is used, but y isn’t used.

Why when I assign sqrt(100) to y then it’s ignored and not even executed (which is the desired behaviour), but when it’s assigned collect(1:100) then it is executed?

Is there an official separation between all the functions that are optimized away when the variable isn’t used in the scope versus those that aren’t?

function f1(z)
    x = 5
    y = sqrt(100) # unused
    return z + x
end

@code_native f1(5)

output very short, and x value is inlined:

	.text
; ┌ @ In[2]:6 within `f1`
; │┌ @ int.jl:87 within `+`
	leaq	5(%rdi), %rax
; │└
	retq
	nopw	%cs:(%rax,%rax)
; └

but this one becomes huge output which means collect isn’t removed:

function f2(z)
    x = 5
    y = collect(1:10) # unused
    return z + x
end

@code_native f2(5)

semantically there is no difference. However, it is much harder to delete allocations, especially since Array allocations go through a ccall that makes some optimizations harder. That said, recent dev versions of Julia are getting better at doing escape analysis which is the required optimization to delete the allocation.

5 Likes

https://github.com/JuliaLang/julia/pull/43548

2 Likes