Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use powi from x^p #43

Merged
merged 4 commits into from
Jan 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 44 additions & 13 deletions src/SIMD.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,18 @@ for sz in (8, 16, 32, 64, 128)

Base.convert(::Type{Bool}, b::$Boolsz) = b.int != 0

Base. ~(b::$Boolsz) = $Boolsz(~b.int)
Base. !(b::$Boolsz) = ~b
Base. &(b1::$Boolsz, b2::$Boolsz) = $Boolsz(b1.int & b2.int)
Base. |(b1::$Boolsz, b2::$Boolsz) = $Boolsz(b1.int | b2.int)
Base.:~(b::$Boolsz) = $Boolsz(~b.int)
Base.:!(b::$Boolsz) = ~b
Base.:&(b1::$Boolsz, b2::$Boolsz) = $Boolsz(b1.int & b2.int)
Base.:|(b1::$Boolsz, b2::$Boolsz) = $Boolsz(b1.int | b2.int)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are inside the comment so I wasn't sure if it's better to change them or leave them as-is. Let me know if I need to revert them (I'll remove this from the patch and then force-push).

Base.$(:$)(b1::$Boolsz, b2::$Boolsz) = $Boolsz(b1.int $ b2.int)

Base. ==(b1::$Boolsz, b2::$Boolsz) = $Boolsz(b1.int == b2.int)
Base. !=(b1::$Boolsz, b2::$Boolsz) = $Boolsz(b1.int != b2.int)
Base. <(b1::$Boolsz, b2::$Boolsz) = $Boolsz(b1.int < b2.int)
Base. <=(b1::$Boolsz, b2::$Boolsz) = $Boolsz(b1.int <= b2.int)
Base. >(b1::$Boolsz, b2::$Boolsz) = $Boolsz(b1.int > b2.int)
Base. >=(b1::$Boolsz, b2::$Boolsz) = $Boolsz(b1.int >= b2.int)
Base.:==(b1::$Boolsz, b2::$Boolsz) = $Boolsz(b1.int == b2.int)
Base.:!=(b1::$Boolsz, b2::$Boolsz) = $Boolsz(b1.int != b2.int)
Base.:<(b1::$Boolsz, b2::$Boolsz) = $Boolsz(b1.int < b2.int)
Base.:<=(b1::$Boolsz, b2::$Boolsz) = $Boolsz(b1.int <= b2.int)
Base.:>(b1::$Boolsz, b2::$Boolsz) = $Boolsz(b1.int > b2.int)
Base.:>=(b1::$Boolsz, b2::$Boolsz) = $Boolsz(b1.int >= b2.int)
end
end
Base.convert(::Type{Bool}, b::Boolean) = error("impossible")
Expand Down Expand Up @@ -115,7 +115,7 @@ Vec(xs::NTuple{N,T}) where {N,T<:ScalarTypes} = Vec{N,T}(xs)
@inline Tuple(v::Vec{N}) where {N} = ntuple(i -> v.elts[i].value, Val(N))
@inline NTuple{N, T}(v::Vec{N}) where{N, T} = ntuple(i -> convert(T, v.elts[i].value), Val(N))

@generated function Base. %(v::Vec{N,T}, ::Type{Vec{N,R}}) where {N,R,T}
@generated function Base.:%(v::Vec{N,T}, ::Type{Vec{N,R}}) where {N,R,T}
quote
$(Expr(:meta, :inline))
Vec{N,R}(tuple($([:(v.elts[$i].value % R) for i in 1:N]...)))
Expand Down Expand Up @@ -560,6 +560,33 @@ end
end
end

# Functions taking two arguments, second argument is a scalar
@generated function llvmwrap(::Type{Val{Op}}, v1::Vec{N,T1},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to just use ccall("@llvm.powi.v4f64", llvmcall, RT, (AT...,), args...)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it specific to @llvm.powi? Can all other llvmwrap methods be implemented with ccall? Maybe only if there is only one instruction other than declare?

s2::ScalarTypes, ::Type{R} = T1) where {Op,N,T1,R}
@assert isa(Op, Symbol)
typ1 = llvmtype(T1)
vtyp1 = "<$N x $typ1>"
typ2 = llvmtype(s2)
typr = llvmtype(R)
vtypr = "<$N x $typr>"
ins = llvmins(Val{Op}, N, T1)
decls = []
instrs = []
if ins[1] == '@'
push!(decls, "declare $vtypr $ins($vtyp1, $typ2)")
push!(instrs, "%res = call $vtypr $ins($vtyp1 %0, $typ2 %1)")
else
push!(instrs, "%res = $ins $vtyp1 %0, %1")
end
push!(instrs, "ret $vtypr %res")
quote
$(Expr(:meta, :inline))
Vec{N,R}(Base.llvmcall($((join(decls, "\n"), join(instrs, "\n"))),
NTuple{N,VE{R}}, Tuple{NTuple{N,VE{T1}}, $s2},
v1.elts, s2))
end
end

# Functions taking two arguments, returning Bool
@generated function llvmwrap(::Type{Val{Op}}, v1::Vec{N,T1},
v2::Vec{N,T2}, ::Type{Bool}) where {Op,N,T1,T2}
Expand Down Expand Up @@ -900,7 +927,7 @@ for op in (:~, :+, :-)
llvmwrap(Val{$(QuoteNode(op))}, v1)
end
end
@inline Base. !(v1::Vec{N,Bool}) where {N} = ~v1
@inline Base.:!(v1::Vec{N,Bool}) where {N} = ~v1
@inline function Base.abs(v1::Vec{N,T}) where {N,T<:IntTypes}
# s = -Vec{N,T}(signbit(v1))
s = v1 >> Val{8*sizeof(T)}
Expand Down Expand Up @@ -986,7 +1013,11 @@ for op in (:+, :-, :*, :/, :^, :copysign, :max, :min, :rem)
llvmwrap(Val{$(QuoteNode(op))}, v1, v2)
end
end
@inline Base. ^(v1::Vec{N,T}, x2::Integer) where {N,T<:FloatingTypes} =
# Using `IntegerTypes` here so that this definition "wins" against
# `^(::ScalarTypes, v2::Vec)`.
@inline Base.:^(v1::Vec{N,T}, x2::IntegerTypes) where {N,T<:FloatingTypes} =
llvmwrap(Val{:powi}, v1, Int(x2))
@inline Base.:^(v1::Vec{N,T}, x2::Integer) where {N,T<:FloatingTypes} =
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you using Base.:^ instead of Base. ^ here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just thought it's better since Base.:^ is more explicit. FYI, it looks like julia code base prefer Base.:^:

$ git grep 'Base\. ^'
$ git grep 'Base\.:^'
base/compiler/ssair/show.jl:^(s::String, i::Int) = Base.:^(s, i)
base/mathconstants.jl:    Base.:^(::Irrational{:ℯ}, x::T) = exp(x)
doc/src/base/math.md:Base.:^(::Number, ::Number)
doc/src/base/strings.md:Base.:^(::AbstractString, ::Integer)
stdlib/LinearAlgebra/docs/src/index.md:Base.:^(::AbstractMatrix, ::Number)
stdlib/LinearAlgebra/docs/src/index.md:Base.:^(::Number, ::AbstractMatrix)
stdlib/LinearAlgebra/src/dense.jl:Base.:^(b::Number, A::AbstractMatrix) = exp!(log(b)*A)
stdlib/LinearAlgebra/src/dense.jl:Base.:^(::Irrational{:ℯ}, A::AbstractMatrix) = exp(A)
test/math.jl:Base.:^(x::Number, y::Float22716) = x^(y.x)

But I don't mind using Base. ^. Let me know if I need to switch to it.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't seen this syntax before. If it works then it's fine. I'm mostly worried about consistency of style in the source code; people shouldn't wonder why there is ^ in one and :^ in other places. If you prefer :^, then I'd prefer a pull request that changes this everywhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this is the only place Base.:^ is used but there are other similar cases like Base. %; I replaced them all.

llvmwrap(Val{:powi}, v1, Int(x2))
@inline Base.flipsign(v1::Vec{N,T}, v2::Vec{N,T}) where {N,T<:FloatingTypes} =
vifelse(signbit(v2), -v1, v1)
Expand Down
10 changes: 9 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,14 @@ llvm_ir(f, args) = sprint(code_llvm, f, Base.typesof(args...))
@test Tuple(op(V4F64(v4f64), V4F64(v4f64b), V4F64(v4f64c))) ===
map(op, v4f64, v4f64b, v4f64c)
end

v = V4F64(v4f64)
@test v^5 === v * v * v * v * v

# Make sure our dispatching rule does not select floating point `pow`.
# See: https://github.com/eschnett/SIMD.jl/pull/43
ir = llvm_ir(^, (V4F64(v4f64), 2))
@test occursin("@llvm.powi.v4f64", ir)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

end

@testset "Type promotion" begin
Expand Down Expand Up @@ -242,7 +250,7 @@ llvm_ir(f, args) = sprint(code_llvm, f, Base.typesof(args...))

for op in (
==, !=, <, <=, >, >=,
+, -, *, /, ^, copysign, flipsign, max, min, rem)
+, -, *, /, copysign, flipsign, max, min, rem)
@test op(42, V4F64(v4f64)) === op(V4F64(42), V4F64(v4f64))
@test op(V4F64(v4f64), 42) === op(V4F64(v4f64), V4F64(42))
end
Expand Down