[llvm-dev] PR43374 - when should comparing NaN values raise a floating point exception?

Sanjay Patel via llvm-dev llvm-dev at lists.llvm.org
Tue Oct 8 05:07:10 PDT 2019


On Tue, Oct 8, 2019 at 7:08 AM Szabolcs Nagy <nsz at port70.net> wrote:

> * Sanjay Patel via llvm-dev <llvm-dev at lists.llvm.org> [2019-10-01
> 09:44:54 -0400]:
> > Let's change the example to eliminate suspects:
> >   #include <math.h>
> >   int is_nan(float x) {
> >     /*
> >       The following subclauses provide macros that are quiet (non
> > floating-point exception raising)
> >       versions of the relational operators, and other comparison macros
> > that facilitate writing
> >       efficient code that accounts for NaNs without suffering the
> > ‘‘invalid’’ floating-point exception.
> >     */
> >     return isunordered(x, x);
> >   }
> >
> > The comment text is from 7.12.14 of the C standard draft. I'm hoping to
> > avoid any scenario under which it is ok to raise an exception in that
> code
> > (eliminate any questions about the clang front-end behavior /
> FENV_ACCESS).
>
> isunordered (like isnan) is a different operation from x!=x,
> in particular it does not signal even on signaling nans
> while x!=x does.
>
> >
> > As IR from clang with no optimization, this becomes a bunch of load/store
> > with:
> >   %cmp = fcmp uno double %conv, %conv1
> >
> > Ok, so far? "fcmp uno" -
> http://llvm.org/docs/LangRef.html#fcmp-instruction
> > :
> > uno: yields true if either operand is a QNAN.
>
> why is that ok?
>

Because there are no FP exceptions/signals for this IR opcode:
http://llvm.org/docs/LangRef.html#floating-point-environment

AFAIK, the problem has been resolved with:
https://reviews.llvm.org/D68463 (committed at r374025)

here you need an unordered-not-equal, but got an unordered-compare,
> the former is a silent ieee754 operation the latter is signaling.
>
> as noted earlier this is wrong for signaling nans, because any fcmp
> would signal for them, but the lack of snan support can be forgiven,
> however here even qnans fail to remain silent, that's a bug.
>
> >
> > EarlyCSE/InstCombine reduce that fcmp to:
> >   %cmp = fcmp uno float %x, 0.000000e+00
> >
> > Still good? Same fcmp predicate, but we replaced a repeated use of "%x"
> > with a zero constant to aid optimization.
>
> no, this is different from even x!=x not to mention isunordered(x,x).
>
> clang does not support FENV_ACCESS but repeatedly claimed in relevant
> bug reports that users who care should use -O0, but it seems to create
> broken compares even at -O0, so there is no way to get c99 conforming
> behaviour.
>

I understand why someone may have suggested -O0 as a work-around, but as
you've noted, that's not a complete solution to the problem. You likely
need:
http://llvm.org/docs/LangRef.html#constrainedfp



