First Last Prev Next    No search results available
Details
: [llvmgcc] floating-point unary minus is incorrect for +0.0
Bug#: 216
: tools
: llvm-gcc
Status: RESOLVED
Resolution: FIXED
: All
: All
: 1.0
: P2
: normal
: 1.2

:
: miscompilation
: 218
:
  Show dependency tree - Show dependency graph
People
Reporter: Michael Kahl <mkahl@apple.com>
Assigned To: Chris Lattner <sabre@nondot.org>

Attachments
test case (minus.c) (705 bytes, text/plain)
2004-01-30 11:42, Michael Kahl
Details


Note

You need to log in before you can comment on or make changes to this bug.

Related actions


Description:   Opened: 2004-01-30 11:39
LLVM does not have unary operators, so unary minus is emulated as "0 - x". 
This is not correct for IEEE 
floating-point numbers.

In particular, the negation of "0.0" should be "-0.0", not "0.0", because
positive and negative zeroes are 
distinct in IEEE.  I will attach a test program that illustrates this
difference.

I don't know whether LLVM's treatment is also incorrect for NaN's and Inf's...

On the PowerPC, this could be easily fixed by emulating floating-point unary
minus as "-0.0 - x" (rather 
than "+0.0 - x").  However, (a) I don't know whether this also works for NaN's
and Inf's, and (b) I don't 
know whether this works in general on other processors.

You may need to rethink the decision to omit true unary operators from the LLVM
IR.

You could argue that IEEE floating-point is not a strict requirement of the
C/C++ standards, but in 
practice that is what people expect (and get, from gcc).
------- Comment #1 From Michael Kahl 2004-01-30 11:42:55 -------
Created an attachment (id=68) [details]
test case (minus.c)

Compile this and run with arguments (e.g.): 3.14 -3.14 0.0 -0.0

Using gcc, all 4 tests say "ok".

With llvm-gcc, one of the tests (0.0) fails.
------- Comment #2 From Chris Lattner 2004-01-30 12:18:06 -------
You are absolutely correctly: this needs to be addressed.  There are also other
missing pieces, such as support for unordered comparisons, though that is less
glaring of an ommission.

My current plan is for the Add,Sub,Mul,Div, & Rem operators to all indicate
"non-strict" or "fast" operators when used on floating point operands.  This
would mean, for example, that all of the LLVM transformations could treat
Add/Mul as if there were associative, regardless of whether the operands were
floating point or not.  To support strict floating point, new operators would be
added 'addfp', 'negfp', ... ? Which would be required to support IEEE semantics
precisely.

I think that this is a good balance between supporting things like non-strict FP
in Java, GCC's -ffast-math, etc... while still maintaining good support for
numerical programming.

Do you think this would solve the problem as you see it?  If so, do you want to
come up with a minimal recommended list of operators to add?

-Chris

ps, on X86 at least, GCC does not come close to providing "what people expect"
from IEEE math, even with -ffloat-store.  :(  Not that that is a reason for LLVM
to be as bad.  At least the LLVM register allocation decisions cannot effect
results.
------- Comment #3 From Chris Lattner 2004-02-01 02:25:31 -------
The more I read up about this, the more I believe that compiling negation into
'-0.0 - X' is correct for all IEEE machines.  Unfortunately, I can't find proof
of this on google.  I'm inclined to change the C front-end in the meantime, as
+0.0 - X certainly isn't correct.  What do you think, is there anyone that you
know who might know for certain?

-Chris
------- Comment #4 From Chris Lattner 2004-02-02 11:45:04 -------
I surreptitiously started a thread on the GCC list about this topic, and got the
following response from Geoff Keating:

"""I looked this up.  '-0.0 - X' is the same as '-0.0 + (-X)'.  When -X
!= 0.0, the result will be -X, so that's OK.  Suppose X is +/- 0.0.
Then the following rules apply:

- If both operands have the same sign, the sign of the result is the
  same as the sign of the operands.  So if X is +0.0, you'll get -0.0,
  the same as -X.

- If the sum of two operands with opposite sign is exactly zero, the
  sign is positive in all rounding modes except round towards -Inf, in
  which case the sign is negative.  So, if X is -0.0, you'll get
  +0.0, the same as -X, *unless* we're rounding towards -Inf.

Thus, the answer to your question is "no".  The case that differs is
when X is -0.0 and the rounding mode is towards -Inf."""


Which I interpret to mean "yes", it's the same in all cases except when the
rounding mode is tweaked to be -Inf, which is not the default.  As this is the
case, I've commited the following patch to the CFE:
http://mail.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20040202/011060.html

Note that will still will eventually need "strict" vs "non-strict" floating
point operators, particularly to support languages like Fortran and Java well.

-Chris
------- Comment #5 From Michael Kahl 2004-02-03 18:44:36 -------
The proposed patch does NOT fix the bug.  Specifically, the test case still
fails with argument "0.0".

It looks like the front end is now getting it right:

        % llvm-gcc -S minus.c
        % fgrep 'sub double' minus.s
                %tmp.1 = sub double -0.0, %tmp.0                 ; ty=double

So far, so good.  But:

        % llvm-gcc -c -Wa,-disable-opt minus.c
        % llvm-dis -o - minus.o | fgrep 'sub double'
                %tmp.1 = sub double 0x0, %tmp.0         ; <double> [#uses=1]
------- Comment #6 From Chris Lattner 2004-02-03 18:57:56 -------
It works for me:

$ llvmgcc test4.c -c -o - | lli - 0.0
WARNING: Cannot resolve fn '__main' using a dummy noop function instead!
 x =  0.000000
-x = -0.000000
ok
$ llvmgcc test4.c -c -o - | llvm-dis | grep 'sub'
        %tmp.1 = sub double 0x8000000000000000, %x              ; <double> [#uses=1]

Make sure that your tree includes the patches for Bug 218, which is related to
-0.0 handling.

If this helps, please reclose the bug.

-Chris
------- Comment #7 From Michael Kahl 2004-02-03 20:41:09 -------
So sorry!  I didn't realize I also had to install those other patches.  D'oh...

Yes, it works.  Reclosed.

First Last Prev Next    No search results available