@@ -742,24 +742,78 @@ end
742742end
743743
744744@testset " argument layout" begin
745- kernel (x) = nothing
746-
747- # plain 128-bit integers occupy their own parameter slot, so are fine
745+ # the back-end aligns 128-bit integers to 16 bytes, but Julia only started doing so in
746+ # 1.12, so aggregates with (U)Int128 fields lay out differently on older hosts. such
747+ # types are rejected there (host==device on 1.12+, so everything is accepted).
748+ @eval struct Int128Wrapper; x:: Int64 ; y:: Int128 ; end
749+ @eval struct FloatWrapper; x:: Int64 ; y:: Float64 ; end # control: no 128-bit integers
750+ host_ok = Base. datatype_alignment (Int128) == 16 # true on Julia 1.12+
751+
752+ # -- the compatibility walk must look through type parameters (e.g. device-array
753+ # element types), not just fields. this part is host-independent. --
754+ reaches_i128 (T) = CUDACore. layout_reaches (S -> S === Int128 || S === UInt128, T)
755+ @test reaches_i128 (Int128)
756+ @test reaches_i128 (Int128Wrapper) # via a field
757+ @test reaches_i128 (Tuple{Int64,Int128Wrapper}) # via a tuple element
758+ @test reaches_i128 (Ptr{Int128Wrapper}) # via a pointer's pointee
759+ @test reaches_i128 (CUDACore. CuDeviceArray{Int128Wrapper,1 ,1 }) # via an element type
760+ @test ! reaches_i128 (Float64)
761+ @test ! reaches_i128 (FloatWrapper)
762+ @test ! reaches_i128 (CUDACore. CuDeviceArray{Float64,1 ,1 })
763+
764+ @test CUDACore. device_layout (Int128) == (16 , 16 )
765+ @test CUDACore. device_layout (FloatWrapper) == (16 , 8 )
766+ @test CUDACore. device_layout (Int128Wrapper) === (host_ok ? (32 , 16 ) : :mismatch )
767+ @test CUDACore. device_compatible_layout (Int128Wrapper) == host_ok
768+ @test CUDACore. device_compatible_layout (CUDACore. CuDeviceArray{Int128Wrapper,1 ,1 }) == host_ok
769+ @test CUDACore. device_compatible_layout (CUDACore. CuDeviceArray{Float64,1 ,1 })
770+
771+ # -- end-to-end: rejected on <1.12, compiled and correct on 1.12+ --
772+
773+ # plain 128-bit integers occupy their own parameter slot / array element, and are fine
748774 # regardless of how the host aligns them
749- @cuda kernel (Int128 (1 ))
750- @test true
751-
752- # aggregates with 128-bit fields are only compatible when Julia aligns
753- # those to 16 bytes like the device does (i.e., on 1.12+)
754- @eval struct Int128Wrapper
755- x:: Int64
756- y:: Int128
757- end
758- if Base. datatype_alignment (Int128) == 16
759- @cuda kernel (Int128Wrapper (1 , 2 ))
760- @test true
775+ setval (out, v) = (@inbounds out[1 ] = v; return )
776+ let out = CuArray {Int128} (undef, 1 )
777+ @cuda setval (out, Int128 (2 )^ 100 + 7 )
778+ @test Array (out)[1 ] == Int128 (2 )^ 100 + 7
779+ end
780+
781+ # aggregate with a 128-bit field, passed as a kernel argument: read its field back so
782+ # the layout check (not an unrelated type error) is what fails on incompatible hosts
783+ gety (out, w) = (@inbounds out[1 ] = w. y; return )
784+ if host_ok
785+ out = CuArray {Int128} (undef, 1 )
786+ @cuda gety (out, Int128Wrapper (42 , Int128 (2 )^ 100 + 7 ))
787+ @test Array (out)[1 ] == Int128 (2 )^ 100 + 7
761788 else
762- @test_throws " layout differs" @cuda kernel (Int128Wrapper (1 , 2 ))
789+ out = CuArray {Int128} (undef, 1 )
790+ @test_throws " references 128-bit integer fields" @cuda gety (out, Int128Wrapper (42 , Int128 (2 )^ 100 + 7 ))
791+ end
792+
793+ # aggregate with a 128-bit field, reached as a device-array element (memory traffic;
794+ # this is only seen through a pointer, so it used to slip past the argument check)
795+ function readfields (out, A)
796+ i = threadIdx (). x
797+ @inbounds begin
798+ out[2 i- 1 ] = A[i]. x
799+ out[2 i] = A[i]. y % Int64
800+ end
801+ return
802+ end
803+ wrappers = [Int128Wrapper (1 , 2 ), Int128Wrapper (3 , 4 )]
804+ if host_ok
805+ dA = CuArray (wrappers); out = CuArray {Int64} (undef, 4 )
806+ @cuda threads= 2 readfields (out, dA)
807+ @test Array (out) == [1 , 2 , 3 , 4 ]
808+ else
809+ dA = CuArray (wrappers); out = CuArray {Int64} (undef, 4 )
810+ @test_throws " references 128-bit integer fields" @cuda threads= 2 readfields (out, dA)
811+ end
812+
813+ # control: an aggregate without 128-bit integers is always accepted
814+ let out = CuArray {Float64} (undef, 1 )
815+ @cuda gety (out, FloatWrapper (1 , 3.5 ))
816+ @test Array (out)[1 ] == 3.5
763817 end
764818end
765819
0 commit comments