[cfe-dev] [llvm-dev] Intrinsic llvm::isnan

James Y Knight via cfe-dev cfe-dev at lists.llvm.org
Mon Aug 23 13:46:04 PDT 2021


According to IEEE 754, the following operations are "non-computational",
and should not signal if provided with an sNAN argument.
I've annotated each with -> C function/macro equivalent, taken from the
table in the C standard draft.

enum class(source) -> fpclassify, signbit, issignaling
boolean isSignMinus(source) -> signbit
boolean isNormal(source) -> isnormal
boolean isFinite(source) -> isfinite
boolean isZero(source) -> iszero
boolean isSubnormal(source) -> issubnormal
boolean isInfinite(source) -> isinf
boolean isNaN(source) -> isnan
boolean isSignaling(source) -> issignaling
boolean isCanonical(source) -> iscanonical
enum radix(source) -> FLT_RADIX constant
boolean totalOrder(source, source) -> totalorder
boolean totalOrderMag(source, source) -> totalordermag

(Decimal numbers:)
boolean sameQuantum(source, source) -> samequantum

The following list are "quiet-computational" operations, which also should
not signal when provided with an sNAN:

sourceFormat copy(source) -> memcpy, memmove,+(x) -- (Somewhat
surprisingly, "x = y" is implementation-defined to be either a "copy"
(non-signaling) or a "convertFormat" (signaling), even when x and y are the
same type.)
sourceFormat negate(source) -> -(x)
sourceFormat abs(source) -> fabs

(Decimal numbers):

decimalEncoding encodeDecimal(decimal) -> encodedec
decimal decodeDecimal(decimalEncoding) -> decodedec
binaryEncoding encodeBinary(decimal) -> encodebin
decimal decodeBinary(binaryEncoding) -> decodebin




On Mon, Aug 23, 2021 at 3:42 PM Sanjay Patel via cfe-dev <
cfe-dev at lists.llvm.org> wrote:

> Ok, does this edit to the LangRef make sense for the definition of
> "ignore":
> "optimization passes may assume that the exception status flags will not
> be read and that floating-point exceptions **will** be masked" -->
> "optimization passes may assume that the exception status flags will not
> be read and that floating-point exceptions **may** be masked"
>
> It's still not clear to me if there's a benefit from having an intrinsic
> vs. one more exception mode ("none" or "off").
> That answer might depend on how many more of these intrinsics we'll need?
> <cmath> has these:
> isfinite()
> isinf()
> isnormal()
> signbit()
>
> others?
>
> On Mon, Aug 23, 2021 at 2:25 PM Kaylor, Andrew <andrew.kaylor at intel.com>
> wrote:
>
>> > Why would a target be allowed to lower the constrained fcmp intrinsic
>> with "ignore" to an operation that might raise an exception?
>>
>>
>>
>> Because the “fpexcept.ignore” argument means that exceptions are being
>> ignored. That is, it doesn’t matter whether exceptions are raised or not.
>> It’s a promise that exceptions are not unmasked or being explicitly checked
>> in this part of the code.
>>
>>
>>
>> The “fpexcept.ignore” argument isn’t used for the fully strict mode. It
>> is used for two cases:
>>
>>
>>
>> 1) To get back to the “default” state (in combination with
>> “fpround.tonearest”) when a non-constrained operation is inlined into a
>> function that has constrained operations.
>>
>> 2) To enable dynamic rounding (-frounding-math) without requiring strict
>> exception semantics.
>>
>>
>>
>>
>>
>> Regarding NaN comparison support in the presence of fast-math flags, I
>> think this is an excellent reason to have the intrinsic. I needed this for
>> a (non-C/C++) downstream compiler before the llvm.isnan intrinsic was
>> introduced and found that the only ways to achieve it were either to
>> introduce an intrinsic for the comparison or to remove the ‘nnan’ flag
>> everywhere.
>>
>>
>>
>> -Andy
>>
>>
>>
>>
>>
>> *From:* llvm-dev <llvm-dev-bounces at lists.llvm.org> *On Behalf Of *Sanjay
>> Patel via llvm-dev
>> *Sent:* Monday, August 23, 2021 10:56 AM
>> *To:* Wang, Pengfei <Pengfei.Wang at intel.com>
>> *Cc:* llvm-dev at lists.llvm.org; Clang Dev <cfe-dev at lists.llvm.org>
>> *Subject:* Re: [llvm-dev] [cfe-dev] Intrinsic llvm::isnan
>>
>>
>>
>> Why would a target be allowed to lower the constrained fcmp intrinsic
>> with "ignore" to an operation that might raise an exception?
>>
>> If that scenario does not exist, then make the definition of fcmp
>> "ignore" stronger by saying that it *requires* a lowering that does not
>> raise an exception.
>>
>> If refining the definition of "ignore" in this case is too hard to
>> reconcile with other FP ops, how about adding another exception mode
>> ("none") to specify that exceptions are guaranteed not to be raised?
>>
>>
>>
>> On Mon, Aug 23, 2021 at 11:04 AM Wang, Pengfei <pengfei.wang at intel.com>
>> wrote:
>>
>> AFAIU, the fpexcept metadata is just a hint for optimizations, which have
>> to respect the sequence of FP instructions. “ignore” is not a command to
>> ask backend to mask the exception. It just tells optimizations the
>> exceptions are not concerned by user, so that the FP instructions can be
>> scheduled.
>>
>> I think an non exception intrinsic is needed, because it is a commend to
>> request backend not to emit instructions that may raise exception.
>>
>>
>>
>> Thanks
>>
>> Pengfei
>>
>>
>>
>> *From:* llvm-dev <llvm-dev-bounces at lists.llvm.org> *On Behalf Of *Sanjay
>> Patel via llvm-dev
>> *Sent:* Monday, August 23, 2021 10:13 PM
>> *To:* Serge Pavlov <sepavloff at gmail.com>
>> *Cc:* LLVM Developers <llvm-dev at lists.llvm.org>; Clang Dev <
>> cfe-dev at lists.llvm.org>
>> *Subject:* Re: [llvm-dev] [cfe-dev] Intrinsic llvm::isnan
>>
>>
>>
>> If the FP state is not made invisible/irrelevant by "fpexcept.ignore",
>> then why is that argument on this intrinsic call at all?
>>
>> Ie, why is that argument not used by the backend to decide to lower to a
>> CMP instruction or special isnan instruction or library call?
>>
>>
>>
>> An example would be helpful - in what case would these two lower
>> differently given that SNAN always raises a visible exception?
>>
>> call i1 @llvm.experimental.constrained.fcmp.f64(double %x, double %x,
>> metadata !"uno", metadata !"fpexcept.ignore") ; "floating-point exceptions
>> will be masked"
>>
>> call i1 @llvm.experimental.constrained.fcmp.f64(double %x, double %x,
>> metadata !"uno", metadata !"fpexcept.strict")  ; "this mode can also be
>> used with code that unmasks FP exceptions"
>>
>>
>>
>>
>>
>> On Mon, Aug 23, 2021 at 9:50 AM Serge Pavlov <sepavloff at gmail.com> wrote:
>>
>> 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.
>>
>>
>> Thanks,
>> --Serge
>>
>>
>>
>>
>>
>> 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
>>
>> _______________________________________________
> 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/3be5f0e8/attachment-0001.html>


More information about the cfe-dev mailing list