Std::isinf vs Xcode 14.1/14.2 -Ofast

Today I came across a strange problem on my secondary machine running Ventura/Xcode 14. In my dsp code I use infinite double values to mark analogue poles/zeros placed at infinity.
Other parts of the code check this using std::isinf(double).

During performance testing I ramped up the optimisation settings to -Ofast, which includes -ffast-math and a bunch of other math stuff - including not caring too much about nan and inf values in math routines. So far (on older versions of Xcode) this has never been a problem and std::isinf(double) still worked. Something seems to be different on Xcode 14.1+ and I am now getting false for +inf values. It seems the test is completely bypassed. Initially I thought something was wrong with my Xcode 14.1 installation and I downloaded and installed 14.2 - just to see no difference. Unfortunately I don’t have another Ventura machine to verify this.

Has anyone seen that as well? At least in my case it broke my dsp code in a terrible way… ironically producing +inf output samples.

#include <iostream>
#include <numeric>

int main() {
  double a = std::numeric_limits<double>::infinity();
  if (std::isinf(a))
    std::cout << "Inf detected.\n";
    std::cout << "Inf NOT detected.\n";
  return 0;

result on Venture command line:

adrianpf@Adis-MBA Desktop % g++ -Ofast test.cpp
adrianpf@Adis-MBA Desktop % ./a.out 
Inf NOT detected.

I get the same behaviour for floats btw. It works fine on OSX 12.3 / Xcode 13

I stopped using fast-math with clang, it has caused me too many issues. With fast-math, clang considers that Inf or NaN values will never occur ( -ffast-math implies -ffinite-math-only ) so all your safeguards trying to detect inf or nan are bypassed by the compiler. I also had at one time an even worse behaviour where std::sqrt(1e-40f) would return -inf. The very small performance gain is absolutely not worth the drawbacks of fast-math .

The performance gain depends on what the code is doing. I have some dsp code where it makes a lot of difference (30% speedup) and I’d like to keep it on at least for those parts. Before switching to CMake I left -ffast-math on at all times to catch these weird bugs as early as possible.

In the meantime I saw some discussions on LLVM forums about my specific problem and the new-ish behaviour of just bypassing isinf (and isnan it seems…) is especially troublesome if code receives floating point values from other code/files/the network and wants to make sure the data is sound.

So -Ofast users beware… in the Juce sources (v6.1.6) there’s one instance of std::isinf in the svg parser that’s affected by this - not a real problem.

Does x != x still detect nans?

x != x for nans is fine, but std::isnan() is not.

I now switched to this for isinf()

inline bool _optimisable_isinf(double x) {
  return (reinterpret_cast<uint64_t &>(x) & 0x7fffffffffffffffULL) ==

btw. here’s the llvm discussion that seems to conclude isinf/isnan should still work, but somehow I’m seeing something else since Xcode 14.

I’m seeing the same thing with clang and GCC trunk on Godbolt:

On godbolt using clang x86-64 the behaviour seems to change between clang 11 and clang 12… however on my m1 macs the switch happens between clang 13 and clang 14. Odd.

Is that Apple Clang 13 & 14? I’m not sure they track clang exactly?

yes, AppleClang 13 and 14, but maybe it depends in the libc++ version as well?
It seems gcc has been this way for a long time… so for me the lesson is to not trust std::isnan, std::isinf and std::fpclassify if math optimisations are used.