<div dir="ltr"><div>Hi all,</div><div><br></div><div>One of the purposes of `llvm::isnan` was to help preserve the check made by `isnan` if fast-math mode is</div><div>specified (<a href="https://reviews.llvm.org/D104854">https://reviews.llvm.org/D104854</a>). I'd like to describe reason for that and propose to use the behavior</div><div>implemented in that patch.</div><div><br></div>The option `-ffast-math` is often used when performance is important, as it allows a compiler to generate faster code.<div>This option itself is a collection of different optimization techniques, each having its own option. For this topic only the</div><div>option `-ffinite-math-only` is of interest. With it the compiler treats floating point numbers as mathematical real numbers,</div><div>so transformations like `0 * x -> 0` become valid.</div><div><br></div><div>In clang documentation (<a href="https://clang.llvm.org/docs/UsersManual.html#cmdoption-ffast-math">https://clang.llvm.org/docs/UsersManual.html#cmdoption-ffast-math</a>) this option is described as:<br><br>    "Allow floating-point optimizations that assume arguments and results are not NaNs or +-Inf."<br><br>GCC documentation (<a href="https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html">https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html</a>) is a bit more concrete:<br><br>    "Allow optimizations for floating-point arithmetic that assume that arguments and results are not NaNs or +-Infs."<br></div><div><br></div><div>**What is the issue?**<br><br>C standard defines a macro `isnan`, which can be mapped to an intrinsic function provided by the compiler. For both</div><div>clang and gcc it is `__builtin_isnan`. How should this function behave if `-ffinite-math-only` is specified? Should it make a</div><div>real check or the compiler can assume that it always returns false?<br><br>GCC optimizes out `isnan`. It follows from the viewpoint that (<a href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=50724#c1">https://gcc.gnu.org/bugzilla/show_bug.cgi?id=50724#c1</a>):<br><br>    "With -ffinite-math-only you are telling that there are no NaNs and thus GCC optimizes isnan (x) to 0."</div><div><br></div><div>Such treatment of `-ffinite-math-only` has sufficient drawbacks. In particular it makes it impossible to check validity of</div><div>data: a user cannot write</div><div><br></div><div>assert(!isnan(x));</div><div><br></div><div>because the compiler replaces the actual function call with its expected value. There are many complaints in GCC bug</div><div>tracker (for instance <a href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84949">https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84949</a> or <a href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=50724">https://gcc.gnu.org/bugzilla/show_bug.cgi?id=50724</a>)</div><div>as well as in forums (<a href="https://stackoverflow.com/questions/47703436/isnan-does-not-work-correctly-with-ofast-flags">https://stackoverflow.com/questions/47703436/isnan-does-not-work-correctly-with-ofast-flags</a> or <br><a href="https://stackoverflow.com/questions/22931147/stdisinf-does-not-work-with-ffast-math-how-to-check-for-infinity">https://stackoverflow.com/questions/22931147/stdisinf-does-not-work-with-ffast-math-how-to-check-for-infinity</a>). Proposed</div><div>solutions are using integer operations to make the check, to turn off `-ffinite-math-only` in some parts of the code or to</div><div>ensure that libc function is called. It clearly demonstrates that `isnan` in this case is useless, but users need its functionality</div><div>and do not have a proper tool to make required checks. The similar direction was criticized in llvm as well (<a href="https://reviews.llvm.org/D18513#387418">https://reviews.llvm.org/D18513#387418</a>).</div><div><br></div><div>**Why imposing restrictions on floating types is bad?**<br><br>If `-ffinite-math-only` modifies properties of `double` type, several issues arise, for instance:<br>- What should return `std::numeric_limits<double>::has_quiet_NaN()`?<br>- What body should have this function if it is used in a program where some functions are compiled with `fast-math` and some without?<br>- Should inlining of a function compiled with `fast-math` to a function compiled without it be prohibited in inliner?<br>- Should `std::isnan(std::numeric_limits<float>::quiet_NaN())` be true?<br><br>If the type `double` cannot have NaN value, it means that `double` and `double` under `-ffinite-math-only` are different types</div><div>(<a href="https://gcc.gnu.org/pipermail/gcc-patches/2020-April/544641.html">https://gcc.gnu.org/pipermail/gcc-patches/2020-April/544641.html</a>). Such a way can solve these problems but it is so expensive</div><div>that hardly it has a chance to be realized.</div><div><br></div><div>**The solution**<br><br>Instead of modifying properties of floating point types, the effect of `-ffinite-math-only` can be expressed as a restriction on</div><div>operation usage.  Actually clang and gcc documentation already follows this way. Fast-math flags in llvm IR also are attributes</div><div>of instructions. The only question is whether `isnan` and similar functions are floating-point arithmetic.<br><br>From a practical viewpoint, treating non-computational functions as arithmetic does not add any advantage. If a code extensively</div><div>uses `isnan` (so could profit by their removal), it is likely it is not suitable for -ffinite-math-only. This interpretation however creates</div><div>the problems described above. So it is profitable to consider `isnan` and similar functions as non-arithmetical.</div><div><br></div><div>**Why is it safe to leave `isnan`?**<br><br>The probable concern of this solution is deviation from gcc behavior. There are several reasons why this is not an issue.<br><br>      1. -ffinite-math-only is an optimization option. A correct program compiled with -ffinite-math-only and without it should behave</div><div>   identically, if conditions for using -ffinite-math-only are fulfilled. So making the check cannot break functionality.<br>    2. `isnan` is implemented by libc, which can map it to a compiler builtin or use its own implementation, depending on</div><div>   configuration options. `isnan` implemented in libc obviously always does the real check.<br>     3. ICC and MSVC preserve `isnan` in fast-math mode.</div><div><br></div><div>The proposal is to not consider `isnan` and other such functions as arithmetic operations and do not optimize them out</div><div>just because -ffinite-math-only is specified. Of course, there are cases when `isnan` may be optimized out, for instance,</div><div>`isnan(a + b)` may be optimized if -ffinite-math-only is in effect due to the assumption (result of arithmetic operation is not NaN).<br><br>What are your opinions?<br><br><div><div dir="ltr" class="gmail_signature" data-smartmail="gmail_signature">Thanks,<br>--Serge<br></div></div></div></div>