Rules for constant elimination

Is there documentation for the rules for constant elimination? Or is there a well-documented/readable source file I could read?

I recently ran into a rather severe performance gotcha in julia 0.6.0 (which is almost worth a bug report, either to speed up such cases or to document that such code does not work properly in julia):

function ft1(n)
    sum = 0
    for i in 1:n
        sum += (2^6)
    end
    return sum
end

function ft2(n)
    sum = 0
    for i in 1:n
        sum += 64
    end
    return sum
end

ft1(2)
ft2(2)

@time ft1(1000_000)
@time ft2(1000_000)

  0.010660 seconds (5 allocations: 176 bytes)
  0.000005 seconds (5 allocations: 176 bytes)

What happens is that julia decides to compute the power 2^6 by squaring, and apparently the fact that this is a pure function (no side effects) gets lost on the way, which prevents constant elimination.

Second question: Is there a way to mark pure functions (especially if they involve external library calls)? Something like @pure would go a long way to prevent such gotchas; then, one could go through Base and sprinkle @pure at various places (and some hypothetical future julia version might even try to autodetect some pure functions which don’t involve ccall).

[edit] PS. If the literal is sufficiently simple (e.g. 32+32 instead of 64) then llvm manages to remove the addition, but julia does not. Is constant elimination done at all, on the julia level? Or is this purely done on the llvm level, and there are no good heuristics whether inliner and llvm manage to eliminate a literal?

[edit2] PS. Ok, @Base.pure exists and does what we want, I just failed to find documentation (if it exists at all?). So the proper way would be to go through all of base, sprinkle magic @pure dust, and submit a pull-request?

1 Like

https://github.com/JuliaLang/julia/issues/14324