Skip to content

Support arrays of isbits unions - #735

Merged
maleadt merged 1 commit into
mainfrom
tb/isbits-unions
Oct 24, 2026
Merged

maleadt merged 1 commit into
mainfrom
tb/isbits-unions

Conversation

@maleadt

@maleadt maleadt commented Oct 23, 2026

Copy link
Copy Markdown
Member

oneArray rejected isbits-union element types (Union{Int,Nothing}, Union{Missing,Bool}, ...) with "oneArray does not yet support isbits-union arrays". This adds support, following the layout and design of JuliaGPU/AMDGPU.jl#1182 (see also JuliaGPU/AMDGPU.jl#1171).

Layout is the same as Array's: the data, aligned_sizeof(T) bytes per element, followed by one selector byte per element. The device side already had the union load/store code; what was missing is on the host:

  • maxsize locates an array's selector bytes. GPUArrays.derive advances it by the element offset, since the byte offset can't recover that for unions of singletons (Union{Nothing,Missing}), and kernels get maxsize - offset so that views use their own selector bytes.
  • Every copy path copies the selector bytes too: uploads, downloads, device-to-device, the host-pointer paths for shared and host memory, and resize!. Union uploads aren't staged (they synchronize instead), as the selector bytes would need a staged copy of their own.
  • Scalar indexing of host-accessible union arrays goes through a copy instead of unsafe_load; unsafe_wrap(Array, ...) rejects unions.
  • On the device, Const arrays (which AcceleratedKernels' reductions use) load unions through their selector byte, and structs with a union field no longer take the union path, which read a selector byte past the end of the array.
  • Element sizes use aligned_sizeof, which differs from sizeof for e.g. Union{Int64,NTuple{3,Int32}} (16 vs. 12 bytes). On Julia 1.10 it's wrapped in a @generated function, as Base.aligned_sizeof doesn't fold to a constant in device code there.

This also enables the union tests in GPUArrays' testsuite (reinterpret of a union array, any/all on Union{Missing,Bool}), which check for support at run time.

Not addressed: SPIRVIntrinsics' emit_localmemory sizes local memory as len * sizeof(T) plus the selector bytes, which is too small for oneLocalArrays of unions like Union{Int64,NTuple{3,Int32}} whose size isn't a multiple of their alignment.

oneArray rejected element types like `Union{Int,Nothing}` or
`Union{Missing,Bool}`, although the device side already knew how to load
and store them. Store them like `Array` does: the data, padded to
`aligned_sizeof` per element, followed by one selector byte per element.

`maxsize` locates an array's selector bytes. Derived arrays advance it by
their element offset, which the byte offset can't recover for unions of
singletons, so kernels on views of these arrays use the view's own
selector bytes. Every copy path (to and from the host, between device
arrays, and through host pointers into shared and host memory) and
`resize!` copy the selector bytes too; scalar indexing of host-accessible
arrays goes through such a copy, and `unsafe_wrap(Array, ...)` rejects
unions as an `Array` keeps its selector bytes elsewhere.

On the device, `Const` arrays (used by AcceleratedKernels' reductions)
load unions through their selector byte. Structs with a union field took
the union path too, reading a selector byte past the end of the array;
they keep their selector inside the element, and now load as plain bits.
@codecov

codecov Bot commented Oct 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.42857% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.60%. Comparing base (7020223) to head (262e6c9).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
src/array.jl 95.55% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #735      +/-   ##
==========================================
+ Coverage   85.08%   85.60%   +0.51%     
==========================================
  Files          53       52       -1     
  Lines        4660     4550     -110     
==========================================
- Hits         3965     3895      -70     
+ Misses        695      655      -40     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@maleadt
maleadt merged commit 40e5bd9 into main Oct 24, 2026
6 checks passed
@maleadt
maleadt deleted the tb/isbits-unions branch October 24, 2026 06:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

arrays The array abstraction: broadcasting, mapreduce, indexing, views, generic linear algebra.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant