Skip to content

Test BFloat16 arithmetic against exactly rounded references - #952

Merged
maleadt merged 1 commit into
mainfrom
tb/bf16-exact-references
Nov 6, 2026
Merged

maleadt merged 1 commit into
mainfrom
tb/bf16-exact-references

Conversation

@maleadt

@maleadt maleadt commented Nov 5, 2026

Copy link
Copy Markdown
Member

Part of #949. The BFloat16 tests fail on AArch64 when compiling for a target without BF16, as on Apple M2 and M5 (whose CPUs have it, but Julia targets apple-m1 there, and PoCL apparently a similar model) and on a Neoverse-N1, for two reasons. LLVM 19 to 22 round <8 x bfloat> fadd/fsub/fmul/fdiv wrongly there: the round_v4fp32_to_v4bf16 pattern in AArch64InstrInfo.td takes the round-to-even bit from an operand rather than from the result, so ties can round the wrong way. LLVM 23 removed those patterns (llvm/llvm-project#190164). That bug affects both sides of the test:

  • The device: PoCL in pocl_standalone_jll uses LLVM 22. The fix is to build it with LLVM 23; a Yggdrasil change moving the experimental pocl_standalone_next to LLVM 23 is ready, to try that first.
  • The references: the test rounded them with the host's BFloat16 conversion inside a vectorizable map, which Julia 1.13 (LLVM 20) miscompiles in the same way. On a Neoverse-N1, the device results from an LLVM 23 PoCL were exact, but 21 of 4096 references were not.

This PR fixes the references. It computes them with bf16_nearest, as the conversion tests already do. bf16_nearest itself double-rounded subnormal results, since it kept 8 significant bits, which bfloat16 subnormals don't have. It now rounds those to multiples of 2^-133. It matches an integer round-to-nearest-even on all Float32 inputs checked, including every subnormal tie.

Results, Julia 1.13, 5 runs each:

pocl_standalone_jll (LLVM 22) pocl_standalone_next (LLVM 23, local build)
x86_64 (Ryzen 9 9950X) pass pass
aarch64 (Neoverse-N1, no BF16) fail (device) pass

So on such CPUs the test still fails with the current JLL, now only because of the device, until pocl_standalone moves to LLVM 23. The full test suite passes on x86_64 with both libraries on Julia 1.13, and with the current one on Julia 1.10.

The arithmetic tests rounded their references with the host's `BFloat16`
conversion inside a vectorizable `map`. LLVM 19 to 22 (Julia 1.13)
miscompiles that for AArch64 targets without BF16: an `<8 x bfloat>`
operation takes its round-to-even bit from an operand rather than the
result, so some ties round the wrong way. Round them with `bf16_nearest`
instead, as the conversion tests already do.

`bf16_nearest` kept 8 significant bits, which is too many for bfloat16
subnormals, so subnormal quotients were rounded twice. Round those to
multiples of 2^-133.

