- Sat 06 May 2023
- programming
- Gaige B. Paulsen
- #programming, #xcode, #macintosh
My previous post about proj floating point investigation discussed an issue that I'd tracked down to the OS level. However, it's clear that this relates to an underlying change to code compiled by Xcode (and/or the LLVM toolchain that it is built upon).
Based on a post about Xcode 14.3
in Michael Tsai's blog, I started looking at a
change in the compiler around the handling of fp-contract
, which controls
the use of contractions in optimizing floating point operations in the compiler.
There's certainly beeen some debate about the change
that was introduced in Clang 14 which changed the handling of the
fp-contract
flag, and I'm not going to take a stand on which is "better",
but I am going to note that the change was unexpected (in a minor release)
and had notable, if not significant effects on floating point handling in
Cartographica.
The change in behavior results in Xcode 14.3 (Clang 14) by default choosing to contract Multiply and Add instructions in floating point using a Fused Multiply Add instruction that is intended to capture rounding betwen the operations. Although this likely makes the calculations more accurate, it runs the risk of diverging from existing resutls and can create compolexitiies in testing.
In practice, I haven't found a large number of differences, but in some cases, there are variances that are causing some difficulties in test management.
The change itself was in how the fp-contract
(floating-point contraction)
flag was being handled by Clang to bring it more into alignment with the
standards for C/C++. The details on the flag handling are a bit esoteric
so I'll leave that for the reader, but there are a
variety of options
for the setting and the change was in the default handling between Clang 13
and Clang 14, effectively causing it to move from off
to on
by default.
If you want to see an illustration of what this does from a code generation
perspective, there's a good comparison using godbolt
between default Clang 13 and Clang 14, as well as Clang 14 with
-ffp-contract=off
, showing the behavior change.
(
longer godbolt link here if the short one ever goes stale).
I'm still on the fence over whether this is actually a code problem or a test problem, but at the moment, it's really feeling more like the latter. The IEEE Floating Point standards define the fused-multiply-add operator and it's clearly intended to remove some error in the combining of floating point operations while also improving speed.