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

Add support for intrinsics for NTuple{VecElement} #55118

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
25 changes: 23 additions & 2 deletions base/simd.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module SIMD

import Base: VecElement, Memory, MemoryRef
import Base: VecElement, Memory, MemoryRef, IEEEFloat
import Base: @propagate_inbounds, @_propagate_inbounds_meta, @_boundscheck, @_noub_if_noinbounds_meta
import Base: memoryrefget, memoryrefnew, memoryrefset!

Expand Down Expand Up @@ -46,7 +46,6 @@ function Base.show(io::IO, v::Vec{N, T}) where {N, T}
print(io, "]")
end

import Base: +, -, *

# Mocked vload/vstore! relying on SLP

Expand Down Expand Up @@ -80,4 +79,26 @@ end
return nothing
end

import Base: +, -, *, /, muladd, promote_rule, widen
import Core.Intrinsics: add_float, sub_float, mul_float, div_float, muladd_float, neg_float

## floating point promotions ##
promote_rule(::Type{Vec{N, Float32}}, ::Type{Vec{N, Float16}}) where N = Vec{N, Float32}
Copy link
Member

Choose a reason for hiding this comment

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

It is not obvious to me that these should be defined. When you are doing low level SIMD stuff you probably don't want to accidentally promote things and in case where you really want to work with different types, an explicit convert might be better for clarity?

promote_rule(::Type{Vec{N, Float64}}, ::Type{Vec{N, Float16}}) where N = Vec{N, Float64}
promote_rule(::Type{Vec{N, Float64}}, ::Type{Vec{N, Float32}}) where N = Vec{N, Float64}

widen(::Type{Vec{N, Float16}}) where N = Vec{N, Float16}
widen(::Type{Vec{N, Float32}}) where N = Vec{N, Float32}

## floating point arithmetic ##
-(x::Vec{N,T}) where {N,T<:IEEEFloat} = neg_float(x.data)

+(x::Vec{N,T}, y::Vec{N,T}) where {N,T<:IEEEFloat} = add_float(x.data, y.data)
-(x::Vec{N,T}, y::Vec{N,T}) where {N,T<:IEEEFloat} = sub_float(x.data, y.data)
*(x::Vec{N,T}, y::Vec{N,T}) where {N,T<:IEEEFloat} = mul_float(x.data, y.data)
/(x::Vec{N,T}, y::Vec{N,T}) where {N,T<:IEEEFloat} = div_float(x.data, y.data)

muladd(x::Vec{N,T}, y::Vec{N,T}, z::Vec{N,T}) where {N, T<:IEEEFloat} =
muladd_float(x.data, y.data, z.data)

end # module
21 changes: 21 additions & 0 deletions test/simd.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,24 @@ end
@test contains(ir, "load <4 x double>")
@test !contains(ir, "call void @j_throw_boundserror")
end

@testset "basic arithmetic" begin
ir = sprint(io->code_llvm(io, +, (Vec{4, Float64}, Vec{4, Float64})))
@test contains(ir, "fadd <4 x double>")
ir = sprint(io->code_llvm(io, -, (Vec{4, Float64}, Vec{4, Float64})))
@test contains(ir, "fsub <4 x double>")
ir = sprint(io->code_llvm(io, *, (Vec{4, Float64}, Vec{4, Float64})))
@test contains(ir, "fmul <4 x double>")
ir = sprint(io->code_llvm(io, /, (Vec{4, Float64}, Vec{4, Float64})))
@test contains(ir, "fdiv <4 x double>")

ir = sprint(io->code_llvm(io, muladd, (Vec{4, Float64}, Vec{4, Float64}, Vec{4, Float64})))
@test contains(ir, "fmul contract <4 x double>")
@test contains(ir, "fadd contract <4 x double>")

ir = sprint(io->code_llvm(io, -, (Vec{4, Float64},)))
@test contains(ir, "fneg <4 x double>")

# TODO: Way to test Intrinsics directly?
#`-v` -> ERROR: neg_float_withtype: value is not a primitive type
end