PoCL's LLVM 22 has the same bug on the device side, so the tests still
fail on such targets with the current pocl_standalone_jll (#949).
@maleadt maleadt added upstream Root cause lies in Julia, LLVM, a vendor, or another package. pocl The PoCL-based CPU back-end. labels Nov 5, 2026
@github-actions

github-actions Bot commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

Benchmark results

Compared with a13691a5b, the merge base.
The environment differs from the baseline's: SPIRV_LLVM_Backend_jll 23.1.4+0 → 23.1.4+1.

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 −1.0% 1 2 32
Latency +1.8% 1 0 13
Applications −15.2% 0 2 5
Benchmark Baseline This PR Change
Performance
pocl/parallel/groupscan/add-i32 299 µs 432 µs +44.5% 🔴 slower
pocl/parallel/private/across-barrier 84.0 µs 60.6 µs −27.8% 🟢 faster
pocl/parallel/scheduling/explicit 181 µs 140 µs −22.6% 🟢 faster
Latency
pocl/parallel/launch/groupreduce-f64 5.60 µs 6.48 µs +15.7% 🔴 slower
Applications
pocl/parallel/dgsem/fluxdiff-node 445 µs 295 µs −33.7% 🟢 faster
pocl/serial/stencil/timestep 12.2 ms 11.0 ms −9.7% 🟢 faster
All benchmarks
Benchmark Baseline This PR Change
Performance
julia/serial/arithmetic/muladd-reference 655 µs 655 µs −0.0%
julia/serial/math/exp-f64-reference 284 µs 299 µs +5.2%
julia/serial/narrow/masked-reference 707 µs 700 µs −1.0%
pocl/parallel/atomics/histogram 5.14 ms 5.16 ms +0.3%
pocl/parallel/groupreduce/add-f64 1.17 ms 1.17 ms −0.1%
pocl/parallel/groupreduce/fallback 4.42 ms 4.42 ms +0.0%
pocl/parallel/groupscan/add-i32 299 µs 432 µs +44.5% 🔴 slower
pocl/parallel/indexing/cartesian3d 80.4 µs 83.0 µs +3.3%
pocl/parallel/indexing/linear3d 79.7 µs 82.2 µs +3.2%
pocl/parallel/indexing/ntuple3d 79.8 µs 82.6 µs +3.5%
pocl/parallel/indexing/ntuple4d 163 µs 163 µs −0.2%
pocl/parallel/localmem/transpose-naive 458 µs 453 µs −1.0%
pocl/parallel/localmem/transpose-tiled 110 µs 103 µs −6.2%
pocl/parallel/private/across-barrier 84.0 µs 60.6 µs −27.8% 🟢 faster
pocl/parallel/scheduling/default 181 µs 182 µs +0.2%
pocl/parallel/scheduling/explicit 181 µs 140 µs −22.6% 🟢 faster
pocl/parallel/stream/copy/cache 662 ns 669 ns +1.1%
pocl/parallel/stream/copy/dram 6.34 ms 6.49 ms +2.4%
pocl/parallel/stream/triad/cache 7.62 µs 6.90 µs −9.5%
pocl/parallel/stream/triad/dram 9.44 ms 9.38 ms −0.6%
pocl/parallel/util/copyto-small 26.0 ns 24.0 ns −7.7%
pocl/parallel/util/zeros-large 1.01 ms 1.01 ms −0.2%
pocl/parallel/util/zeros-small 653 ns 650 ns −0.5%
pocl/serial/arithmetic/contract 1.91 ms 1.91 ms −0.1%
pocl/serial/arithmetic/muladd 752 µs 759 µs +0.9%
pocl/serial/const/marked 730 µs 709 µs −2.8%
pocl/serial/const/unmarked 918 µs 911 µs −0.7%
pocl/serial/math/exp-f64 140 µs 137 µs −1.6%
pocl/serial/math/sin-f64 196 µs 200 µs +2.3%
pocl/serial/narrow/masked 778 µs 797 µs +2.4%
pocl/serial/narrow/unmasked 783 µs 777 µs −0.8%
pocl/serial/stream/triad/dram 8.74 ms 8.58 ms −1.8%
Latency
host/import/ka 503 ms 504 ms +0.4%
host/precompile/ka 39.8 s 39.8 s −0.2%
host/startup 132 ms 131 ms −0.7%
pocl/parallel/launch/dynamic-default 4.26 µs 4.40 µs +3.4%
pocl/parallel/launch/groupreduce-f64 5.60 µs 6.48 µs +15.7% 🔴 slower
pocl/parallel/launch/many-args 12.3 µs 12.6 µs +2.6%
pocl/parallel/launch/partial-workgroup 4.05 µs 4.25 µs +5.0%
pocl/serial/compile/groupreduce 1.46 s 1.46 s −0.4%
pocl/serial/compile/localmem-barrier 692 ms 691 ms −0.1%
pocl/serial/compile/new-kernel 122 ms 121 ms −0.9%
pocl/serial/compile/new-workgroupsize 8.86 ms 8.79 ms −0.7%
pocl/serial/first-kernel/cold-cache 357 ms 358 ms +0.3%
pocl/serial/first-kernel/warm-cache 278 ms 278 ms −0.0%
Applications
pocl/parallel/dgsem/fluxdiff-node 445 µs 295 µs −33.7% 🟢 faster
pocl/parallel/dgsem/weak-element 212 µs 187 µs −11.9%
pocl/parallel/dgsem/weak-node-localmem 146 µs 122 µs −16.8%
pocl/parallel/stencil/timestep 7.92 ms 7.93 ms +0.1%
pocl/serial/stencil/timestep 12.2 ms 11.0 ms −9.7% 🟢 faster

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

@maleadt
maleadt merged commit c614650 into main Nov 6, 2026
29 of 30 checks passed
@maleadt
maleadt deleted the tb/bf16-exact-references branch November 6, 2026 07:34
@codecov

codecov Bot commented Nov 6, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 84.11%. Comparing base (a13691a) to head (6d9e3a4).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #952      +/-   ##
==========================================
- Coverage   84.91%   84.11%   -0.81%     
==========================================
  Files          31       31              
  Lines        2612     2562      -50     
==========================================
- Hits         2218     2155      -63     
- Misses        394      407      +13     

☔ 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

pocl The PoCL-based CPU back-end. upstream Root cause lies in Julia, LLVM, a vendor, or another package.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant