<div dir="ltr">Hi all,<br><br>Some time ago a new intrinsic `llvm.isnan` was introduced, which is intended to represent IEEE-754 operation `isNaN` as well as a family of C library functions `isnan*`. Recently during post-commit review concern was raised (see
<a href="https://reviews.llvm.org/D104854">https://reviews.llvm.org/D104854</a>) that this functionality must have had RFC to make sure there is consensus on semantics.<div><br></div><div>Previously the frontend intrinsic `__builtin_isnan` was converted into `cmp uno` during IR generation in clang codegen. There are two main reasons why this solution is not satisfactory. <br></div><div><br></div><div>1. Strict floating-point semantics.<br><br>If FP exceptions are not ignored, `cmp uno` must be replaced with its constrained counterpart, namely `llvm.experimental.constrained.fcmp` or `llvm.experimental.constrained.fcmps`. None of them is compatible with the semantics of `isnan`. Both IEEE-754 (5.7.2) an C standard (<a href="http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2596.pdf">http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2596.pdf</a>, F.3p6) demand that this function does not raise floating point exceptions. Both the constrained compare intrinsics raise an exception if either operand is a SNAN (<a href="https://llvm.org/docs/LangRef.html#id1131">https://llvm.org/docs/LangRef.html#id1131</a>). So there was no target-independent IR construct that could express `isnan`.<br><br>This drawback was significant enough and some attempts to alleviate it were undertaken. In <a href="https://reviews.llvm.org/D95948">https://reviews.llvm.org/D95948</a> `isnan` was implemented using integer operations in strictfp functions. It however is not suitable for targets where a more efficient way exists, like dedicated instruction. Another solution was implemented in <a href="https://reviews.llvm.org/D96568">https://reviews.llvm.org/D96568</a>, where a hook 'clang::TargetCodeGenInfo::testFPKind' was introduced, which injects target specific code into IR. Such a solution makes IR more target-dependent and prevents some IR-level optimizations.<br></div><div><br></div><div>2. Compilation with -ffast-math <br><br>The option '-ffast-math' is often used for performance critical code, as it can produce faster code. In this case the user must ensure that NaNs are not used as operand values. `isnan` is just proposed for such checks, but it was unusable when `isnan` was represented by compare instruction, because the latter may be optimized out. One of use cases is data in memory, which is processed by a function compiled with `-ffast-math`. Some items in the data are NaNs to denote absence of values.<br><br>This point requires some remarks about using NaNs when a function is compiled with `-ffast-math`. GCC manual does not specify how this option works, it only states about `-ffinite-math-only` (<a href="https://gcc.gnu.org/onlinedocs/gcc-11.2.0/gcc/Optimize-Options.html#Optimize-Options">https://gcc.gnu.org/onlinedocs/gcc-11.2.0/gcc/Optimize-Options.html#Optimize-Options</a>):<br><br> `Allow optimizations for floating-point arithmetic that assume that arguments and results are not NaNs or +-Infs.`<br><br></div><div>`isnan` does not do any arithmetic, only check, so this statement apparently does not apply to it. There is a GCC bug report <a href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84949">https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84949</a>, where investigation conforms that std::isnan() and std::fpclassify() should works with NaNs as specified even in -ffast-math mode.<br><br>Extending NaN restrictions in -ffast-math mode to functions like `isnan` does not make code faster, but is a source of broken user expectations. If a user writes `isnan` they usually expect an actual check. Silently removing the check is a stronger action than assuming that float value contains only real numbers.<br></div><div><br></div><div>Intrinsic `llvm.isnan` solves these problems. It<br>- represents the check throughout the IR pipeline and saves it from undesired optimizations,<br>- is lowered in selector, which can choose the most suitable implementation for particular target,<br>- helps keeping IR target-independent,<br>- facilitates program analysis as the operation is presented explicitly and is not hidden behind general nodes.<br><br>Note that `llvm.isnan` is optimized out if its argument is an operation with `nnan` flag, this behavior agrees with the definition of this flag in LLVM documentation.<br><br>Any feedback is welcome.</div><div><br><div><div dir="ltr" class="gmail_signature" data-smartmail="gmail_signature">Thanks,<br>--Serge<br></div></div></div></div>