This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug target/55939] [4.6/4.7/4.8 regression] gcc miscompiles gmp-5.0.5 on m68k-linux
- From: "aldyh at gcc dot gnu.org" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: Tue, 29 Jan 2013 17:26:46 +0000
- Subject: [Bug target/55939] [4.6/4.7/4.8 regression] gcc miscompiles gmp-5.0.5 on m68k-linux
- Auto-submitted: auto-generated
- References: <bug-55939-4@http.gcc.gnu.org/bugzilla/>
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55939
--- Comment #11 from Aldy Hernandez <aldyh at gcc dot gnu.org> 2013-01-29 17:26:46 UTC ---
In adding debugging printfs throughout a locally reduced testcase, I ran into
something peculiar, that may or may not be related to this PR. Perhaps some
floating point savvy person comment?
double d, d2;
...
if (d != d2) {
dumpd(d,d2);
return -1;
}
By this point, "d" and "d2" are in fp2/fp3, and we compare them in
extended-precision real mode (fcmp.x) below:
(gdb) si
0x80000670 154 if (d != d2)
1: x/i $pc
=> 0x80000670 <check_random+260>: fcmpx %fp3,%fp2
(gdb) info reg fp2
fp2 9.5869038983080764131982923476680188e-94 (raw
0x3ec90000fff801fffff84000)
(gdb) info reg fp3
fp3 9.5869038983080764090401284414100591e-94 (raw
0x3ec90000fff801fffff83ff8)
Notice above that the registers are slightly different, so d != d2.
(gdb) si
0x80000674 154 if (d != d2)
1: x/i $pc
=> 0x80000674 <check_random+264>: fbne 0x80000692 <check_random+294>
(gdb)
156 dumpd(d,d2);
1: x/i $pc
=> 0x80000692 <check_random+294>: fmoved %fp2,%sp@-
(gdb) si
0x80000696 156 dumpd(d,d2);
1: x/i $pc
=> 0x80000696 <check_random+298>: fmoved %fp3,%sp@-
(gdb)
0x8000069a 156 dumpd(d,d2);
1: x/i $pc
=> 0x8000069a <check_random+302>: jsr 0x80000508 <dumpd>
Notice we pass fp2/fp3 in the stack as arguments to dumpd(). Interestingly, we
move them with fmove.d which is double-precision (instead of the compare we did
prior in .x mode).
With dumpd() implemented as below, "a" will be the same as "b", since we
chopped off some bits with the fmove.d explained above.
void dumpd(double a, double b)
{
...
if (a == b)
dump_same();
...
...
}
dumpd() gets executed as follows:
1: x/i $pc
=> 0x8000050c <dumpd+4>: fmoved %fp@(8),%fp1
(gdb)
0x80000512 90 {
1: x/i $pc
=> 0x80000512 <dumpd+10>: fmoved %fp@(16),%fp0
(gdb) info reg fp1
fp1 9.5869038983080764131982923476680188e-94 (raw
0x3ec90000fff801fffff84000)
(gdb) info reg fp0
fp0 9.5869038983080764131982923476680188e-94 (raw
0x3ec90000fff801fffff84000)
Notice fp0 and fp1 are now the same.
(gdb)
93 if (a == b)
1: x/i $pc
=> 0x80000528 <dumpd+32>: fcmpx %fp0,%fp1
(gdb)
0x8000052c 93 if (a == b)
1: x/i $pc
=> 0x8000052c <dumpd+36>: fbeq 0x80000538 <dumpd+48>
(gdb)
110 }
1: x/i $pc
=> 0x80000538 <dumpd+48>: unlk %fp
etc etc etc.
I'm a bit flaky as to FP standards, but it seems suspect that two values that
are different, suddenly become the same when passed to a function.
Is this one of those FP quirks, and I'm horrendously misguided?