diff --git a/src/datatypes.jl b/src/datatypes.jl index 9dd721fcc..cefe5aa92 100644 --- a/src/datatypes.jl +++ b/src/datatypes.jl @@ -149,7 +149,7 @@ end function Datatype(::Type{T}) where {T} global created_datatypes - get!(created_datatypes, T) do + datatype = get!(created_datatypes, T) do datatype = Datatype() # lazily initialize so that it can be safely precompiled function init() @@ -162,6 +162,15 @@ function Datatype(::Type{T}) where {T} init() datatype end + + # Make sure the "aligned" size of the type matches the MPI "extent". + sz = sizeof(T) + al = Base.datatype_alignment(T) + mpi_extent = Types.extent(datatype) + aligned_size = (0, cld(sz,al)*al) + @assert mpi_extent == aligned_size "The MPI extent of type $(T) ($(mpi_extent[2])) does not match the size expected by Julia ($(aligned_size[2]))" + + return datatype end function Base.show(io::IO, datatype::Datatype) @@ -437,8 +446,10 @@ function create!(newtype::Datatype, ::Type{T}) where {T} types = Datatype[] if isprimitivetype(T) - # primitive type - szrem = sz = sizeof(T) + # This is a primitive type. Create a type which has size an integer multiple of its + # alignment on the Julia side: . + al = Base.datatype_alignment(T) + szrem = sz = cld(sizeof(T), al) * al disp = 0 for (i,basetype) in (8 => Datatype(UInt64), 4 => Datatype(UInt32), 2 => Datatype(UInt16), 1 => Datatype(UInt8)) if sz == i diff --git a/test/test_datatype.jl b/test/test_datatype.jl index c966a9678..ab8385d75 100644 --- a/test/test_datatype.jl +++ b/test/test_datatype.jl @@ -87,18 +87,17 @@ end primitive type Primitive16 16 end primitive type Primitive24 24 end primitive type Primitive80 80 end +primitive type Primitive104 104 end +primitive type Primitive136 136 end -@testset for PrimitiveType in (Primitive16, Primitive24, Primitive80) +@testset for PrimitiveType in (Primitive16, Primitive24, Primitive80, Primitive104, Primitive136) sz = sizeof(PrimitiveType) al = Base.datatype_alignment(PrimitiveType) @test MPI.Types.extent(MPI.Datatype(PrimitiveType)) == (0, cld(sz,al)*al) - if VERSION < v"1.3" && PrimitiveType == Primitive80 - # alignment is broken on earlier Julia versions - continue - end + conv = sizeof(PrimitiveType) <= sizeof(UInt128) ? Core.Intrinsics.trunc_int : Core.Intrinsics.sext_int - arr = [Core.Intrinsics.trunc_int(PrimitiveType, UInt128(comm_rank + i)) for i = 1:4] + arr = [conv(PrimitiveType, UInt128(comm_rank + i)) for i = 1:4] arr_recv = Array{PrimitiveType}(undef,4) recv_req = MPI.Irecv!(arr_recv, src, 2, MPI.COMM_WORLD) @@ -106,7 +105,7 @@ primitive type Primitive80 80 end MPI.Waitall([recv_req, send_req]) - @test arr_recv == [Core.Intrinsics.trunc_int(PrimitiveType, UInt128(src + i)) for i = 1:4] + @test arr_recv == [conv(PrimitiveType, UInt128(src + i)) for i = 1:4] end @testset "packed non-aligned tuples" begin