From 673c02d25f564edfc020df9cd0b46b008e783c62 Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Fri, 25 Sep 2026 15:54:28 +0200 Subject: [PATCH 1/4] CI: select steps with list-based tags, and test less on drafts Adopt GPUCompiler's commit message grammar, where `[only ...]` and `[skip ...]` take a comma-separated list of step tags, e.g. `[only nightly]` or `[skip special]`. To save CI time, draft pull requests only test the newest Julia release and nightly; older releases and the validation run once the pull request is marked ready. Co-Authored-By: Claude Opus 5.5 --- .buildkite/pipeline.yml | 44 ++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 9db467c8..7cd9f046 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -1,9 +1,16 @@ +# Commit message tags select what to run: `[only X]` runs only the listed steps, `[skip X]` +# skips them, where X is a comma-separated list of: `tests` (all steps), `julia` (released +# Julia versions), `nightly`, `special`. Draft pull requests only test the newest Julia +# release and nightly, unless steps are selected explicitly. See also GPUCompiler.jl's CI, +# which uses the same tags. steps: # Test supported Julia versions - group: ":julia: Julia" key: "julia" steps: - - label: "Julia {{matrix.julia}}" + # the newest release, also tested on draft pull requests + - &julia + label: "Julia {{matrix.julia}}" plugins: - JuliaCI/julia#v1: version: "{{matrix.julia}}" @@ -18,20 +25,37 @@ steps: queue: "oneapi" commands: | julia --project=deps deps/build_ci.jl - if: build.message !~ /\[skip tests\]/ + if: | + build.message !~ /\[skip [^\]]*(tests|julia)/ && + (build.message =~ /\[only [^\]]*(tests|julia)/ || build.message !~ /\[only /) timeout_in_minutes: 120 + matrix: + setup: + julia: + - "1.13" + + # older releases + - <<: *julia + if: | + build.message !~ /\[skip [^\]]*(tests|julia)/ && + (build.message =~ /\[only [^\]]*(tests|julia)/ || + build.message !~ /\[only / && !build.pull_request.draft) matrix: setup: julia: - "1.10" - "1.11" - "1.12" - - "1.13" + + - <<: *julia + if: | + build.message !~ /\[skip [^\]]*(tests|nightly)/ && + (build.message =~ /\[only [^\]]*(tests|nightly)/ || build.message !~ /\[only /) + soft_fail: true + matrix: + setup: + julia: - "nightly" - adjustments: - - with: - julia: "nightly" - soft_fail: true # Special tests - group: ":eyes: Special" @@ -55,14 +79,16 @@ steps: # use debug JLLs, for asserts + better backtraces using oneAPI oneAPI.set_debug!(true)' - if: build.message !~ /\[skip tests\]/ env: ZE_ENABLE_VALIDATION_LAYER: '1' ZE_ENABLE_PARAMETER_VALIDATION: '1' EnableDebugBreak: '0' agents: queue: "oneapi" - if: build.message !~ /\[skip tests\]/ && !build.pull_request.draft + if: | + build.message !~ /\[skip [^\]]*(tests|special)/ && + (build.message =~ /\[only [^\]]*(tests|special)/ || + build.message !~ /\[only / && !build.pull_request.draft) timeout_in_minutes: 60 soft_fail: true From 03f9ba0e64cba57569e67d30e6936030d184623a Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Fri, 25 Sep 2026 15:54:18 +0200 Subject: [PATCH 2/4] Override _throw_boundserror_indices on Julia 1.14 Julia 1.14 reports bounds errors from the generic `checkbounds`, as used e.g. when indexing views, through `Base._throw_boundserror_indices` (JuliaLang/julia#61561), bypassing the `throw_boundserror` override. Mirror the override Metal.jl already has. Co-Authored-By: Claude Opus 5.5 --- src/device/quirks.jl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/device/quirks.jl b/src/device/quirks.jl index cbd4c520..942fd1a3 100644 --- a/src/device/quirks.jl +++ b/src/device/quirks.jl @@ -31,6 +31,14 @@ end # abstractarray.jl @device_override @noinline Base.throw_boundserror(A, I) = @gputhrow "BoundsError" "Out-of-bounds array access" +# 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) = From d731de6c5603b5932b704e25102ad37b522bdbdd Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Fri, 25 Sep 2026 16:07:06 +0200 Subject: [PATCH 3/4] Fix broadcasting types on Julia 1.14 Julia 1.14 specializes type-valued arguments on `Core.TypeEgal{T}` (JuliaLang/julia#62001), so a broadcast of a type constructor has `TypeEgal{T}` as its function type parameter. That isn't matched by the `Type{T}` in our adaptor rule, which replaces the non-isbits type with a closure, making such broadcasts fail to compile. Match any subtype of `Type{T}` instead. Co-Authored-By: Claude Opus 5.5 --- src/compiler/execution.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/compiler/execution.jl b/src/compiler/execution.jl index 6c9bf86a..e0185071 100644 --- a/src/compiler/execution.jl +++ b/src/compiler/execution.jl @@ -156,8 +156,9 @@ Adapt.adapt_structure(to::KernelAdaptor, r::Base.RefValue{<:Union{DataType,Type} oneRefType{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}}) where {Style, T} = + bc::Broadcast.Broadcasted{Style, <:Any, <:Type{T}}) where {Style, T} = Broadcast.Broadcasted{Style}((x...) -> T(x...), adapt(to, bc.args), bc.axes) """ From b5533fddbdc1aa08aa6a8403016c89845350362a Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Fri, 25 Sep 2026 16:39:08 +0200 Subject: [PATCH 4/4] Convert functions that capture a type for use in kernels LinearAlgebra's `det` of triangular matrices now reduces with `Base.Fix1(convert, T)`, which isn't isbits (JuliaLang/LinearAlgebra.jl#1658). Convert `Fix1` and `Fix2` capturing a type into closures that carry the type as a parameter instead, like we already do for broadcasting types. Co-Authored-By: Claude Opus 5.5 --- src/compiler/execution.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/compiler/execution.jl b/src/compiler/execution.jl index e0185071..20742c2d 100644 --- a/src/compiler/execution.jl +++ b/src/compiler/execution.jl @@ -161,6 +161,13 @@ Adapt.adapt_structure(to::KernelAdaptor, 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 +Adapt.adapt_structure(to::KernelAdaptor, f::Base.Fix1{<:Any, <:Type{T}}) where {T} = + let g = adapt(to, f.f); (x...) -> g(T, x...) end +Adapt.adapt_structure(to::KernelAdaptor, f::Base.Fix2{<:Any, <:Type{T}}) where {T} = + let g = adapt(to, f.f); (x...) -> g(x..., T) end + """ kernel_convert(x)