One source, one compiler, unlike CPUs, same bits.
This harness asks whether OpenCL kernels compiled by PoCL, through one LLVM, give bit-identical results on different CPUs. It records a SHA-256 of every output slice, with NaNs made canonical (OpenCL does not specify NaN bits, and x86 and RISC-V produce different ones), and compares the hashes across builds, targets and settings.
It is published so that someone can refute it. Every hash we recorded is in
results/. A different hash from yours, on the same cell, is a finding.
x86-64 native; riscv64 under qemu.
- Integer kernels (an int8 matmul, reductions, scans) are bit-identical
across 84 configurations:
- work-group handlers, core counts and local sizes;
- compilation targets (x86-64 baseline and znver3 native), LLVM 22 and 23, and two vector math libraries;
- our PoCL series and upstream's merge base;
- x86 against riscv64, and PoCL against Mesa Rusticl on an AMD iGPU.
- Float kernels calling 36 math builtins are bit-identical between x86
and riscv64 on all 76 outputs, when PoCL's builtins are CORE-MATH's
correctly rounded functions. A correctly rounded result is unique, so any
two such builds must agree.
- With PoCL's own builtins, x86 and riscv64 also agree, because it is the same code, but the results are not correctly rounded.
- With a vector math library (glibc's
libmvec), the results differ between builds.
- Three things break float bit-identity even on one machine, unless
every path is correctly rounded:
- The work-group size. Some sizes run a call scalar (the host's libm)
and others vectorized (
libmvec). With glibc'slibmvec, sizes 1, 2 and 13 change about a quarter of all results. With CORE-MATH as the kernel library, no size changes anything. - Build flags such as
-cl-fast-relaxed-math. On x86 they turn a division into a reciprocal estimate, and softmax and GELU then differ between x86 and riscv64. - Constant folding. LLVM folds a literal's math call with the
compiling machine's libm, so a constant and the same value computed at
run time can differ: in 333 of 2,048 cases with glibc's
libmvec, and in none with CORE-MATH as the kernel library.
- The work-group size. Some sizes run a call scalar (the host's libm)
and others vectorized (
The contract this harness tests:
- correctly rounded math functions on every path (vector, scalar and compile time);
- a fixed order for every reduction, set by the source;
- no floating-point contraction (
#pragma OPENCL FP_CONTRACT OFF); - no relaxed-math build flags;
- no flushing of subnormals;
- correctly rounded division and square root
(
-cl-fp32-correctly-rounded-divide-sqrt).
- RISC-V has been checked under qemu only, not on silicon.
- Everything but the one Rusticl cell is PoCL's CPU device.
- The cells are not plain upstream PoCL. Every PoCL cell but
up-base-noneis built on our vector-math patch series, and the CORE-MATH route is one more patch on top (seepatches/andCELLS.md). - Integer kernels that call a subgroup reduction were not tested.
| path | what |
|---|---|
harness/determinism/ |
the kernels (int_kernels.py, float_kernels.py), the probes (remainder_probe.py, constfold_probe.py), the runners (run.sh, run-float.sh) and the comparisons (compare.py, compare_float.py) |
container/ |
the two build images: Dockerfile (x86-64, Ubuntu 24.04, LLVM 22) and Dockerfile.rv64 (riscv64, Debian trixie, LLVM 22) |
patches/ |
the PoCL patches, on upstream aaaa2d67b (2026-09-11) |
results/ |
every hash we recorded, one JSON per run |
CELLS.md |
each cell: its source, its build options, and its result files |
- Build an image from
container/. For riscv64, usedocker build --platform linux/riscv64and run with-e QEMU_CPU=max,vlen=256. - Check out PoCL at
aaaa2d67b4f3cfe7b7d55a4984d5adb168d72d1aand apply the patches for your cell:git am patches/vecmath/*.patch, thenpatches/coremath.patchorpatches/crmvec.patchif the cell needs one. - Configure and build with the cell's options from
CELLS.md, in the container, with the build at/work/buildand this checkout at/h. - Run
harness/determinism/run.sh <build-dir> <tag>(integer) orrun-float.sh <tag>(float), then compare withcompare.pyorcompare_float.pyagainstresults/.
The patches reproduce our branches exactly: applied to aaaa2d67b, they
give trees identical to the commits we built from (10a12a5fc,
8ba2be4a8, 56073e544).
MIT for this repository's own files (LICENSE). The patches carry PoCL's
license, and patches/coremath.patch adds CORE-MATH's files with their own
MIT notices.
Developed with AI assistance (Claude), disclosed throughout.