Quuxplusone / LLVMBugzillaTest

0 stars 0 forks source link

Regression: NaN handling differs from LLVM 3.1-3.3 #18047

Open Quuxplusone opened 10 years ago

Quuxplusone commented 10 years ago
Bugzilla Link PR18048
Status NEW
Importance P release blocker
Reported by Kai Nacke (kai@redstar.de)
Reported on 2013-11-24 15:15:33 -0800
Last modified on 2013-12-06 01:41:23 -0800
Version trunk
Hardware PC Windows NT
CC llvm-bugs@lists.llvm.org, mgottesman@apple.com
Fixed by commit(s)
Attachments bug.ll (1527 bytes, application/octet-stream)
nan.c (293 bytes, text/plain)
Blocks
Blocked by
See also
Created attachment 11601
IR file demonstrating the problem.

The attached IR code is reduced from a D program. It can be compiled and run on
Linux/x86_64.

Compiled with llc -filetype=obj bug.ll ; gcc -o bug bug.o ; ./bug it produces
the output:

0000ffff - 0000ffff

but compiled with opt -O3 <bug.ll | llc -filetype=obj >bug.o ; gcc -o bug bug.o
; ./bug it produces the output:

0000ffff - 00007fff

The root cause seems to be that -real.nan is negativ but 2* -real.nan is
positiv (with -O3). That is really surprising.

The original D program is:
import core.stdc.stdio : printf;

ushort sign(real x)
{
    ushort* pxe = cast(ushort *)&x;
    return pxe[4];
}

void main()
{
    real x = -real.nan;
    real y = 2*x;
    printf("%08x - %08x\n", sign(x), sign(y));
}

This happens only with LLVM3.4+, not with LLVM 3.1/3.2/3.3.
Quuxplusone commented 10 years ago

Attached bug.ll (1527 bytes, application/octet-stream): IR file demonstrating the problem.

Quuxplusone commented 10 years ago
This also affects clang. The attached C file produces different results if
compiled with gcc-4.8.2 and clang-3.4 on Linux/x86_64.
Again, the sign bit is lost.
Quuxplusone commented 10 years ago

Attached nan.c (293 bytes, text/plain): C file which produces different output if compiled by gcc and clang.

Quuxplusone commented 10 years ago

I think commit r187314 introduced this behavior.

Michael, I set you on CC because you are the author of this commit.

Is this really the indented functionality?

Quuxplusone commented 10 years ago

Yes that is the intended behavior and is the result of a compromise. Let me explain:

APFloat is IEEE-754 conformant (or if it violates the standard in some way, that is a bug, please file it = p).

IEEE-754 1.4 states that the interpretation of the sign and significant fields of a NaN are not specified by the standard. So one should not assume any behavior in general from a negative NaN.

Thus APFloat does not interpret/use the sign field of a NaN and for any operation that yields a NaN will only produce one form of NaN: +NaN.

On the other hand, as a compromise, if the user creates an APFloat that is a negative NaN and does not perform any operations on it we just let it through.

Does that answer your question?

Quuxplusone commented 10 years ago

Yes, it answers my question.

I am not really happy with this because

(1) gcc and clang now produce different results (at least on x86)

(2) The x86 fpu works differently

(3) as a consequence of (2), you get different results if you compile code with or without optimization. This makes debugging harder.

But I was able to fix the upstream sources. :-)