[llvm-dev] Intrinsic llvm::isnan

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.

2. 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
- represents the check throughout the IR pipeline and saves it from
undesired optimizations,
- is lowered in selector, which can choose the most suitable implementation
for particular target,
- helps keeping IR target-independent,
- facilitates program analysis as the operation is presented explicitly and
is not hidden behind general nodes.

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