This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
Floating point trouble on m68k
- To: egcs-bugs at egcs dot cygnus dot com
- Subject: Floating point trouble on m68k
- From: Kars de Jong <jongk at cs dot utwente dot nl>
- Date: Sat, 27 Mar 1999 12:54:58 +0100
Hello,
OS: Linux/m68k kernel version 2.2.3pre1
CPU: 68060
gcc version: all, tested with gcc 2.7.2.3 and egcs 1.1.2
Options to gcc: -O2 (not important)
First, let me include a mail I sent to the Linux/m68k mailing list which
provoked some discussion:
------------------------------------------------------------------------------
I'm working with the Blackdown Java porting team to get Linux/m68k a working
version of the Java Development Kit version 1.2.
Before I'm allowed to distribute it, I have to pass the Java Compatibility
Kit, and this is where my problems start.
I have a 68060 CPU, and 2 floating point tests fail. They both concern the
single precision float multiplication, fsglmul.s and denormalized results.
I have converted one of the testcases to C, and here's the result:
rounding is double, result = 0x640006, expected result = 0x640005
rounding is float, result = 0x640006, expected result = 0x640005
The test passes on Linux/x86 and Solaris/Sparc, however.
I am very curious whether this test also fails on the 68881/68882 copros.
If not, the 68060 FPSP has a bug, and I'll report it to Motorola.
I'm also very curious about the 68040, because that has denormalized numbers
handled in software as well.
So, could those of you that have a 68040, 68881 or 68882 please compile and
run this test and mail the results?
The test does pass if I use the soft-float implementation from libgcc1, by
the way. Which is what I will use as a workaround for now.
The status of the JDK on Linux/m68k is quite good already, by the way. I pass
over 98% of the JCK.
Kars.
Here's the test:
---- Cut here ----
#include <stdio.h>
#include <string.h>
unsigned long darr[] = { 0x800007, 0x3f480000, 0x640005 };
int main() {
float i, j, x;
unsigned long result, *darrp = darr;
#ifdef __i386__
asm(" pushl $575");
asm(" fldcw (%esp)");
asm(" addl $4,%esp");
#endif
#ifdef __mc68000__
asm(" fmovel #0x80,%fpcr");
#endif
memcpy(&i, darrp++, sizeof(float));
memcpy(&j, darrp++, sizeof(float));
x = i * j;
memcpy(&result, &x, sizeof(float));
printf("rounding is double, result = 0x%x, expected result = 0x%x\n", result, *darrp);
#ifdef __mc68000__
asm(" fmovel #0x40,%fpcr");
#endif
x = i * j;
memcpy(&result, &x, sizeof(float));
printf("rounding is float, result = 0x%x, expected result = 0x%x\n", result, *darrp);
return 0;
}
---- Cut here ----
------------------------------------------------------------------------------
Several people with a 68040 and 68881/2 tried the test, and they all got the
same results as me.
The relevant code section in this case is this, the multiplication:
fmove.s -4(%a6),%fp0
fsglmul.s -8(%a6),%fp0
fmove.s %fp0,-12(%a6)
After this I did a test. I made gcc output its assembler file, manually changed
the instruction it used (fsglmul.s) to fmul.s AND IT PASSES!
The Java language requires a strictly IEEE 754 compliant FPU, at double
precision (no more, no less) and using Round to Nearest rounding mode. This
is what I set the FPU to at the start of every thread, and the Intel port
does the same. Apparently using the fsglmul.s instruction for single
precision floating point is NOT equivalent to using fmul.s in terms of the
result, and I doubt this was intended, especially seeing in the .md file that
if compiling for a 68060 or 68040 the fsmul.s instruction is used (which makes
the test pass too).
My suggestion: don't use the fsgl variants of the mul and div instructions,
not even for single precision floats. Or at least have a flag like the Alpha
or Intel have for strict IEEE results. I'd prefer the former though.
Kars.
--
------------------------------------------------------------------------------
Kars de Jong Signaalkamp rules the waves! Turrican@Discworld
--------======]**-----| jongk@cs.utwente.nl |-----**[======---------