diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 06c06215dfad19..f3a7e5ea7e6d7a 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -524,7 +524,10 @@ static Type *julia_struct_to_llvm(jl_value_t *jt, jl_unionall_t *ua, bool *isbox #endif unsigned llvm_alignment = DL.getABITypeAlignment((Type*)jst->struct_decl); unsigned julia_alignment = jst->layout->alignment; - assert(llvm_alignment == julia_alignment); + // Check that the alignment adheres to the heap alignment. + assert(julia_alignment <= JL_SMALL_BYTE_ALIGNMENT); + if (llvm_alignment <= JL_SMALL_BYTE_ALIGNMENT) + assert(julia_alignment == llvm_alignment); } #endif } diff --git a/src/datatype.c b/src/datatype.c index 0bf85c8af246a2..ce7c46c24e7900 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -310,7 +310,10 @@ void jl_compute_field_offsets(jl_datatype_t *st) // Some tuples become LLVM vectors with stronger alignment than what was calculated above. unsigned al = jl_special_vector_alignment(nfields, lastty); assert(al % alignm == 0); - if (al) + // JL_SMALL_BYTE_ALIGNMENT is the smallest alignment we can guarantee on the heap. + if (al > JL_SMALL_BYTE_ALIGNMENT) + alignm = JL_SMALL_BYTE_ALIGNMENT; + else if (al) alignm = al; } st->size = LLT_ALIGN(sz, alignm); diff --git a/test/vecelement.jl b/test/vecelement.jl index 95209b143c28b5..49c34825def5ee 100644 --- a/test/vecelement.jl +++ b/test/vecelement.jl @@ -23,6 +23,13 @@ for i=1:20 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}} @@ -65,3 +72,56 @@ 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) @test isa(VecElement((1,2)), VecElement{Tuple{Int,Int}}) + +# 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 + Base.llvmcall($exp, + NTuple{N, VecElement{T}}, + Tuple{NTuple{N,VecElement{T}},NTuple{N,VecElement{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 + # For some vectortypes Julia emits llvm arrays instead of vectors + if N % 7 == 0 || N % 11 == 0 || N % 13 == 0 || N % 15 == 0 || + N % 19 == 0 || N % 23 == 0 || N % 25 == 0 || N % 27 == 0 || + N % 29 == 0 || N % 31 == 0 + continue + end + 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 + if N == 36 + code_llvm(STDOUT, f20961, (Vector{Vec{N, T}}, Vector{Vec{N, T}})) + end + end +end