>
> >
> > Now, send the optimized IR to codegen:
> > define i32 @is_nan(float %x) {
> >   %cmp = fcmp uno float %x, 0.000000e+00
> >   %r = zext i1 %cmp to i32
> >   ret i32 %r
> > }
> >
> > $ llc -o - fpexception.ll -mtriple=armv7a
> >   vmov s0, r0
> >   mov r0, #0
> >   vcmpe.f32 s0, s0
> >   vmrs APSR_nzcv, fpscr
> >   movwvs r0, #1
> >   bx lr
> >
> > We produced "vcmpe" for code that should never cause an FP exception. ARM
> > codegen bug?
>
> sorry, the arm code gen is right here, the bug is in clang.
>
> >
> > On Tue, Oct 1, 2019 at 5:45 AM Kristof Beyls <Kristof.Beyls at arm.com>
> wrote:
> >
> > > Hi,
> > >
> > > I’ve been investigating https://bugs.llvm.org/show_bug.cgi?id=43374,
> > > which is about clang/llvm producing code that triggers a floating point
> > > exception when x is NaN, when targeting ARM, in the below code example.
> > >
> > > int bar(float x) {
> > >   return x!=x ? 0 : 1;
> > > }
> > >
> > > The C99 standard states in section 7.12.14:
> > >
> > > """
> > > The relational and equality operators support the usual mathematical
> > > relationships between numeric values. For any ordered pair of numeric
> > > values exactly one of the relationships — less, greater, and equal — is
> > > true. Relational operators may raise the ‘‘invalid’’ floating-point
> > > exception when argument values are NaNs.
> > > """
> > >
> > > My interpretation of that paragraph is that it's OK for <, <=, > and
> >= to
> > > raise an exception when argument values are NaNs. It is not OK for ==
> an !=
> > > to raise an exception when argument values are NaNs.
> > >
> > > Therefore,
> > >
> > > int bar(float x) {
> > >   return x!=x ? 0 : 1;
> > > }
> > >
> > > should not produce an exception when x is NaN, and hence a vcmp rather
> > > than vcmpe instruction should be produced when generating ARM code for
> > > this.
> > >
> > > http://llvm.org/viewvc/llvm-project?rev=294945&view=rev introduced
> > > support for generating vcmp instead of vcmpe for equality comparisons.
> > > How come vcmpe is generated for (x!=x)?
> > >
> > > The answer is that InstCombine transforms the equality comparison into
> an
> > > "ordered comparison”. Before InstCombine:
> > > define dso_local i32 @bar(float %x) local_unnamed_addr {
> > > entry:
> > >   %cmp = fcmp une float %x, %x
> > >   %cond = select i1 %cmp, i32 0, i32 1
> > >   ret i32 %cond
> > > }
> > >
> > > After InstCombine:
> > > define dso_local i32 @bar(float %x) local_unnamed_addr #0 {
> > > entry:
> > >   %cmp = fcmp ord float %x, 0.000000e+00
> > >   %cond = zext i1 %cmp to i32
> > >   ret i32 %cond
> > > }
> > >
> > > Please note that on other backends like x86 or AArch64, this
> InstCombine
> > > doesn’t trigger floating point exception behaviour since those backends
> > > don’t seem to be producing any instructions for fcmp that raise
> floating
> > > point exceptions on NaNs.
> > >
> > > My question here is: how to fix this behaviour? Or: which part in the
> > > compilation flow is wrong?
> > > Reading through various standards and specifications, I’m getting
> confused
> > > to what the best fix would be:
> > >
> > >
> > >    - https://llvm.org/docs/LangRef.html#floating-point-environment
> states
> > >    "The default LLVM floating-point environment assumes that
> > >    floating-point instructions do not have side effects. Results
> assume the
> > >    round-to-nearest rounding mode. No floating-point exception state is
> > >    maintained in this environment. Therefore, there is no attempt to
> create or
> > >    preserve invalid operation (SNaN) or division-by-zero exceptions.”
> > >    This suggests that if we want to retain floating point exception
> > >    behaviour in the compilation flow, we shouldn’t be using the
> “default LLVM
> > >    floating-point environment”, but rather something else. Presumably
> the
> > >    constrained intrinsics? However, when I look at the constrained
> intrinsics
> > >    definition, it seems (
> > >
> http://llvm.org/docs/LangRef.html#constrained-floating-point-intrinsics)
> > >    there is no constrained intrinsic for the floating point comparison
> > >    operation. Should there be one?
> > >    - If the default floating-point environment assumes that
> > >    floating-point instructions do not have side effects, why does the
> Arm
> > >    backend lower floating point comparison to vcmpe rather than vcmp?
> The
> > >    revision history suggests this has been this way since the initial
> creation
> > >    of the ARM backend. Should this behaviour be changed and vcmp be
> produced
> > >    rather than vcmpe? And only later, once the generation of
> constrained
> > >    floating point intrinsics is implemented should backends start
> producing
> > >    signalling floating point comparisons for floating point comparison
> > >    constrained intrinsics (assuming they’ll exist by then)?
> > >    - Or alternatively, there is a good reason to keep on producing
> vcmpe
> > >    as is today, and instcombine just shouldn’t convert “fcmp une” into
> “fcmp
> > >    ord”?
> > >    - Or as yet another alternative, instcombine is just fine converting
> > >    “fcmp une” into “fcmp ord”, and it’s the ARM backend that should
> produce
> > >    vcmp rather than vcmpe also for “unordered” comparisons, next to
> equality
> > >    comparisons?
> > >
> > >
> > > Thanks,
> > >
> > > Kristof
> > >
>
> > _______________________________________________
> > 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/20191008/d429cbbf/attachment.html>


More information about the llvm-dev mailing list