Between 1.7.3 and 1.8.0-rc1 it seems like the compiler stopped calculating exponentiation Float64^Int literals (maybe other to, havenβt checked) if the exponent is larger than 3. This resulted in adding an overhead for variables defined like that.
Here is 1.7.3
julia> f() = 2.0^4
f (generic function with 2 methods)
julia> @code_llvm f()
; @ REPL[8]:1 within `f`
define double @julia_f_873() #0 {
top:
ret double 1.600000e+01
}
and 1.8.0-rc1
julia> f() = 2.0^3
f (generic function with 2 methods)
julia> @code_llvm f()
; @ REPL[12]:1 within `f`
define double @julia_f_1201() #0 {
top:
ret double 8.000000e+00
}
julia> f() = 2.0^4
f (generic function with 2 methods)
julia> @code_llvm f()
; @ REPL[14]:1 within `f`
define double @julia_f_1203() #0 {
top:
; β @ intfuncs.jl:326 within `literal_pow`
; ββ @ math.jl:1037 within `^`
%0 = call double @j_pow_body_1205(double 2.000000e+00, i64 signext 4) #0
; ββ
ret double %0
}
Checking the source for Float64^Int we see that there has certainly been come changes (seems to mostly be from this PR) between the versions.
If the function is pure and the inputs are literals, could the compiler calculate it? Is there any reason it shouldnβt? Why does it do it with the first and not the second?
Here is 1.7.3
@inline function ^(x::Float64, y::Integer)
y == -1 && return inv(x)
y == 0 && return one(x)
y == 1 && return x
y == 2 && return x*x
y == 3 && return x*x*x
ccall("llvm.pow.f64", llvmcall, Float64, (Float64, Float64), x, Float64(y))
end
and 1.8.0-rc1
@constprop :aggressive @inline function ^(x::Float64, n::Integer)
n == 0 && return one(x)
return pow_body(x, n)
end
@assume_effects :terminates_locally @noinline function pow_body(x::Float64, n::Integer)
y = 1.0
xnlo = ynlo = 0.0
n == 3 && return x*x*x # keep compatibility with literal_pow
if n < 0
rx = inv(x)
n==-2 && return rx*rx #keep compatability with literal_pow
isfinite(x) && (xnlo = -fma(x, rx, -1.) * rx)
x = rx
n = -n
end
while n > 1
if n&1 > 0
err = muladd(y, xnlo, x*ynlo)
y, ynlo = two_mul(x,y)
ynlo += err
end
err = x*2*xnlo
x, xnlo = two_mul(x, x)
xnlo += err
n >>>= 1
end
!isfinite(x) && return x*y
return muladd(x, y, muladd(y, xnlo, x*ynlo))
end