Skip to content

POCL: support BFloat16 kernels when PoCL accepts SPV_KHR_bfloat16 - #946

Merged
maleadt merged 2 commits into
mainfrom
tb/pocl-bfloat16
Nov 3, 2026
Merged

maleadt merged 2 commits into
mainfrom
tb/pocl-bfloat16

Conversation

@maleadt

@maleadt maleadt commented Nov 3, 2026 •

Copy link
Copy Markdown
Member

On Julia 1.11+, BFloat16 is Core.BFloat16, which Julia lowers to LLVM's bfloat. The POCL back end never set GPUCompiler's supports_bfloat16, so every kernel touching a BFloat16 array, even a copy, failed with InvalidIRError: unsupported use of bfloat value (#921).

This queries the device's SPIR-V extensions (CL_DEVICE_SPIRV_EXTENSIONS_KHR, from cl_khr_spirv_queries) and, when PoCL lists SPV_KHR_bfloat16, enables that extension and supports_bfloat16. The pieces this relies on:

Tests cover #921's copy kernel, arithmetic and conversions from Float32/Float64/Int32/Int64/UInt64, checked against correctly rounded references. The references are computed in Float32 (arithmetic) and BigFloat (conversions) rather than with the host's BFloat16 operations: on Julia 1.11, vectorized BFloat16 code on the host either crashes LLVM (Cannot select ... X86ISD::VFPROUND on AVX512-BF16 CPUs) or, for copysign, gives wrong results. On Julia 1.10, BFloat16 is still BFloat16s.jl's 16-bit primitive type and the tests pass as before.

Closes #921

On Julia 1.11+, `BFloat16` is `Core.BFloat16`, which lowers to LLVM's `bfloat`, so any
kernel touching a `BFloat16` array failed GPUCompiler's validation. Query the device's
SPIR-V extensions (cl_khr_spirv_queries) and, when PoCL lists SPV_KHR_bfloat16 (from
pocl_standalone_jll 7.2.3+3), enable it together with GPUCompiler's `supports_bfloat16`.
Arithmetic is widened to `float` by GPUCompiler 2.20; older PoCL builds keep failing
cleanly with an `InvalidIRError`.

Closes #921.
@github-actions

github-actions Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Benchmark results

Compared with c10ff8cf4, the merge base.
The environment differs from the baseline's: GPUCompiler 2.18.0 → 2.20.0, JSON 1.13.0 → 1.13.4, LLVM 10.4.2 → 10.4.3, Parsers 3.0.3 → 3.0.5, SPIRVIntrinsics 1.5.1 → 1.6.0, SPIRV_LLVM_Backend_jll 23.1.1+8 → 23.1.4+0, StructUtils 2.11.2 → 2.12.0, StructUtilsStaticArraysCoreExt 2.11.2 → 2.12.0, pocl_standalone_jll 7.2.3+2 → 7.2.3+3.

Times are the minimum time of every benchmark. A change is unusual when it exceeds both three times the benchmark's typical change between consecutive runs on the default branch and a minimum per category (performance 3%, latency 5%, applications 3%, other 3%). A benchmark that starts or stops allocating is listed however few the allocations. A single run can still be a fluke, so rerun before drawing conclusions.

Geometric mean Unusual: slower Unusual: faster Compared
Performance +0.2% 0 0 32
Latency −3.6% 0 0 13
Applications −9.0% 0 0 5

No unusual changes.

All benchmarks
Benchmark Baseline This PR Change
Performance
julia/serial/arithmetic/muladd-reference 655 µs 655 µs +0.0% noise unknown
julia/serial/math/exp-f64-reference 290 µs 284 µs −2.0% noise unknown
julia/serial/narrow/masked-reference 689 µs 708 µs +2.8% noise unknown
pocl/parallel/atomics/histogram 5.13 ms 5.15 ms +0.2% noise unknown
pocl/parallel/groupreduce/add-f64 1.65 ms 1.65 ms +0.0% noise unknown
pocl/parallel/groupreduce/fallback 18.1 ms 18.8 ms +4.0% noise unknown
pocl/parallel/groupscan/add-i32 2.50 ms 2.52 ms +0.5% noise unknown
pocl/parallel/indexing/cartesian3d 73.7 µs 80.9 µs +9.8% noise unknown
pocl/parallel/indexing/linear3d 81.0 µs 79.3 µs −2.2% noise unknown
pocl/parallel/indexing/ntuple3d 80.7 µs 87.5 µs +8.4% noise unknown
pocl/parallel/indexing/ntuple4d 162 µs 166 µs +2.6% noise unknown
pocl/parallel/localmem/transpose-naive 455 µs 459 µs +0.9% noise unknown
pocl/parallel/localmem/transpose-tiled 125 µs 109 µs −12.7% noise unknown
pocl/parallel/private/across-barrier 164 µs 165 µs +0.7% noise unknown
pocl/parallel/scheduling/default 185 µs 181 µs −1.9% noise unknown
pocl/parallel/scheduling/explicit 181 µs 181 µs −0.2% noise unknown
pocl/parallel/stream/copy/cache 786 ns 662 ns −15.8% noise unknown
pocl/parallel/stream/copy/dram 6.16 ms 6.40 ms +4.0% noise unknown
pocl/parallel/stream/triad/cache 6.84 µs 6.83 µs −0.1% noise unknown
pocl/parallel/stream/triad/dram 9.34 ms 9.45 ms +1.3% noise unknown
pocl/parallel/util/copyto-small 24.0 ns 24.0 ns +0.0% noise unknown
pocl/parallel/util/zeros-large 995 µs 1.01 ms +1.5% noise unknown
pocl/parallel/util/zeros-small 651 ns 635 ns −2.5% noise unknown
pocl/serial/arithmetic/contract 1.91 ms 1.90 ms −0.3% noise unknown
pocl/serial/arithmetic/muladd 764 µs 767 µs +0.4% noise unknown
pocl/serial/const/marked 722 µs 735 µs +1.8% noise unknown
pocl/serial/const/unmarked 922 µs 914 µs −0.9% noise unknown
pocl/serial/math/exp-f64 146 µs 152 µs +4.6% noise unknown
pocl/serial/math/sin-f64 186 µs 190 µs +2.1% noise unknown
pocl/serial/narrow/masked 824 µs 826 µs +0.1% noise unknown
pocl/serial/narrow/unmasked 789 µs 790 µs +0.1% noise unknown
pocl/serial/stream/triad/dram 8.59 ms 8.70 ms +1.3% noise unknown
Latency
host/import/ka 509 ms 505 ms −0.7% noise unknown
host/precompile/ka 44.6 s 44.8 s +0.3% noise unknown
host/startup 132 ms 130 ms −1.9% noise unknown
pocl/parallel/launch/dynamic-default 4.30 µs 4.42 µs +2.9% noise unknown
pocl/parallel/launch/groupreduce-f64 5.03 µs 6.58 µs +30.7% noise unknown
pocl/parallel/launch/many-args 12.4 µs 12.1 µs −2.0% noise unknown
pocl/parallel/launch/partial-workgroup 4.19 µs 3.75 µs −10.4% noise unknown
pocl/serial/compile/groupreduce 1.88 s 1.40 s −25.4% noise unknown
pocl/serial/compile/localmem-barrier 719 ms 694 ms −3.5% noise unknown
pocl/serial/compile/new-kernel 110 ms 118 ms +7.4% noise unknown
pocl/serial/compile/new-workgroupsize 13.6 ms 13.9 ms +2.7% noise unknown
pocl/serial/first-kernel/cold-cache 2.05 s 1.94 s −5.5% noise unknown
pocl/serial/first-kernel/warm-cache 392 ms 279 ms −28.7% noise unknown
Applications
pocl/parallel/dgsem/fluxdiff-node 291 µs 285 µs −2.1% noise unknown
pocl/parallel/dgsem/weak-element 203 µs 159 µs −21.9% noise unknown
pocl/parallel/dgsem/weak-node-localmem 148 µs 117 µs −20.4% noise unknown
pocl/parallel/stencil/timestep 7.80 ms 7.86 ms +0.8% noise unknown
pocl/serial/stencil/timestep 11.1 ms 11.3 ms +1.4% noise unknown

History: https://juliagpu.org/perf/?pkg=kernelabstractions

BFloat16s.jl 0.6.4 rounds them correctly; the reason left is that vectorized ones crash
LLVM on Julia 1.11 on AVX512-BF16 hosts.
@maleadt
maleadt merged commit 89d5916 into main Nov 3, 2026
19 of 20 checks passed
@maleadt
maleadt deleted the tb/pocl-bfloat16 branch November 3, 2026 20:43
@codecov

codecov Bot commented Nov 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 82.83%. Comparing base (c10ff8c) to head (2399b1b).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #946      +/-   ##
==========================================
- Coverage   83.46%   82.83%   -0.64%     
==========================================
  Files          31       31              
  Lines        2571     2534      -37     
==========================================
- Hits         2146     2099      -47     
- Misses        425      435      +10     

☔ 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

POCL backend: kernels on BFloat16 arrays fail with "unsupported use of bfloat value"

1 participant