diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 9f2a95828..2211c1bee 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -1,3 +1,7 @@ +# Tests of the KernelAbstractions-related parts of the GPU back-ends. Draft pull requests skip +# them, unless selected by name in the last commit message: `[only cuda]`, `[only metal, oneapi]` +# or `[only tests]` for all of them. `[skip amdgpu]` or `[skip tests]` does the opposite. +# (`opencl` selects the OpenCL.jl tests on CUDA hardware.) steps: - label: "CUDA Julia {{matrix.version}}" matrix: @@ -29,6 +33,10 @@ steps: Pkg.test("CUDA"; coverage=true, test_args=["core/kernelabstractions", "core/kernelinterface"])' agents: queue: "cuda" + if: | + build.message !~ /\[skip [^\]]*(tests|cuda)/ && + (build.message =~ /\[only [^\]]*(tests|cuda)/ || + build.message !~ /\[only / && !build.pull_request.draft) timeout_in_minutes: 120 soft_fail: - exit_status: 3 @@ -92,6 +100,10 @@ steps: Pkg.test("Metal"; coverage=true, test_args=["kernelabstractions", "kernelinterface"])' agents: queue: "metal" + if: | + build.message !~ /\[skip [^\]]*(tests|metal)/ && + (build.message =~ /\[only [^\]]*(tests|metal)/ || + build.message !~ /\[only / && !build.pull_request.draft) timeout_in_minutes: 120 soft_fail: - exit_status: 3 @@ -126,6 +138,10 @@ steps: Pkg.test("oneAPI"; coverage=true, test_args=["kernelabstractions", "kernelinterface"])' agents: queue: "oneapi" + if: | + build.message !~ /\[skip [^\]]*(tests|oneapi)/ && + (build.message =~ /\[only [^\]]*(tests|oneapi)/ || + build.message !~ /\[only / && !build.pull_request.draft) timeout_in_minutes: 120 soft_fail: - exit_status: 3 @@ -161,6 +177,10 @@ steps: Pkg.test("AMDGPU"; coverage=true, test_args=["kernelabstractions", "kernelinterface"])' agents: queue: "rocm" + if: | + build.message !~ /\[skip [^\]]*(tests|amdgpu)/ && + (build.message =~ /\[only [^\]]*(tests|amdgpu)/ || + build.message !~ /\[only / && !build.pull_request.draft) timeout_in_minutes: 120 soft_fail: - exit_status: 3 @@ -196,6 +216,10 @@ steps: Pkg.test("OpenCL"; coverage=true, test_args=`--platform=nvidia nvidia/kernelabstractions nvidia/kernelinterface`)' agents: queue: "cuda" + if: | + build.message !~ /\[skip [^\]]*(tests|opencl)/ && + (build.message =~ /\[only [^\]]*(tests|opencl)/ || + build.message !~ /\[only / && !build.pull_request.draft) timeout_in_minutes: 120 soft_fail: - exit_status: 3 diff --git a/src/pocl/compiler/execution.jl b/src/pocl/compiler/execution.jl index 4bee8ba72..7e0e20de2 100644 --- a/src/pocl/compiler/execution.jl +++ b/src/pocl/compiler/execution.jl @@ -118,12 +118,24 @@ Adapt.adapt_structure(to::KernelAdaptor, r::Base.RefValue{<:Union{DataType, Type CLRefType{r[]}() # case where type is the function being broadcasted +# (on Julia 1.14, the function type parameter is `Core.TypeEgal{T} <: Type{T}`) Adapt.adapt_structure( to::KernelAdaptor, - bc::Broadcast.Broadcasted{Style, <:Any, Type{T}} + bc::Broadcast.Broadcasted{Style, <:Any, <:Type{T}} ) where {Style, T} = Broadcast.Broadcasted{Style}((x...) -> T(x...), adapt(to, bc.args), bc.axes) +# functions that capture a type, e.g., `Base.Fix1(convert, T)` as used by LinearAlgebra, +# which isn't a valid kernel argument either +function Adapt.adapt_structure(to::KernelAdaptor, f::Base.Fix1{<:Any, <:Type{T}}) where {T} + g = adapt(to, f.f) + return (x...) -> g(T, x...) +end +function Adapt.adapt_structure(to::KernelAdaptor, f::Base.Fix2{<:Any, <:Type{T}}) where {T} + g = adapt(to, f.f) + return (x...) -> g(x..., T) +end + """ clconvert(x, [pointers]) diff --git a/src/pocl/device/quirks.jl b/src/pocl/device/quirks.jl index 035bcffb0..70c4e3397 100644 --- a/src/pocl/device/quirks.jl +++ b/src/pocl/device/quirks.jl @@ -32,6 +32,16 @@ end @device_override @noinline Base.throw_boundserror(A, I) = @gputhrow "BoundsError" "Out-of-bounds array access" +# essentials.jl +# Julia 1.14 routes indexed bounds errors through `_throw_boundserror_indices` +# rather than `throw_boundserror`, bypassing the override above. +@static if isdefined(Base, :_throw_boundserror_indices) + @device_override @noinline Base._throw_boundserror_indices(A) = + @gputhrow "BoundsError" "Out-of-bounds array access" + @device_override @noinline Base._throw_boundserror_indices(A, i1, I...) = + @gputhrow "BoundsError" "Out-of-bounds array access" +end + # trig.jl @device_override @noinline Base.Math.sincos_domain_error(x) = @gputhrow "DomainError" "sincos(x) is only defined for finite x" diff --git a/src/pocl/device/random.jl b/src/pocl/device/random.jl index d931232dc..4360b25f9 100644 --- a/src/pocl/device/random.jl +++ b/src/pocl/device/random.jl @@ -232,11 +232,16 @@ end end end +# Signature of Random's generic `AbstractFloat` fallbacks. Kept as a constant because +# spelling it inline (e.g. with `@invoke`) constructs the `UnionAll` at run time, which +# inference no longer folds away as of Julia 1.14 (JuliaLang/julia#62001). +const AbstractFloatFallback = Tuple{AbstractRNG, Type{<:AbstractFloat}} + # Use the table-free fallback, but compute it in Float32 because its polar transform can # overflow in Float16. Keep this scoped to our RNG: overlay methods take precedence over # regular dispatch and an AbstractRNG method would shadow methods for other device RNGs. @device_override @inline function Random.randn(rng::Philox2x32, ::Type{T}) where {T <: Union{Float16, Float32}} - return T(@invoke Random.randn(rng::AbstractRNG, Float32::Type{<:AbstractFloat})) + return T(invoke(Random.randn, AbstractFloatFallback, rng, Float32)) end ## randexp @@ -262,10 +267,13 @@ end # Compute through Float32 to avoid requiring Float16 `log1p` support. @device_override @inline function Random.randexp(rng::Philox2x32, ::Type{T}) where {T <: Union{Float16, Float32}} - return T(@invoke Random.randexp(rng::AbstractRNG, Float32::Type{<:AbstractFloat})) + return T(invoke(Random.randexp, AbstractFloatFallback, rng, Float32)) end -@device_override Random.Sampler( +# NOTE: not a consistent overlay (as SPIRVIntrinsics' `@device_override` may define), as +# this returns a different sampler than the host method: concrete evaluation would +# otherwise substitute the latter, which our overlaid `rand` methods fail to handle. +Base.Experimental.@overlay method_table Random.Sampler( ::Type{<:AbstractRNG}, r::AbstractUnitRange{T}, ::Random.Repetition ) where {T <: Union{Int64, UInt64}} = Random.SamplerRangeFast(r)