This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
assignment problem with doubles: getting -NaN unexpectedly
- To: gcc-bugs at gcc dot gnu dot org
- Subject: assignment problem with doubles: getting -NaN unexpectedly
- From: Karl Ostner <micha_und_karl at vr-web dot de>
- Date: Fri, 08 Oct 1999 19:54:29 +0200
Hi,
I have a problem with an assigment of one double variable to another,
like dub1 = dub2;
I'm getting -NaN in dub1, even if there is a valid value in dub2.
This is on RedHat Linux 6.0, kernel 2.2.5, glibc-2.1.1-6
C compiler is egcs-2.91.66 19990314/Linux (egcs-1.1.2 release)
(not the newest, I know).
Also tried compiling the relevant file with egcs-1.1.2-24,
which did not help.
HW is 2 x Pentium II, FPU.
this is the compiler call:
cc -g -ansi -fwritable-strings -DLINUX -D_BSD_SOURCE -Wall
-Wno-parentheses -Wno-unused -Wno-return-type -Wno-implicit-int
rvaldata.c
Here is a gdb session that shows the difference between a working
and a non working case:
Breakpoint 2, todouble (val=0x1085e094) at rvaldata.c:1445
1445 dub = val->v_double;
(gdb) info registers
eax: 0x80e3c70 135150704
ecx: 0x10850003 277151747
edx: 0x86a0003 141164547
ebx: 0x1085e094 277209236
esp: 0x1085d5d8 277206488
ebp: 0x1085d61c 277206556
esi: 0x108a8a88 277514888
edi: 0x10803060 276836448
eip: 0x80e3c70 135150704
eflags: 0x297 IOPL: 0; flags: CF PF AF SF IF
orig_eax: 0xffffffff -1
cs: 0x23 35
ss: 0x2b 43
ds: 0x2b 43
es: 0x2b 43
fs: 0x0 0
gs: 0x0 0
(gdb) info float
st0: 0x40008000000000000000 Valid Normal 2
st1: 0x4000c000000000000000 Valid Normal 3
st2: 0x40008000000000000000 Valid Normal 2
st3: 0x4000c000000000000000 Valid Normal 3
st4: 0x40008000000000000000 Valid Normal 2
st5: 0x4000c000000000000000 Valid Normal 3
st6: 0x40008000000000000000 Valid Normal 2
st7: 0x3fff8000000000000000 Empty Normal 1
fctrl: 0x037f 64 bit; NEAR; mask INVAL DENOR DIVZ OVERF UNDER
LOS;
fstat: 0x0863 flags 0000; top 1; excep INVAL DENOR LOS STACK
ftag: 0x0003
fip: 0x400154ae
fcs: 0x05400023
fopoff: 0x108a87a8
fopsel: 0x002b
(gdb) disass 0x80e3c70 0x80e3c7b
Dump of assembler code from 0x80e3c70 to 0x80e3c7b:
0x80e3c70 <todouble+712>: fldl 0xc(%ebx)
0x80e3c73 <todouble+715>: fstpl 0xfffffff8(%ebp)
0x80e3c76 <todouble+718>: jmp 0x80e3d13 <todouble+875>
End of assembler dump.
(gdb) p val->v_double
$1 = 2
(gdb) p &val->v_double
$2 = (double *) 0x1085e0a0
(gdb) x/2 &val->v_double
0x1085e0a0: 0x00000000 0x40000000
(gdb) stepi
0x80e3c73 1445 dub = val->v_double;
(gdb) info float
st0: 0x40008000000000000000 Valid Normal 2
st1: 0x40008000000000000000 Valid Normal 2
st2: 0x4000c000000000000000 Valid Normal 3
st3: 0x40008000000000000000 Valid Normal 2
st4: 0x4000c000000000000000 Valid Normal 3
st5: 0x40008000000000000000 Valid Normal 2
st6: 0x4000c000000000000000 Valid Normal 3
st7: 0x40008000000000000000 Valid Normal 2
fctrl: 0x037f 64 bit; NEAR; mask INVAL DENOR DIVZ OVERF UNDER
LOS;
fstat: 0x0063 flags 0000; top 0; excep INVAL DENOR LOS STACK
ftag: 0x0000
fip: 0x080e3c70
fcs: 0x05430023
fopoff: 0x1085e0a0
fopsel: 0x002b
(gdb) stepi
1446 break;
(gdb) info float
st0: 0x40008000000000000000 Valid Normal 2
st1: 0x4000c000000000000000 Valid Normal 3
st2: 0x40008000000000000000 Valid Normal 2
st3: 0x4000c000000000000000 Valid Normal 3
st4: 0x40008000000000000000 Valid Normal 2
st5: 0x4000c000000000000000 Valid Normal 3
st6: 0x40008000000000000000 Valid Normal 2
st7: 0x40008000000000000000 Empty Normal 2
fctrl: 0x037f 64 bit; NEAR; mask INVAL DENOR DIVZ OVERF UNDER
LOS;
fstat: 0x0863 flags 0000; top 1; excep INVAL DENOR LOS STACK
ftag: 0x0003
fip: 0x080e3c73
fcs: 0x055d0023
fopoff: 0x1085d614
fopsel: 0x002b
(gdb) print dub
$3 = 2
(gdb) p &dub
$4 = (double *) 0x1085d614
(gdb) x/2 &dub
0x1085d614: 0x00000000 0x40000000
The correct value was assigned.
Now the bad case:
(gdb) c
Continuing.
Breakpoint 2, todouble (val=0x1085e094) at rvaldata.c:1445
1445 dub = val->v_double;
(gdb) info registers
eax: 0x80e3c70 135150704
ecx: 0x10850003 277151747
edx: 0x86a0003 141164547
ebx: 0x1085e094 277209236
esp: 0x1085d5d8 277206488
ebp: 0x1085d61c 277206556
esi: 0x108a8a88 277514888
edi: 0x10803060 276836448
eip: 0x80e3c70 135150704
eflags: 0x297 IOPL: 0; flags: CF PF AF SF IF
orig_eax: 0xffffffff -1
cs: 0x23 35
ss: 0x2b 43
ds: 0x2b 43
es: 0x2b 43
fs: 0x0 0
gs: 0x0 0
(gdb) info float
st0: 0x4000c000000000000000 Valid Normal 3
st1: 0x40008000000000000000 Valid Normal 2
st2: 0x4000c000000000000000 Valid Normal 3
st3: 0x40008000000000000000 Valid Normal 2
st4: 0x4000c000000000000000 Valid Normal 3
st5: 0x40008000000000000000 Valid Normal 2
st6: 0x4000c000000000000000 Valid Normal 3
st7: 0x40008000000000000000 Valid Normal 2
fctrl: 0x037f 64 bit; NEAR; mask INVAL DENOR DIVZ OVERF UNDER
LOS;
fstat: 0x0063 flags 0000; top 0; excep INVAL DENOR LOS STACK
ftag: 0x0000
fip: 0x400154ae
fcs: 0x05400023
fopoff: 0x108a87a8
fopsel: 0x002b
(gdb) disass 0x80e3c70 0x80e3c7b
Dump of assembler code from 0x80e3c70 to 0x80e3c7b:
0x80e3c70 <todouble+712>: fldl 0xc(%ebx)
0x80e3c73 <todouble+715>: fstpl 0xfffffff8(%ebp)
0x80e3c76 <todouble+718>: jmp 0x80e3d13 <todouble+875>
End of assembler dump.
(gdb) p val->v_val.vdub
$5 = 3
(gdb) p &val->v_val.vdub
$6 = (double *) 0x1085e0a0
(gdb) x/2 &val->v_val.vdub
0x1085e0a0: 0x00000000 0x40080000
(gdb) stepi
0x80e3c73 1445 dub = val->v_double;
The fldl machine instruction does not place the expected value into st0.
Is this because of some FPU flags?
This may be a compiler bug, but I don't know.
Now, I'm getting the unexpected value in st0:
(gdb) info float
st0: 0xffffc000000000000000 Spec QNaN -NaN(0xc000000000000000)
st1: 0x4000c000000000000000 Valid Normal 3
st2: 0x40008000000000000000 Valid Normal 2
st3: 0x4000c000000000000000 Valid Normal 3
st4: 0x40008000000000000000 Valid Normal 2
st5: 0x4000c000000000000000 Valid Normal 3
st6: 0x40008000000000000000 Valid Normal 2
st7: 0x4000c000000000000000 Valid Normal 3
fctrl: 0x037f 64 bit; NEAR; mask INVAL DENOR DIVZ OVERF UNDER
LOS;
fstat: 0x3a63 flags 0010; top 7; excep INVAL DENOR LOS STACK
ftag: 0x8000
fip: 0x080e3c70
fcs: 0x05430023
fopoff: 0x1085e0a0
fopsel: 0x002b
(gdb) stepi
1446 break;
(gdb) info float
st0: 0x4000c000000000000000 Valid Normal 3
st1: 0x40008000000000000000 Valid Normal 2
st2: 0x4000c000000000000000 Valid Normal 3
st3: 0x40008000000000000000 Valid Normal 2
st4: 0x4000c000000000000000 Valid Normal 3
st5: 0x40008000000000000000 Valid Normal 2
st6: 0x4000c000000000000000 Valid Normal 3
st7: 0xffffc000000000000000 Empty QNaN -NaN(0xc000000000000000)
fctrl: 0x037f 64 bit; NEAR; mask INVAL DENOR DIVZ OVERF UNDER
LOS;
fstat: 0x0063 flags 0000; top 0; excep INVAL DENOR LOS STACK
ftag: 0xc000
fip: 0x080e3c73
fcs: 0x055d0023
fopoff: 0x1085d614
fopsel: 0x002b
(gdb) print dub
$7 = -NaN(0x8000000000000)
(gdb) p &dub
$8 = (double *) 0x1085d614
(gdb) x/2 &dub
0x1085d614: 0x00000000 0xfff80000
Are there any known compiler bugs causing this?
There are two scenarios which are reproducing this problem.
I did some code changes which did not help:
1. add -O or -O0, did not work
2. add register to the definition of the local variable:
this solves the first scenario (!) but the second fails
3. add -mno-fp-ret-in-387 compiler switch, and compile the
relevant file only.
this solves the second scenario, but the first fails
4. add -mno-fp-ret-in-387 compiler switch, and compile all
files of my lib this files belongs to:
both scenarios fail !
5. substitute assignment by a memcpy()
This helps directly for this function, but the problem
occurs in the next assignment of a double value.
6. add -ffloat-store compiler switch, does not help
Pls reply to: kostner@informix.com.
Thanks in advance for your help,
Karl Ostner