Since JLArrays v0.3.2, any * / mul! involving a strided SubArray of a JLArray with a BLAS-eligible eltype errors. MWE on Julia 1.12.6, JLArrays v0.3.2:
using JLArrays, LinearAlgebra
JLArrays.allowscalar(false)
A = JLArray(randn(4, 3))
B = JLArray(randn(4, 5))
view(A, 1:2, :)' * view(B, 1:2, :)
# ERROR: Illegal conversion of a JLArray to a Ptr
# Stacktrace: ... gemm!(...) @ LinearAlgebra.BLAS
The same happens for dense' * view, view' * dense, view' * vector, and mul! with any strided-view operand. On JLArrays v0.3.1 all of these "worked".
What changed
SubArrays of a JLArray with contiguous-ish indices belong to Base's StridedArray union (since AbstractGPUArray <: DenseArray), so for BLAS eltypes LinearAlgebra routes these products to BLAS gemm!/gemv!, which calls unsafe_convert(::Type{Ptr}, ...):
- On v0.3.1,
Base.unsafe_convert(Ptr{T}, ::JLArray) silently returned a pointer into the host-backed buffer, so the products ran CPU BLAS on the emulation array — numerically correct, but exactly the implicit CPU ccall that JLArrays is meant to catch.
- On v0.3.2, the new guard (
error("Illegal conversion of a JLArray to a Ptr"), added alongside the "Pointer access is only available for callers that explicitly want a pointer" change) correctly rejects the conversion — but nothing intercepts the strided-BLAS dispatch before it gets there, so the products now throw.
Non-BLAS eltypes are no better off: view(Ai, 1:2, :)' * view(Bi, 1:2, :) with Int8 falls through to Base's generic matmul and dies with "Scalar indexing is disallowed" under allowscalar(false). So as of 0.3.2, strided views of JLArrays are effectively not multipliable at all.
Why this matters
JLArrays is the reference backend used downstream to emulate CUDA semantics in CPU CI. On real CUDA, view(A, 1:2, :)' * view(B, 1:2, :) works (CUBLAS supports strided device views), so the emulator now rejects code that is fine on the backend it emulates. Downstream example: JuliaGPU-style CI in cossio/RestrictedBoltzmannMachines.jl went red on the JLArrays 0.3.1 → 0.3.2 bump with unchanged code (fixed there by materializing the views: cossio/RestrictedBoltzmannMachines.jl#206).
To be clear, the 0.3.2 pointer guard itself looks like the right call — it exposed a real emulation gap that 0.3.1 was silently papering over with host BLAS.
Suggestion
Would it make sense for GPUArrays/JLArrays to provide LinearAlgebra.generic_matmatmul!/mul! coverage for strided SubArrays (and Adjoint/Transpose thereof) of AbstractGPUArray, routing them to the existing generic GPU matmul kernels, so wrapped views keep working and JLArray matches CuArray behavior? Alternatively, if erroring is the intended semantics for view products on JLArray, a targeted error ("matrix products with views of JLArrays are not supported; materialize with copy/getindex") would be much easier to act on than the Ptr guard firing deep inside BLAS.
Since JLArrays v0.3.2, any
*/mul!involving a stridedSubArrayof aJLArraywith a BLAS-eligible eltype errors. MWE on Julia 1.12.6, JLArrays v0.3.2:The same happens for
dense' * view,view' * dense,view' * vector, andmul!with any strided-view operand. On JLArrays v0.3.1 all of these "worked".What changed
SubArrays of aJLArraywith contiguous-ish indices belong to Base'sStridedArrayunion (sinceAbstractGPUArray <: DenseArray), so for BLAS eltypes LinearAlgebra routes these products to BLASgemm!/gemv!, which callsunsafe_convert(::Type{Ptr}, ...):Base.unsafe_convert(Ptr{T}, ::JLArray)silently returned a pointer into the host-backed buffer, so the products ran CPU BLAS on the emulation array — numerically correct, but exactly the implicit CPUccallthat JLArrays is meant to catch.error("Illegal conversion of a JLArray to a Ptr"), added alongside the "Pointer access is only available for callers that explicitly want a pointer" change) correctly rejects the conversion — but nothing intercepts the strided-BLAS dispatch before it gets there, so the products now throw.Non-BLAS eltypes are no better off:
view(Ai, 1:2, :)' * view(Bi, 1:2, :)withInt8falls through to Base's generic matmul and dies with "Scalar indexing is disallowed" underallowscalar(false). So as of 0.3.2, strided views of JLArrays are effectively not multipliable at all.Why this matters
JLArrays is the reference backend used downstream to emulate CUDA semantics in CPU CI. On real CUDA,
view(A, 1:2, :)' * view(B, 1:2, :)works (CUBLAS supports strided device views), so the emulator now rejects code that is fine on the backend it emulates. Downstream example: JuliaGPU-style CI in cossio/RestrictedBoltzmannMachines.jl went red on the JLArrays 0.3.1 → 0.3.2 bump with unchanged code (fixed there by materializing the views: cossio/RestrictedBoltzmannMachines.jl#206).To be clear, the 0.3.2 pointer guard itself looks like the right call — it exposed a real emulation gap that 0.3.1 was silently papering over with host BLAS.
Suggestion
Would it make sense for GPUArrays/JLArrays to provide
LinearAlgebra.generic_matmatmul!/mul!coverage for stridedSubArrays (andAdjoint/Transposethereof) ofAbstractGPUArray, routing them to the existing generic GPU matmul kernels, so wrapped views keep working and JLArray matches CuArray behavior? Alternatively, if erroring is the intended semantics for view products on JLArray, a targeted error ("matrix products with views of JLArrays are not supported; materialize withcopy/getindex") would be much easier to act on than thePtrguard firing deep inside BLAS.