[cfe-dev] [llvm-dev] Should isnan be optimized out in fast-math mode?

Chris Tetreault via cfe-dev cfe-dev at lists.llvm.org
Tue Sep 21 10:18:30 PDT 2021

(tl;dr) I seem to have become embroiled in this argument again, and this is clearly going nowhere. Therefore, I propose:

  1.  At a minimum, we should do nothing but (maybe) clarify the docs. I think the current behavior is acceptable for the vast majority of users, and there exists workarounds for users that really need them.
  2.  If interested users really want to be able to do isnan(x) with fast-math enabled without workarounds, they should implement the pragma. Such a pragma would be of great value to society, and surely users would thank us.
  3.  We should not create a special case for isnan(x). I have laid out many arguments why it’s not a good solution. It would reduce the value of fast-math for users such as the graphics programmers described below, and create portability issues if code begins to rely on this new special case (becoming non-portable to any other compiler or old versions of clang. And again, just because MSVC and ICC *just happen to*, as an implementation detail, work like this today doesn’t mean that they can be relied on to continue working like this, or that old versions worked like this).

(my rebuttal to this last message)

Many users of fast-math *can* actually ignore the existence of NaNs. For example, in a real time 3D renderer, the presence of NaN is typically a bug. In the hot render loop, you cannot afford to do any sort of error handling related to NaN, and getting a NaN in one your matrices or vertices will result in black triangles or a black screen. For these users, you must just be disciplined, and avoid creating NaNs.

However, if such a user were to depend on a math lib (probably templated because graphics programmers overwhelmingly prefer C++, which means that they would be compiling it themselves, but can’t easily modify it) that contains isnan, it would be a shame if the compiler were forbidden to consider it an optimization candidate because they called a function that “uses” it for input validation or something. Such code would look something like:

template <typename T> T f(T x) {
   // some sort of branch based on isnan(x) here

… which meets the criteria you propose for not being eliminated, but is also absolutely undesirable. For users that do care about NaN, a pragma would be an elegant way for them to ensure that the isnan call they care about is not eliminated. For a graphics developer, an assert on isnan suddenly becomes useful if they had a pragma and could enable it selectively.

   Christopher Tetreault

From: llvm-dev <llvm-dev-bounces at lists.llvm.org> On Behalf Of Serge Pavlov via llvm-dev
Sent: Tuesday, September 21, 2021 6:05 AM
To: antlists <antlists at youngman.org.uk>
Cc: LLVM Developers <llvm-dev at lists.llvm.org>
Subject: Re: [llvm-dev] [cfe-dev] Should isnan be optimized out in fast-math mode?

WARNING: This email originated from outside of Qualcomm. Please be wary of any links or attachments, and do not enable macros.
On Tue, Sep 21, 2021 at 3:46 AM antlists via llvm-dev <llvm-dev at lists.llvm.org<mailto:llvm-dev at lists.llvm.org>> wrote:
I know I may be coming in at half cock, but what is the CORRECT

I'll use your question to make a summary.

 Now clang removes calls to `isnan` in -ffinite-math-only. The justification for such behavior comes from early GCC viewpoint (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=50724#c1):

"With -ffinite-math-only you are telling that there are no NaNs"

On this assumption the removal of `isnan` is a perfectly valid optimization, it produces a program that behaves identically to the initial program, which contains `isnan`. For all valid input data it produces  the same output.

Actually the existence of NaNs cannot be ignored even if no operations on NaNs take place. There are several reasons for that, at least:
- Users need  to check the input data, for example to assert, or to choose a slower but general path.
- NaN can be used as a sentinel. In this case it is actually not a number but some distinguishable bit pattern.
- NaNs can be produced by operations on "allowed" numbers. It is easier to demonstrate on infinities. The expression `x * y` may produce infinity when its operands are finite numbers and it is hard to reveal that without execution of the operation.
- Code compiled with `-ffinite-math-only` may call functions from libraries or from other parts of the program, compiled without this flag. These functions may return infinities and NaNs. It is often impractical to check the arguments prior to the call to ensure the result would be finite. In some cases it is even impossible. In this case it is necessary to check if the result is finite.

The "correct behavior" depends on whether NaNs are allowed in the code compiled with -ffinite-math-only:
- if no, we have the current behavior,
- if yes, `isnan` cannot be optimized out.

The approach "-ffinite-math-only means there are no NaNs" is an abstraction that does not fit user needs. This problem is actually common. There are many user feedbacks, in GCC bug tracker:
- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=50724
- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84949
as well as in forums:
- https://stackoverflow.com/questions/38978951/can-ffast-math-be-safely-used-on-a-typical-project
- https://stackoverflow.com/questions/47703436/isnan-does-not-work-correctly-with-ofast-flags
To support `isnan` with -ffinite-math-only users have to use kludges like emulating `isnan` with integer arithmetic, calling libs implementation or moving their own `isnan` implementation to separate translation units. All of them have drawbacks and bring loss in portability and performance.

The proposal was to support the programming model, anticipated by many users. Advantages and risks were discussed in the thread previously.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20210921/a3c693a9/attachment-0001.html>

More information about the cfe-dev mailing list