From e25987577c94d16df3c37b4039a25ed400ec226c Mon Sep 17 00:00:00 2001 From: lkdvos Date: Mon, 5 Oct 2026 18:11:06 -0400 Subject: [PATCH 1/2] Delegate StridedView alias checks to dense parents --- src/stridedview.jl | 6 ++++++ test/aliasing.jl | 46 ++++++++++++++++++++++++++++++++++++++++++++++ test/runtests.jl | 1 + 3 files changed, 53 insertions(+) create mode 100644 test/aliasing.jl diff --git a/src/stridedview.jl b/src/stridedview.jl index b7e93c0..906b041 100644 --- a/src/stridedview.jl +++ b/src/stridedview.jl @@ -286,3 +286,9 @@ function Base.elsize(::Type{<:StridedView{T, N, A}}) where {T, N, A} return Base.elsize(A) end Base.dataids(a::StridedView) = Base.dataids(a.parent) + +# The parents may have a more precise alias check than their shared-storage dataids. +# Disjoint parents imply disjoint views; overlapping parents remain conservative. +function Base.mightalias(a::StridedView, b::StridedView) + return !isempty(a) && !isempty(b) && Base.mightalias(parent(a), parent(b)) +end diff --git a/test/aliasing.jl b/test/aliasing.jl new file mode 100644 index 0000000..f2137a0 --- /dev/null +++ b/test/aliasing.jl @@ -0,0 +1,46 @@ +using Test, StridedViews + +# A dense suballocation with conservative storage identities and a precise parent +# alias check, like JLArray and CuArray. This keeps the test independent of GPUs. +struct AliasTestArray <: DenseArray{Float64, 1} + data::Vector{Float64} + region::UnitRange{Int} +end +Base.size(A::AliasTestArray) = (length(A.region),) +Base.strides(::AliasTestArray) = (1,) +Base.IndexStyle(::Type{AliasTestArray}) = IndexLinear() +Base.getindex(A::AliasTestArray, i::Int) = A.data[A.region[i]] +Base.dataids(A::AliasTestArray) = Base.dataids(A.data) +Base.mightalias(A::AliasTestArray, B::AliasTestArray) = + A.data === B.data && !isdisjoint(A.region, B.region) + +@testset "StridedView alias detection" begin + data = zeros(16) + left = StridedView(AliasTestArray(data, 1:8)) + right = StridedView(AliasTestArray(data, 9:16)) + overlap = StridedView(AliasTestArray(data, 5:12)) + other = StridedView(AliasTestArray(copy(data), 1:8)) + @test Base.dataids(left) == Base.dataids(right) + @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(right, overlap) + @test !Base.mightalias(left, other) + @test !Base.mightalias(other, left) + @test !Base.mightalias(transpose(sreshape(left, (2, 4))), transpose(sreshape(right, (2, 4)))) + @test Base.mightalias(conj(left), overlap) + @test !Base.mightalias(sview(left, 1:2:8), right) + @test Base.mightalias(sview(left, 1:2:8), overlap) + @test !Base.mightalias(sview(left, 3:2), left) + @test !Base.mightalias(left, sview(left, 3:2)) + + # For ordinary arrays, preserve conservative overlap detection and the empty + # array behavior even when the normalized parent itself is nonempty. + ordinary = StridedView(data) + @test Base.mightalias(ordinary, sview(ordinary, 1:2:16)) + @test !Base.mightalias(ordinary, StridedView(copy(data))) + @test !Base.mightalias(sview(ordinary, 3:2), ordinary) + @test !Base.mightalias(ordinary, sview(ordinary, 3:2)) +end diff --git a/test/runtests.jl b/test/runtests.jl index 57c32a2..3fa043d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -11,6 +11,7 @@ Random.seed!(1234) is_buildkite = get(ENV, "BUILDKITE", "false") == "true" if !is_buildkite + include("aliasing.jl") @testset "construction of StridedView" begin @testset for T1 in (Float32, Float64, Complex{Float32}, Complex{Float64}) A1 = randn(T1, (60, 60)) From d911be1538659cef544ac7791b406b1d56081508 Mon Sep 17 00:00:00 2001 From: lkdvos Date: Mon, 5 Oct 2026 18:29:06 -0400 Subject: [PATCH 2/2] Simplify alias regressions to use JLArrays --- test/aliasing.jl | 46 ---------------------------------------------- test/runtests.jl | 15 ++++++++++++++- 2 files changed, 14 insertions(+), 47 deletions(-) delete mode 100644 test/aliasing.jl diff --git a/test/aliasing.jl b/test/aliasing.jl deleted file mode 100644 index f2137a0..0000000 --- a/test/aliasing.jl +++ /dev/null @@ -1,46 +0,0 @@ -using Test, StridedViews - -# A dense suballocation with conservative storage identities and a precise parent -# alias check, like JLArray and CuArray. This keeps the test independent of GPUs. -struct AliasTestArray <: DenseArray{Float64, 1} - data::Vector{Float64} - region::UnitRange{Int} -end -Base.size(A::AliasTestArray) = (length(A.region),) -Base.strides(::AliasTestArray) = (1,) -Base.IndexStyle(::Type{AliasTestArray}) = IndexLinear() -Base.getindex(A::AliasTestArray, i::Int) = A.data[A.region[i]] -Base.dataids(A::AliasTestArray) = Base.dataids(A.data) -Base.mightalias(A::AliasTestArray, B::AliasTestArray) = - A.data === B.data && !isdisjoint(A.region, B.region) - -@testset "StridedView alias detection" begin - data = zeros(16) - left = StridedView(AliasTestArray(data, 1:8)) - right = StridedView(AliasTestArray(data, 9:16)) - overlap = StridedView(AliasTestArray(data, 5:12)) - other = StridedView(AliasTestArray(copy(data), 1:8)) - @test Base.dataids(left) == Base.dataids(right) - @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(right, overlap) - @test !Base.mightalias(left, other) - @test !Base.mightalias(other, left) - @test !Base.mightalias(transpose(sreshape(left, (2, 4))), transpose(sreshape(right, (2, 4)))) - @test Base.mightalias(conj(left), overlap) - @test !Base.mightalias(sview(left, 1:2:8), right) - @test Base.mightalias(sview(left, 1:2:8), overlap) - @test !Base.mightalias(sview(left, 3:2), left) - @test !Base.mightalias(left, sview(left, 3:2)) - - # For ordinary arrays, preserve conservative overlap detection and the empty - # array behavior even when the normalized parent itself is nonempty. - ordinary = StridedView(data) - @test Base.mightalias(ordinary, sview(ordinary, 1:2:16)) - @test !Base.mightalias(ordinary, StridedView(copy(data))) - @test !Base.mightalias(sview(ordinary, 3:2), ordinary) - @test !Base.mightalias(ordinary, sview(ordinary, 3:2)) -end diff --git a/test/runtests.jl b/test/runtests.jl index 3fa043d..1f7aa8b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -11,7 +11,6 @@ Random.seed!(1234) is_buildkite = get(ENV, "BUILDKITE", "false") == "true" if !is_buildkite - include("aliasing.jl") @testset "construction of StridedView" begin @testset for T1 in (Float32, Float64, Complex{Float32}, Complex{Float64}) A1 = randn(T1, (60, 60)) @@ -293,6 +292,20 @@ if !is_buildkite end @testset "JLArrays with StridedView" begin + @testset "alias detection" begin + buffer = JLArray{Float32}(undef, 16) + left = view(buffer, 1:8) + right = view(buffer, 9:16) + overlap = view(buffer, 5:12) + # Preserve the parents' alias check, including byte-range specializations. + for other in (left, right, overlap) + @test Base.mightalias(StridedView(left), StridedView(other)) == + Base.mightalias(left, other) + end + empty = sview(StridedView(left), 3:2) + @test !Base.mightalias(empty, StridedView(left)) + @test !Base.mightalias(StridedView(left), empty) + end @testset for T in (Float64, ComplexF64) Araw = randn(T, 10, 10, 10, 10) A = JLArray(Araw)