forked from JuliaLang/julia
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
jl_special_vector_alignment: Remove work-around for old LLVM version …
…(<=3.8) (JuliaLang#34490) LLVM <= 3.8 segfaults when LLVM SIMD vectors are not powers of 2 (or a sum of 2 different powers of 2). This LLVM bug was corrected in 2017 (see <https://bugs.llvm.org/show_bug.cgi?id=27708>). This change removes this work-around, finally allowing arbitrary SIMD vector lengths in Julia. This changes Julia's ABI for SIMD types. All SIMD types are now represented as SIMD vectors in LLVM. The work-around represented some SIMD types as LLVM arrays instead to avoid the LLVM segfault. I don't think that SIMD vector lengths that are not a power of 2 were in widespread use, if at all. (cherry picked from commit e0740fe)
- Loading branch information
1 parent
727180e
commit c7dd7af
Showing
1 changed file
with
122 additions
and
122 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,122 +1,122 @@ | ||
# This file is a part of Julia. License is MIT: https://julialang.org/license | ||
|
||
make_value(::Type{T}, i::Integer) where {T<:Integer} = 3*i%T | ||
make_value(::Type{T},i::Integer) where {T<:AbstractFloat} = T(3*i) | ||
|
||
const Vec{N,T} = NTuple{N,Base.VecElement{T}} | ||
|
||
# Crash report for #15244 motivated this test. | ||
@generated function thrice_iota(::Type{Vec{N,T}}) where {N,T} | ||
:(tuple($([:(Base.VecElement(make_value($T,$i))) for i in 1:N]...))) | ||
end | ||
|
||
function call_iota(n::Integer,t::DataType) | ||
x = thrice_iota(Vec{n,t}) | ||
@test x[1].value === make_value(t,1) | ||
@test x[n].value === make_value(t,n) | ||
end | ||
|
||
# Try various tuple lengths and element types | ||
for i=1:20 | ||
for t in [Bool, Int8, Int16, Int32, Int64, Float32, Float64] | ||
call_iota(i,t) | ||
end | ||
end | ||
|
||
# Try various large tuple lengths and element types #20961 | ||
for i in (34, 36, 48, 64, 72, 80, 96) | ||
for t in [Bool, Int8, Int16, Int32, Int64, Float32, Float64] | ||
call_iota(i,t) | ||
end | ||
end | ||
|
||
# Another crash report for #15244 motivated this test. | ||
struct Bunch{N,T} | ||
elts::NTuple{N,Base.VecElement{T}} | ||
end | ||
|
||
unpeel(x) = x.elts[1].value | ||
@test unpeel(Bunch{2,Float64}((Base.VecElement(5.0), | ||
Base.VecElement(4.0)))) === 5.0 | ||
|
||
rewrap(x) = VecElement(x.elts[1].value + 0) | ||
let b = Bunch((VecElement(1.0), VecElement(2.0))) | ||
@test rewrap(b) === VecElement(1.0) | ||
end | ||
|
||
struct Herd{N,T} | ||
elts::NTuple{N,Base.VecElement{T}} | ||
Herd{N,T}(elts::NTuple{N,T}) where {N,T} = new(ntuple(i->Base.VecElement{T}(elts[i]), N)) | ||
end | ||
|
||
function check(x::Herd{N,T}) where {N,T} | ||
for i=1:N | ||
@test x.elts[i].value === N*N+i-1 | ||
end | ||
end | ||
|
||
check(Herd{1,Int}((1,))) | ||
check(Herd{2,Int}((4,5))) | ||
check(Herd{4,Int}((16,17,18,19))) | ||
|
||
struct Gr{N, T} | ||
u::T | ||
v::Bunch{N,T} | ||
w::T | ||
end | ||
|
||
let a = Vector{Gr{2,Float64}}(undef, 2) | ||
a[2] = Gr(1.0, Bunch((VecElement(2.0), VecElement(3.0))), 4.0) | ||
a[1] = Gr(5.0, Bunch((VecElement(6.0), VecElement(7.0))), 8.0) | ||
@test a[2] == Gr(1.0, Bunch((VecElement(2.0), VecElement(3.0))), 4.0) | ||
end | ||
|
||
@test isa(VecElement((1,2)), VecElement{Tuple{Int,Int}}) | ||
|
||
# test for alignment agreement (#32414) | ||
@noinline function bar32414(a) | ||
v = ntuple(w -> VecElement(Float64(10w)), Val(8)) | ||
return a, (v, (a, (1e6, 1e9))) | ||
end | ||
@test bar32414(-35.0) === (-35.0, ((VecElement(10.0), VecElement(20.0), VecElement(30.0), VecElement(40.0), VecElement(50.0), VecElement(60.0), VecElement(70.0), VecElement(80.0)), (-35.0, (1.0e6, 1.0e9)))) | ||
|
||
# The following test mimic SIMD.jl | ||
const _llvmtypes = Dict{DataType, String}( | ||
Float64 => "double", | ||
Float32 => "float", | ||
Int32 => "i32", | ||
Int64 => "i64" | ||
) | ||
|
||
@generated function vecadd(x::Vec{N, T}, y::Vec{N, T}) where {N, T} | ||
llvmT = _llvmtypes[T] | ||
func = T <: AbstractFloat ? "fadd" : "add" | ||
exp = """ | ||
%3 = $(func) <$(N) x $(llvmT)> %0, %1 | ||
ret <$(N) x $(llvmT)> %3 | ||
""" | ||
return quote | ||
Base.@_inline_meta | ||
Core.getfield(Base, :llvmcall)($exp, Vec{$N, $T}, Tuple{Vec{$N, $T}, Vec{$N, $T}}, x, y) | ||
end | ||
end | ||
|
||
function f20961(x::Vector{Vec{N, T}}, y::Vector{Vec{N, T}}) where{N, T} | ||
@inbounds begin | ||
a = x[1] | ||
b = y[1] | ||
return vecadd(a, b) | ||
end | ||
end | ||
|
||
# Test various SIMD Vectors with known good sizes | ||
for T in (Float64, Float32, Int64, Int32) | ||
for N in 1:36 | ||
a = ntuple(i -> VecElement(T(i)), N) | ||
result = ntuple(i -> VecElement(T(i+i)), N) | ||
b = vecadd(a, a) | ||
@test b == result | ||
b = f20961([a], [a]) | ||
@test b == result | ||
end | ||
end | ||
# This file is a part of Julia. License is MIT: https://julialang.org/license | ||
|
||
make_value(::Type{T}, i::Integer) where {T<:Integer} = 3*i%T | ||
make_value(::Type{T},i::Integer) where {T<:AbstractFloat} = T(3*i) | ||
|
||
const Vec{N,T} = NTuple{N,Base.VecElement{T}} | ||
|
||
# Crash report for #15244 motivated this test. | ||
@generated function thrice_iota(::Type{Vec{N,T}}) where {N,T} | ||
:(tuple($([:(Base.VecElement(make_value($T,$i))) for i in 1:N]...))) | ||
end | ||
|
||
function call_iota(n::Integer,t::DataType) | ||
x = thrice_iota(Vec{n,t}) | ||
@test x[1].value === make_value(t,1) | ||
@test x[n].value === make_value(t,n) | ||
end | ||
|
||
# Try various tuple lengths and element types | ||
for i=1:20 | ||
for t in [Bool, Int8, Int16, Int32, Int64, Float32, Float64] | ||
call_iota(i,t) | ||
end | ||
end | ||
|
||
# Try various large tuple lengths and element types #20961 | ||
for i in (34, 36, 48, 64, 72, 80, 96) | ||
for t in [Bool, Int8, Int16, Int32, Int64, Float32, Float64] | ||
call_iota(i,t) | ||
end | ||
end | ||
|
||
# Another crash report for #15244 motivated this test. | ||
struct Bunch{N,T} | ||
elts::NTuple{N,Base.VecElement{T}} | ||
end | ||
|
||
unpeel(x) = x.elts[1].value | ||
@test unpeel(Bunch{2,Float64}((Base.VecElement(5.0), | ||
Base.VecElement(4.0)))) === 5.0 | ||
|
||
rewrap(x) = VecElement(x.elts[1].value + 0) | ||
let b = Bunch((VecElement(1.0), VecElement(2.0))) | ||
@test rewrap(b) === VecElement(1.0) | ||
end | ||
|
||
struct Herd{N,T} | ||
elts::NTuple{N,Base.VecElement{T}} | ||
Herd{N,T}(elts::NTuple{N,T}) where {N,T} = new(ntuple(i->Base.VecElement{T}(elts[i]), N)) | ||
end | ||
|
||
function check(x::Herd{N,T}) where {N,T} | ||
for i=1:N | ||
@test x.elts[i].value === N*N+i-1 | ||
end | ||
end | ||
|
||
check(Herd{1,Int}((1,))) | ||
check(Herd{2,Int}((4,5))) | ||
check(Herd{4,Int}((16,17,18,19))) | ||
|
||
struct Gr{N, T} | ||
u::T | ||
v::Bunch{N,T} | ||
w::T | ||
end | ||
|
||
let a = Vector{Gr{2,Float64}}(undef, 2) | ||
a[2] = Gr(1.0, Bunch((VecElement(2.0), VecElement(3.0))), 4.0) | ||
a[1] = Gr(5.0, Bunch((VecElement(6.0), VecElement(7.0))), 8.0) | ||
@test a[2] == Gr(1.0, Bunch((VecElement(2.0), VecElement(3.0))), 4.0) | ||
end | ||
|
||
@test isa(VecElement((1,2)), VecElement{Tuple{Int,Int}}) | ||
|
||
# test for alignment agreement (#32414) | ||
@noinline function bar32414(a) | ||
v = ntuple(w -> VecElement(Float64(10w)), Val(8)) | ||
return a, (v, (a, (1e6, 1e9))) | ||
end | ||
@test bar32414(-35.0) === (-35.0, ((VecElement(10.0), VecElement(20.0), VecElement(30.0), VecElement(40.0), VecElement(50.0), VecElement(60.0), VecElement(70.0), VecElement(80.0)), (-35.0, (1.0e6, 1.0e9)))) | ||
|
||
# The following test mimic SIMD.jl | ||
const _llvmtypes = Dict{DataType, String}( | ||
Float64 => "double", | ||
Float32 => "float", | ||
Int32 => "i32", | ||
Int64 => "i64" | ||
) | ||
|
||
@generated function vecadd(x::Vec{N, T}, y::Vec{N, T}) where {N, T} | ||
llvmT = _llvmtypes[T] | ||
func = T <: AbstractFloat ? "fadd" : "add" | ||
exp = """ | ||
%3 = $(func) <$(N) x $(llvmT)> %0, %1 | ||
ret <$(N) x $(llvmT)> %3 | ||
""" | ||
return quote | ||
Base.@_inline_meta | ||
Core.getfield(Base, :llvmcall)($exp, Vec{$N, $T}, Tuple{Vec{$N, $T}, Vec{$N, $T}}, x, y) | ||
end | ||
end | ||
|
||
function f20961(x::Vector{Vec{N, T}}, y::Vector{Vec{N, T}}) where{N, T} | ||
@inbounds begin | ||
a = x[1] | ||
b = y[1] | ||
return vecadd(a, b) | ||
end | ||
end | ||
|
||
# Test various SIMD Vectors with known good sizes | ||
for T in (Float64, Float32, Int64, Int32) | ||
for N in 1:36 | ||
a = ntuple(i -> VecElement(T(i)), N) | ||
result = ntuple(i -> VecElement(T(i+i)), N) | ||
b = vecadd(a, a) | ||
@test b == result | ||
b = f20961([a], [a]) | ||
@test b == result | ||
end | ||
end |