[cfe-dev] Intrinsic llvm::isnan

Serge Pavlov via cfe-dev cfe-dev at lists.llvm.org
Mon Aug 23 06:50:08 PDT 2021

When codegen lowers this call, it does not know if this is a regular
compare and it may create CMP instruction, as for default environment, or
this is 'isnan' for which it should generate different code, which does not
influence FP state.

On most architectures compare instructions change FP state, in default
environment it is just ignored, but actually hardware registers can be
modified, For 'isnan' instructions must actually leave FP state intact.


On Mon, Aug 23, 2021 at 8:43 PM Sanjay Patel <spatel at rotateright.com> wrote:

> You're saying that the function definition text overrides the argument
> definition text. Why are we choosing that interpretation rather than the
> inverse (and documenting it one way or the other)?
> On Mon, Aug 23, 2021 at 9:38 AM Serge Pavlov <sepavloff at gmail.com> wrote:
>> > How is this call in LLVM different than the semantics of "isnan(x)"
>> that is required by IEEE-754 or the C standard?
>> If either of the arguments of `llvm.experimental.constrained.fcmp` is
>> signaling NaN, this function should raise an 'Invalid' exception. 'isnan'
>> never raises exceptions.
>> Thanks,
>> --Serge
>> On Mon, Aug 23, 2021 at 8:10 PM Sanjay Patel <spatel at rotateright.com>
>> wrote:
>>> I'm confused about the definition of:
>>> https://llvm.org/docs/LangRef.html#llvm-experimental-constrained-fcmp-and-llvm-experimental-constrained-fcmps-intrinsics
>>> These intrinsics require an "exception behavior" argument. That argument
>>> can take the value “fpexcept.ignore” which is defined as:
>>> "optimization passes may assume that the exception status flags will not
>>> be read and that floating-point exceptions will be masked"
>>> i1 @llvm.experimental.constrained.fcmp.f64(double %x, double %x,
>>> metadata !"uno", metadata !"fpexcept.ignore")
>>> How is this call in LLVM different than the semantics of "isnan(x)" that
>>> is required by IEEE-754 or the C standard?
>>> On Mon, Aug 23, 2021 at 9:00 AM Serge Pavlov via cfe-dev <
>>> cfe-dev at lists.llvm.org> wrote:
>>>> On Mon, Aug 23, 2021 at 6:12 PM Roman Lebedev <lebedev.ri at gmail.com>
>>>> wrote:
>>>>> Thank you for posting the RFC!
>>>>> I do not believe we should conflate StrictFP support, and
>>>>> `-ffast-math` handling, these are two separate/separatable concerns.
>>>> You are right, they are separate, but they originate from the
>>>> implementation of the same function and can be solved with the same
>>>> solution.
>>>>> As for the latter, right now i'm not convinced that we should
>>>>> second-guess/override explicit user request.
>>>>> This is inconsistent, and does not match how at least the GCC deals
>>>>> with it.
>>>>> I think changing the status-quo (before said patch) should be a
>>>>> separate RFC,
>>>>> and that change should be undone until after that RFC is accepted.
>>>> Actually we have two explicit user requests, a call of 'isnan' and an
>>>> option '-ffast-math'. IMHO they do not contradict each other as 'isnan' is
>>>> not an arithmetic operation. There is a discussion in
>>>> https://reviews.llvm.org/D18513#387418, which also expresses the
>>>> opinion that limitations imposed by '-ffast-math' should be applied only to
>>>> 'math' functions but not to 'tests'. As for GCC behavior, they agree that
>>>> this behavior is a bag:
>>>> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84949. Intel and
>>>> Microsoft compilers do not replace 'isnan' with assumed value.
>>>>> As for the latter, the main point of confusion is,
>>>>> why is `@llvm.isnan` still used in non-StrictFP code?
>>>> We have to introduce an intrinsic to represent `isnan` in strictfp
>>>> environment. It is natural to use it for the default environment as
>>>> well. Besides, a target may have a more efficient way to represent `isnan`
>>>> than unordered comparison.
>>>> The argument that we need `@llvm.isnan` because we *might* transition
>>>>> in and out of StrictFP section does not seem to hold for me, because
>>>>> https://llvm.org/docs/LangRef.html#constrainedfp says:
>>>>> > If any FP operation in a function is constrained then they all must
>>>>> be constrained. This is required for correct LLVM IR.
>>>> There was no such intention. The primary motivation was strict fp
>>>> exceptions.
>>>>> So presumably when codegen'ing a function, we already know that we
>>>>> will use StrictFP ops, and that should be the knob to use
>>>>> `@llvm.isnan`,
>>>>> i think.
>>>>> Roman
>>>>> On Mon, Aug 23, 2021 at 1:57 PM Serge Pavlov via cfe-dev
>>>>> <cfe-dev at lists.llvm.org> wrote:
>>>>> >
>>>>> > 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
>>>>> > _______________________________________________
>>>>> > cfe-dev mailing list
>>>>> > cfe-dev at lists.llvm.org
>>>>> > https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>>>> _______________________________________________
>>>> cfe-dev mailing list
>>>> cfe-dev at lists.llvm.org
>>>> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20210823/0c632c92/attachment.html>

More information about the cfe-dev mailing list