[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 1 06:44:54 PDT 2019

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).

As IR from clang with no optimization, this becomes a bunch of load/store
  %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.

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.

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?

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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20191001/37031e40/attachment-0001.html>

More information about the llvm-dev mailing list