[llvm-dev] Intrinsic llvm::isnan (original) (raw)

Serge Pavlov via llvm-dev llvm-dev at lists.llvm.org
Mon Aug 23 03:57:07 PDT 2021


Hi all,

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 https://reviews.llvm.org/D104854) that this functionality must have had RFC to make sure there is consensus on semantics.

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.

  1. Strict floating-point semantics.

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 ( http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2596.pdf, 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 (https://llvm.org/docs/LangRef.html#id1131). So there was no target-independent IR construct that could express isnan.

This drawback was significant enough and some attempts to alleviate it were undertaken. In https://reviews.llvm.org/D95948 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 https://reviews.llvm.org/D96568, 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.

  1. Compilation with -ffast-math

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.

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 ( https://gcc.gnu.org/onlinedocs/gcc-11.2.0/gcc/Optimize-Options.html#Optimize-Options ):

Allow optimizations for floating-point arithmetic that assume that arguments and results are not NaNs or +-Infs.

isnan does not do any arithmetic, only check, so this statement apparently does not apply to it. There is a GCC bug report https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84949, where investigation conforms that std::isnan() and std::fpclassify() should works with NaNs as specified even in -ffast-math mode.

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.

Intrinsic llvm.isnan solves these problems. It

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.

Any feedback is welcome.

Thanks, --Serge -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20210823/80186078/attachment.html>



More information about the llvm-dev mailing list