[llvm-dev] [cfe-dev] Should isnan be optimized out in fast-math mode?

Serge Pavlov via llvm-dev llvm-dev at lists.llvm.org
Thu Sep 9 08:45:05 PDT 2021


On Thu, Sep 9, 2021 at 10:02 PM Sanjay Patel via llvm-dev <
llvm-dev at lists.llvm.org> wrote:

> Not sure which way to go, but I agree that we need to improve the
> docs/user experience either way.
> Let's try to iron this out with an example (this is based on
> https://llvm.org/PR51775 ):
>
> #include <math.h>
> #include <stdlib.h>
> int main() {
>     const double d = strtod("1E+1000000", NULL);
>     return d == HUGE_VAL;
> }
>
> What should this program return when compiled with -ffinite-math-only?
> Should this trigger a clang warning?
> https://godbolt.org/z/MY73Tf3ee
>

Comparison `d == HUGE_VAL` is an arithmetic operation, so requirements for
using -ffinite-math-only are broken. Both compilers are right.


>
> The proposed documentation text isn't clear to me. Should clang apply
> "nnan ninf" to the IR call for "strtod"?
> "strtod" is not in the enumerated list of functions where we would block
> fast-math-flags, but it is a standard lib call, so "nnan ninf" would seem
> to apply...but we also don't want "-ffinite-math-only" to alter the ability
> to return an INF from a "general function call"?
>
>
> On Thu, Sep 9, 2021 at 9:30 AM Krzysztof Parzyszek via cfe-dev <
> cfe-dev at lists.llvm.org> wrote:
>
>> If we say that the fast-math flags are “enabling optimizations that the
>> presence of nans otherwise prohibits”, then there is no reason for clang to
>> keep calls to “isnan” around, or to keep checks like “fpclassify(x) ==
>> it’s_a_nan” unfolded.  These are exactly the types of optimizations that
>> the presence of NaNs would prohibit.
>>
>>
>>
>> I understand the need for having some NaN-handling preserved in an
>> otherwise finite-math code.  We already have fast-math-related attributes
>> attached to each function in the LLVM IR, so we could introduce a
>> source-level attribute for enabling/disabling these flags per function.
>>
>>
>>
>>
>>
>> --
>>
>> Krzysztof Parzyszek  kparzysz at quicinc.com   AI tools development
>>
>>
>>
>> *From:* cfe-dev <cfe-dev-bounces at lists.llvm.org> *On Behalf Of *Chris
>> Lattner via cfe-dev
>> *Sent:* Wednesday, September 8, 2021 5:51 PM
>> *To:* James Y Knight <jyknight at google.com>
>> *Cc:* LLVM Developers <llvm-dev at lists.llvm.org>; Clang Dev <
>> cfe-dev at lists.llvm.org>
>> *Subject:* Re: [cfe-dev] [llvm-dev] Should isnan be optimized out in
>> fast-math mode?
>>
>>
>>
>> *WARNING:* This email originated from outside of Qualcomm. Please be
>> wary of any links or attachments, and do not enable macros.
>>
>> On Sep 8, 2021, at 3:27 PM, James Y Knight via llvm-dev <
>> llvm-dev at lists.llvm.org> wrote:
>>
>>
>>
>> I expressed my strong support for this on the previous thread, but I'll
>> just repost the most important piece...
>>
>>
>>
>> I believe the proposed semantics from the Clang level ought to be:
>>
>>   The -ffinite-math-only and -fno-signed-zeros options do not impact the
>> ability to accurately load, store, copy, or pass or return such values from
>> general function calls. They also do not impact any of the
>> "non-computational" and "quiet-computational" IEEE-754 operations, which
>> includes classification functions (fpclassify, signbit, isinf/isnan/etc),
>> sign-modification (copysign, fabs, and negation `-(x)`), as well as
>> the totalorder and totalordermag functions. Those correctly handle NaN,
>> Inf, and signed zeros even when the flags are in effect. These flags *do* affect
>> the behavior of other expressions and math standard-library calls, as well
>> as comparison operations.
>>
>>
>>
>> FWIW, I completely agree - these flags are about enabling optimizations
>> that the presence of nans otherwise prohibits.  We shouldn’t take a literal
>> interpretation of an old GCC manual, as that would not be useful.
>>
>>
>>
>> If we converge on this definition, I think it should be documented.  This
>> is a source of confusion that comes up periodically.
>>
>>
>>
>> -Chris
>>
>>
>>
>>
>>
>>
>>
>> I would not expect this to have an actual negative impact on the
>> performance benefit of those flags, since the optimization benefits mainly
>> arise from comparisons and the general computation instructions which are
>> unchanged.
>>
>>
>>
>> In further support of this position, I note that the previous thread
>> uncovered at least one vendor -- Apple (
>> https://opensource.apple.com/source/Libm/Libm-2026/Source/Intel/math.h.auto.html)
>> -- going out of their way to cause isnan and friends to function properly
>> with -ffast-math enabled.
>>
>>
>>
>>
>>
>>
>>
>> On Wed, Sep 8, 2021 at 1:02 PM Serge Pavlov via cfe-dev <
>> cfe-dev at lists.llvm.org> wrote:
>>
>> Hi all,
>>
>>
>>
>> One of the purposes of `llvm::isnan` was to help preserve the check made
>> by `isnan` if fast-math mode is
>>
>> specified (https://reviews.llvm.org/D104854). I'd like to describe
>> reason for that and propose to use the behavior
>>
>> implemented in that patch.
>>
>>
>>
>> The option `-ffast-math` is often used when performance is important, as
>> it allows a compiler to generate faster code.
>>
>> This option itself is a collection of different optimization techniques,
>> each having its own option. For this topic only the
>>
>> option `-ffinite-math-only` is of interest. With it the compiler treats
>> floating point numbers as mathematical real numbers,
>>
>> so transformations like `0 * x -> 0` become valid.
>>
>>
>>
>> In clang documentation (
>> https://clang.llvm.org/docs/UsersManual.html#cmdoption-ffast-math) this
>> option is described as:
>>
>>     "Allow floating-point optimizations that assume arguments and results
>> are not NaNs or +-Inf."
>>
>> GCC documentation (
>> https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html) is a bit more
>> concrete:
>>
>>     "Allow optimizations for floating-point arithmetic that assume that
>> arguments and results are not NaNs or +-Infs."
>>
>>
>>
>> **What is the issue?**
>>
>> C standard defines a macro `isnan`, which can be mapped to an intrinsic
>> function provided by the compiler. For both
>>
>> clang and gcc it is `__builtin_isnan`. How should this function behave if
>> `-ffinite-math-only` is specified? Should it make a
>>
>> real check or the compiler can assume that it always returns false?
>>
>> GCC optimizes out `isnan`. It follows from the viewpoint that (
>> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=50724#c1):
>>
>>     "With -ffinite-math-only you are telling that there are no NaNs and
>> thus GCC optimizes isnan (x) to 0."
>>
>>
>>
>> Such treatment of `-ffinite-math-only` has sufficient drawbacks. In
>> particular it makes it impossible to check validity of
>>
>> data: a user cannot write
>>
>>
>>
>> assert(!isnan(x));
>>
>>
>>
>> because the compiler replaces the actual function call with its expected
>> value. There are many complaints in GCC bug
>>
>> tracker (for instance https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84949
>> or https://gcc.gnu.org/bugzilla/show_bug.cgi?id=50724)
>>
>> as well as in forums (
>> https://stackoverflow.com/questions/47703436/isnan-does-not-work-correctly-with-ofast-flags
>> or
>>
>> https://stackoverflow.com/questions/22931147/stdisinf-does-not-work-with-ffast-math-how-to-check-for-infinity).
>> Proposed
>>
>> solutions are using integer operations to make the check, to turn off
>> `-ffinite-math-only` in some parts of the code or to
>>
>> ensure that libc function is called. It clearly demonstrates that `isnan`
>> in this case is useless, but users need its functionality
>>
>> and do not have a proper tool to make required checks. The similar
>> direction was criticized in llvm as well (
>> https://reviews.llvm.org/D18513#387418).
>>
>>
>>
>> **Why imposing restrictions on floating types is bad?**
>>
>> If `-ffinite-math-only` modifies properties of `double` type, several
>> issues arise, for instance:
>> - What should return `std::numeric_limits<double>::has_quiet_NaN()`?
>> - What body should have this function if it is used in a program where
>> some functions are compiled with `fast-math` and some without?
>> - Should inlining of a function compiled with `fast-math` to a function
>> compiled without it be prohibited in inliner?
>> - Should `std::isnan(std::numeric_limits<float>::quiet_NaN())` be true?
>>
>> If the type `double` cannot have NaN value, it means that `double` and
>> `double` under `-ffinite-math-only` are different types
>>
>> (https://gcc.gnu.org/pipermail/gcc-patches/2020-April/544641.html). Such
>> a way can solve these problems but it is so expensive
>>
>> that hardly it has a chance to be realized.
>>
>>
>>
>> **The solution**
>>
>> Instead of modifying properties of floating point types, the effect of
>> `-ffinite-math-only` can be expressed as a restriction on
>>
>> operation usage.  Actually clang and gcc documentation already follows
>> this way. Fast-math flags in llvm IR also are attributes
>>
>> of instructions. The only question is whether `isnan` and similar
>> functions are floating-point arithmetic.
>>
>> From a practical viewpoint, treating non-computational functions as
>> arithmetic does not add any advantage. If a code extensively
>>
>> uses `isnan` (so could profit by their removal), it is likely it is not
>> suitable for -ffinite-math-only. This interpretation however creates
>>
>> the problems described above. So it is profitable to consider `isnan` and
>> similar functions as non-arithmetical.
>>
>>
>>
>> **Why is it safe to leave `isnan`?**
>>
>> The probable concern of this solution is deviation from gcc behavior.
>> There are several reasons why this is not an issue.
>>
>> 1. -ffinite-math-only is an optimization option. A correct program
>> compiled with -ffinite-math-only and without it should behave
>>
>>    identically, if conditions for using -ffinite-math-only are fulfilled.
>> So making the check cannot break functionality.
>> 2. `isnan` is implemented by libc, which can map it to a compiler builtin
>> or use its own implementation, depending on
>>
>>    configuration options. `isnan` implemented in libc obviously always
>> does the real check.
>> 3. ICC and MSVC preserve `isnan` in fast-math mode.
>>
>>
>>
>> The proposal is to not consider `isnan` and other such functions as
>> arithmetic operations and do not optimize them out
>>
>> just because -ffinite-math-only is specified. Of course, there are cases
>> when `isnan` may be optimized out, for instance,
>>
>> `isnan(a + b)` may be optimized if -ffinite-math-only is in effect due to
>> the assumption (result of arithmetic operation is not NaN).
>>
>> What are your opinions?
>>
>> Thanks,
>> --Serge
>>
>> _______________________________________________
>> cfe-dev mailing list
>> cfe-dev at lists.llvm.org
>> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>>
>> _______________________________________________
>> LLVM Developers mailing list
>> llvm-dev at lists.llvm.org
>> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
>>
>>
>> _______________________________________________
>> cfe-dev mailing list
>> cfe-dev at lists.llvm.org
>> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>>
> _______________________________________________
> LLVM Developers mailing list
> llvm-dev at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20210909/a281498d/attachment.html>


More information about the llvm-dev mailing list