[llvm-bugs] [Bug 26931] New: x87 single precision float underflow hidden (by incorrect double precision store?)

via llvm-bugs llvm-bugs at lists.llvm.org
Sun Mar 13 16:23:17 PDT 2016


https://llvm.org/bugs/show_bug.cgi?id=26931

            Bug ID: 26931
           Summary: x87 single precision float underflow hidden (by
                    incorrect double precision store?)
           Product: new-bugs
           Version: trunk
          Hardware: PC
                OS: All
            Status: NEW
          Severity: normal
          Priority: P
         Component: new bugs
          Assignee: unassignedbugs at nondot.org
          Reporter: dimitry at andric.com
                CC: llvm-bugs at lists.llvm.org
    Classification: Unclassified

Recently on the FreeBSD toolchain mailing list, Steve Kargl posted a
test case [1] which shows that clang appears to mask, or hide, x87
single precision float underflows.

The test case is simple enough to post it directly in this description:

#include <fenv.h>
#include <stdio.h>

__attribute__((__noinline__))
float foo()
{
  static const volatile float tiny = 1.e-30f;
  return (tiny * tiny);
}

int main(void)
{
  float x;
  feclearexcept(FE_ALL_EXCEPT);
  x = foo();
  if (fetestexcept(FE_UNDERFLOW))
    printf("FE_UNDERFLOW: ");
  printf("x = %e\n", x);
  return 0;
}

So when the multiplication is executed, it underflows a single precision
float, and this should generate an FE_UNDERFLOW.  With gcc (I tested
5.3.0) this works as expected.

But with clang trunk r263389, what appears to happen is that it either
stores the FP status word directly after an fmul (which does *not*
generate an underflow, since it stores the result in a double precision
register), or it uses fstpl to store the result as double precision,
again not generating an underflow.

E.g. with clang -m32 -O2 -S, the following assembly is the result:

foo:
        flds    foo.tiny
        fmuls   foo.tiny
        retl
[...]
main:
[...]
        calll   feclearexcept
        calll   foo
        fstpl   20(%esp)                # 8-byte Folded Spill
        movl    $16, (%esp)
        calll   fetestexcept
        testl   %eax, %eax

So while the fmuls might generate an underflow, the result from the call
to foo() is then stored using fstpl, which also affects the FP status
register, thus probably clearing the underflow.  It appears as if clang
is (incorrectly?) using an intermediate value with greater precision.

In contrast, with gcc -m32 -O2 -S, the following assembly results:

foo:
        flds    tiny.2247
        flds    tiny.2247
        fmulp   %st, %st(1)
        ret
[...]
main:
[...]
        call    feclearexcept
        call    foo
        movl    $16, (%esp)
        fstps   12(%esp)
        call    fetestexcept
        testl   %eax, %eax

E.g. here the result of foo() is stored using fstps, which generates an
underflow.  This can then be detected through fetestexcept().

The outcome of this sample is clearly incorrect in clang's case, and it
seems it should store the function result in a single precision floating
point value, not a double precision one.

[1]
https://lists.freebsd.org/pipermail/freebsd-toolchain/2016-March/002077.html

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20160313/04322696/attachment.html>


More information about the llvm-bugs mailing list