diff --git a/lib/JLArrays/src/array.jl b/lib/JLArrays/src/array.jl index 530c7085..11b1b3ab 100644 --- a/lib/JLArrays/src/array.jl +++ b/lib/JLArrays/src/array.jl @@ -44,6 +44,21 @@ mutable struct JLArray{T, N} <: AbstractGPUArray{T, N} end GPUArrays.storage(a::JLArray) = a.data + +## alias detection + +# Byte-range overlap follows CUDA's Base.mightalias(::CuArray, ::CuArray): +# https://github.com/JuliaGPU/CUDA.jl/blob/main/CUDACore/src/array.jl#L113-L116 +# Keep shared-allocation dataids for conservative alias detection involving wrappers. +function Base.mightalias(A::JLArray, B::JLArray) + nA, nB = sizeof(A), sizeof(B) + (iszero(nA) || iszero(nB)) && return false + GC.@preserve A B begin + pA, pB = UInt(pointer(A)), UInt(pointer(B)) + return pA <= pB < pA + nA || pB <= pA < pB + nB + end +end + GPUArrays.dense_array_type(a::JLArray{T, N}) where {T, N} = JLArray{T, N} GPUArrays.dense_array_type(::Type{JLArray{T, N}}) where {T, N} = JLArray{T, N} GPUArrays.dense_vector_type(a::JLArray{T, N}) where {T, N} = JLArray{T, 1} diff --git a/test/testsuite.jl b/test/testsuite.jl index 6f8b49eb..86ccabff 100644 --- a/test/testsuite.jl +++ b/test/testsuite.jl @@ -125,6 +125,7 @@ end include("testsuite/construction.jl") include("testsuite/indexing.jl") include("testsuite/base.jl") +include("testsuite/aliasing.jl") include("testsuite/vector.jl") include("testsuite/reductions.jl") include("testsuite/sorting.jl") diff --git a/test/testsuite/aliasing.jl b/test/testsuite/aliasing.jl new file mode 100644 index 00000000..7b605441 --- /dev/null +++ b/test/testsuite/aliasing.jl @@ -0,0 +1,18 @@ +@testsuite "aliasing" (AT, eltypes)->begin + T = Float32 in eltypes ? Float32 : first(eltypes) + buffer = AT{T}(undef, 32) + left = view(buffer, 1:16) + right = view(buffer, 17:32) + overlap = view(buffer, 9:24) + @test Base.mightalias(left, left) + @test !Base.mightalias(left, right) + @test !Base.mightalias(right, left) + @test Base.mightalias(left, overlap) + @test Base.mightalias(overlap, left) + @test !Base.mightalias(left, copy(left)) + # The last element still overlaps after reinterpreting to a different element size. + @test Base.mightalias(reinterpret(UInt8, left), view(buffer, 16:16)) + empty = view(buffer, 9:8) + @test !Base.mightalias(empty, left) + @test !Base.mightalias(left, empty) +end