From 52837cdf9bdd5b9cfc2fbfb472941ab14f3ab511 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Fri, 17 Feb 2017 12:22:47 -0500 Subject: [PATCH 1/7] minimal inlining of x^Val{p} for p=0,1,2,3 and x::Number --- base/gmp.jl | 4 ++++ base/intfuncs.jl | 7 +++++++ base/mpfr.jl | 5 +++++ 3 files changed, 16 insertions(+) diff --git a/base/gmp.jl b/base/gmp.jl index 8c4a14102689e..a5169d5f38297 100644 --- a/base/gmp.jl +++ b/base/gmp.jl @@ -443,6 +443,10 @@ end ^(x::Integer, y::BigInt ) = bigint_pow(BigInt(x), y) ^(x::Bool , y::BigInt ) = Base.power_by_squaring(x, y) +# override default inlining of x^2 and x^3 as x*x and x*x*x +^(x::BigInt, ::Type{Val{2}}) = x^convert(Culong, 2) +^(x::BigInt, ::Type{Val{3}}) = x^convert(Culong, 3) + function powermod(x::BigInt, p::BigInt, m::BigInt) r = BigInt() ccall((:__gmpz_powm, :libgmp), Void, diff --git a/base/intfuncs.jl b/base/intfuncs.jl index a7eb603ad61f3..e30995882bf3f 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -200,6 +200,13 @@ end # However, we still need a fallback that calls the general ^: ^{p}(x, ::Type{Val{p}}) = x^p +# inference.jl has complicated logic to inline x^2 and x^3 for +# numeric types. In terms of Val we can do it much more simply: +^(x::Number, ::Type{Val{0}}) = one(x) +^(x::Number, ::Type{Val{1}}) = x +^(x::Number, ::Type{Val{2}}) = x*x +^(x::Number, ::Type{Val{3}}) = x*x*x + # b^p mod m """ diff --git a/base/mpfr.jl b/base/mpfr.jl index 808de3a0ca3c7..46367580785f4 100644 --- a/base/mpfr.jl +++ b/base/mpfr.jl @@ -504,6 +504,11 @@ end ^(x::BigFloat, y::Integer) = typemin(Clong) <= y <= typemax(Clong) ? x^Clong(y) : x^BigInt(y) ^(x::BigFloat, y::Unsigned) = typemin(Culong) <= y <= typemax(Culong) ? x^Culong(y) : x^BigInt(y) +# override default inlining of x^2 and x^3 as x*x and x*x*x +^(x::BigFloat, ::Type{Val{2}}) = x^convert(Culong, 2) +^(x::BigFloat, ::Type{Val{3}}) = x^convert(Culong, 3) +^(x::BigFloat, ::Type{Val{1}}) = x^convert(Culong, 1) # might change precision + for f in (:exp, :exp2, :exp10, :expm1, :cosh, :sinh, :tanh, :sech, :csch, :coth, :cbrt) @eval function $f(x::BigFloat) z = BigFloat() From 856f3bf128a7fc327826a9a3f4c73cb22caea310 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Fri, 17 Feb 2017 12:26:26 -0500 Subject: [PATCH 2/7] news --- NEWS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS.md b/NEWS.md index 5a40283cb17ce..8f68503c14bd7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -76,6 +76,8 @@ Language changes * Experimental feature: `x^n` for integer literals `n` (e.g. `x^3` or `x^-3`) is now lowered to `x^Val{n}`, to enable compile-time specialization for literal integer exponents ([#20530]). + `x^p` for `x::Number` and `p=0,1,2,3` is now lowered to + `one(x)`, `x`, `x*x`, and `x*x*x`, respectively ([#20648]). Breaking changes ---------------- From ed0677e6000d5c471b148b82a0151da85a032166 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Fri, 17 Feb 2017 14:05:20 -0500 Subject: [PATCH 3/7] dispatch ^(x,p) to internal_pow(x,p) before dispatching on p=Val to avoid ambiguities for code that dispatches on the first argument --- base/intfuncs.jl | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/base/intfuncs.jl b/base/intfuncs.jl index e30995882bf3f..d299a8da27944 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -197,15 +197,18 @@ end # x^p for any literal integer p is lowered to x^Val{p}, # to enable compile-time optimizations specialized to p. -# However, we still need a fallback that calls the general ^: -^{p}(x, ::Type{Val{p}}) = x^p +# However, we still need a fallback that calls the general ^. +# To avoid ambiguities for methods that dispatch on the +# first argument, we dispatch the fallback via internal_pow: +^(x, p) = internal_pow(x, p) +internal_pow{p}(x, ::Type{Val{p}}) = x^p # inference.jl has complicated logic to inline x^2 and x^3 for # numeric types. In terms of Val we can do it much more simply: -^(x::Number, ::Type{Val{0}}) = one(x) -^(x::Number, ::Type{Val{1}}) = x -^(x::Number, ::Type{Val{2}}) = x*x -^(x::Number, ::Type{Val{3}}) = x*x*x +internal_pow(x::Number, ::Type{Val{0}}) = one(x) +internal_pow(x::Number, ::Type{Val{1}}) = x +internal_pow(x::Number, ::Type{Val{2}}) = x*x +internal_pow(x::Number, ::Type{Val{3}}) = x*x*x # b^p mod m From adf2106e9c5945a2105ea18d71b0fc0957b7271d Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Fri, 17 Feb 2017 14:09:40 -0500 Subject: [PATCH 4/7] e^literal should still call exp(literal), I guess --- base/irrationals.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/base/irrationals.jl b/base/irrationals.jl index 1d61d426a4f2f..55390ac126738 100644 --- a/base/irrationals.jl +++ b/base/irrationals.jl @@ -212,6 +212,7 @@ catalan for T in (Irrational, Rational, Integer, Number) ^(::Irrational{:e}, x::T) = exp(x) end +^{p}(::Irrational{:e}, ::Type{Val{p}}) = exp(p) log(::Irrational{:e}) = 1 # use 1 to correctly promote expressions like log(x)/log(e) log(::Irrational{:e}, x::Number) = log(x) From a03b4d10d05370168da2a9d8f9eb36ee6fb6a0ef Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Fri, 17 Feb 2017 15:21:41 -0500 Subject: [PATCH 5/7] Float16^Val{p} should still use Float32, simpler overriding of BigInt and BigFloat inlining --- base/float.jl | 1 + base/gmp.jl | 5 ++--- base/mpfr.jl | 6 ++---- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/base/float.jl b/base/float.jl index f3b7abdfa5c4c..8b9463be8099f 100644 --- a/base/float.jl +++ b/base/float.jl @@ -367,6 +367,7 @@ _default_type(T::Union{Type{Real},Type{AbstractFloat}}) = Float64 for op in (:+, :-, :*, :/, :\, :^) @eval ($op)(a::Float16, b::Float16) = Float16(($op)(Float32(a), Float32(b))) end +^{p}(x::Float16, ::Type{Val{p}}) = Float16(Float32(x)^Val{p}) +(x::Float32, y::Float32) = add_float(x, y) +(x::Float64, y::Float64) = add_float(x, y) -(x::Float32, y::Float32) = sub_float(x, y) diff --git a/base/gmp.jl b/base/gmp.jl index a5169d5f38297..c01b491e85083 100644 --- a/base/gmp.jl +++ b/base/gmp.jl @@ -443,9 +443,8 @@ end ^(x::Integer, y::BigInt ) = bigint_pow(BigInt(x), y) ^(x::Bool , y::BigInt ) = Base.power_by_squaring(x, y) -# override default inlining of x^2 and x^3 as x*x and x*x*x -^(x::BigInt, ::Type{Val{2}}) = x^convert(Culong, 2) -^(x::BigInt, ::Type{Val{3}}) = x^convert(Culong, 3) +# override default inlining of x^2 and x^3 etc. +^{p}(x::BigInt, ::Type{Val{p}}) = x^Culong(p) function powermod(x::BigInt, p::BigInt, m::BigInt) r = BigInt() diff --git a/base/mpfr.jl b/base/mpfr.jl index 46367580785f4..8592f2e75043a 100644 --- a/base/mpfr.jl +++ b/base/mpfr.jl @@ -504,10 +504,8 @@ end ^(x::BigFloat, y::Integer) = typemin(Clong) <= y <= typemax(Clong) ? x^Clong(y) : x^BigInt(y) ^(x::BigFloat, y::Unsigned) = typemin(Culong) <= y <= typemax(Culong) ? x^Culong(y) : x^BigInt(y) -# override default inlining of x^2 and x^3 as x*x and x*x*x -^(x::BigFloat, ::Type{Val{2}}) = x^convert(Culong, 2) -^(x::BigFloat, ::Type{Val{3}}) = x^convert(Culong, 3) -^(x::BigFloat, ::Type{Val{1}}) = x^convert(Culong, 1) # might change precision +# override default inlining of x^2 etc. +^{p}(x::BigFloat, ::Type{Val{p}}) = x^Culong(p) for f in (:exp, :exp2, :exp10, :expm1, :cosh, :sinh, :tanh, :sech, :csch, :coth, :cbrt) @eval function $f(x::BigFloat) From c0da24e85b017a9c268f1a16e4370dd4ceb8e3e3 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Fri, 17 Feb 2017 15:22:58 -0500 Subject: [PATCH 6/7] clarification --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 8f68503c14bd7..d23faaa9c2813 100644 --- a/NEWS.md +++ b/NEWS.md @@ -76,7 +76,7 @@ Language changes * Experimental feature: `x^n` for integer literals `n` (e.g. `x^3` or `x^-3`) is now lowered to `x^Val{n}`, to enable compile-time specialization for literal integer exponents ([#20530]). - `x^p` for `x::Number` and `p=0,1,2,3` is now lowered to + `x^p` for `x::Number` and a literal `p=0,1,2,3` is now lowered to `one(x)`, `x`, `x*x`, and `x*x*x`, respectively ([#20648]). Breaking changes From 3ef6d5714855370cf3878c88969847f2c61de578 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Fri, 17 Feb 2017 15:26:29 -0500 Subject: [PATCH 7/7] move Float16^Val{p} override to a better place --- base/float.jl | 1 - base/math.jl | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/base/float.jl b/base/float.jl index 8b9463be8099f..f3b7abdfa5c4c 100644 --- a/base/float.jl +++ b/base/float.jl @@ -367,7 +367,6 @@ _default_type(T::Union{Type{Real},Type{AbstractFloat}}) = Float64 for op in (:+, :-, :*, :/, :\, :^) @eval ($op)(a::Float16, b::Float16) = Float16(($op)(Float32(a), Float32(b))) end -^{p}(x::Float16, ::Type{Val{p}}) = Float16(Float32(x)^Val{p}) +(x::Float32, y::Float32) = add_float(x, y) +(x::Float64, y::Float64) = add_float(x, y) -(x::Float32, y::Float32) = sub_float(x, y) diff --git a/base/math.jl b/base/math.jl index 1735efc6e2e46..75c8917843ea2 100644 --- a/base/math.jl +++ b/base/math.jl @@ -676,6 +676,7 @@ end ^(x::Float32, y::Integer) = x^Int32(y) ^(x::Float32, y::Int32) = powi_llvm(x, y) ^(x::Float16, y::Integer) = Float16(Float32(x)^y) +^{p}(x::Float16, ::Type{Val{p}}) = Float16(Float32(x)^Val{p}) function angle_restrict_symm(theta) const P1 = 4 * 7.8539812564849853515625e-01