Skip to content

Don't allow reassociation in two_sum (fixes compensated sums on LLVM 23) - #43

Open
maleadt wants to merge 1 commit into
JuliaMath:masterfrom
maleadt:tb/llvm23-two-sum
Open

maleadt wants to merge 1 commit into
JuliaMath:masterfrom
maleadt:tb/llvm23-two-sum

Conversation

@maleadt

@maleadt maleadt commented Oct 13, 2026

Copy link
Copy Markdown
Member

With Julia built against LLVM 23 (JuliaLang/julia#63626), the compensated summation and dot product tests fail for Float32: 38 of 636 tests in the summation/compensated and dot product/compensated sets. Over 2200 random ill-conditioned sums (generate_sum(N, 1f5), N = 100:110), sum_oro gives:

results ≠ exact reference worst error
LLVM 22 8-11 / 2200 1 ulp
LLVM 23 ~1390 / 2200 262144 ulp
LLVM 23, with this PR 6-9 / 2200 1 ulp

The cause is the @fastmath on the first line of two_sum. It marks that addition fast, which allows reassociation. In the horizontal reduction of Base.sum(acc::CompSumAcc{<:Vec}), the hi values form a chain s = ((s + x1) + x2) + .... LLVM 23's SLP vectorizer turns that chain into a vector reduction. Because the adds are fast, it computes the final s with a tree-shaped llvm.vector.reduce.fadd, while the error terms are still derived from the sequential partial sums:

%foldExtExtBinop    = fadd fast <4 x float> %shift, %res.i211          ; sequential partial sums,
%foldExtExtBinop357 = fadd fast <4 x float> %shift356, %foldExtExtBinop ; used for the error terms
...
%30 = call fast float @llvm.vector.reduce.fadd.v4f32(float 0.0, <4 x float> %res.i211)  ; final hi, tree order

The final hi then no longer matches the lo terms. The fast flag allows this, so it isn't a compiler bug; LLVM 22 just didn't vectorize this chain. An error-free transformation needs hi to be exactly fl(a + b).

The @fastmath came in with a39fd86 as the replacement for SIMDops.@fusible, which only meant "may contract into an FMA". @fastmath allows much more than that (reassociation, no NaN/Inf, no signed zeros), and none of it is safe inside an error-free transformation.

With this PR, the test suite passes on LLVM 23 (636/636) and still passes on LLVM 22, both on assertion builds of Julia master and of the LLVM 23 PR. I left the @fastmath on the error accumulators (acc.e += e). It only reorders the small correction terms, though dropping it would make results independent of vectorization choices.

Investigated with the help of Claude Code; reproduced and tested locally.

`@fastmath` on the sum in two_sum lets the compiler reassociate it.
LLVM 23's SLP vectorizer uses that to compute the final hi of a
compensated reduction with a tree-shaped vector reduction, while the
error terms still come from the sequential partial sums, so the
compensation is lost. An error-free transformation needs hi to be
exactly fl(a + b).

Assisted-by: Claude Code (Opus 5.5)
@codecov

codecov Bot commented Oct 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 47.77%. Comparing base (3427289) to head (e18c2a3).

Additional details and impacted files
@@            Coverage Diff             @@
##           master      #43      +/-   ##
==========================================
- Coverage   50.11%   47.77%   -2.34%     
==========================================
  Files          13       13              
  Lines         447      427      -20     
==========================================
- Hits          224      204      -20     
  Misses        223      223              

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

This branch has not been deployed

No deployments
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.

1 participant