#include <stdio.h>
#include <math.h>

int main()
{
        double a= 10.0;
        double b= 1e+308;
        printf("%d %d %d\n", isinf(a*b), __builtin_isinf(a*b), __isinf(a*b));
        return 0;
}

mtay...@drizzle-dev:~$ gcc -o test test.c 
mtay...@drizzle-dev:~$ ./test
0 0 1
mtay...@drizzle-dev:~$ gcc -o test test.c -std=c99
mtay...@drizzle-dev:~$ ./test
1 0 1
mtay...@drizzle-dev:~$ gcc -o test test.c   -mfpmath=sse -march=pentium4
mtay...@drizzle-dev:~$ ./test
1 1 1
mtay...@drizzle-dev:~$ g++ -o test test.c 
mtay...@drizzle-dev:~$ ./test
1 0 1


Originally I found the simple isinf() case to be different on x86 than x86-64,
ppc32 and sparc (32 and 64).

After more research, I found that x86-64 uses the sse instructions to do it
(and using sse is the only way for __builtin_isinf() to produce correct
results). For the g++ built version, it calls __isinf() instead of inlining
(and as can be seen, the __isinf() version is always correct).

Specifically, it's because the optimised 387 code is doing the math in double
extended precision inside the FPU. 10.0*1e308 fits in 80bits but not in 64bit.
Any code that forces it to be stored and loaded gets the correct result too.
e.g.

mtay...@drizzle-dev:~$ cat test-simple.c
#include <stdio.h>
#include <math.h>

int main()
{
        double a= 10.0;
        double b= 1e+308;
        volatile        double c= a*b;
        printf("%d\n", isinf(c));
        return 0;
}
mtay...@drizzle-dev:~$ gcc -o test-simple test-simple.c 
mtay...@drizzle-dev:~$ ./test-simple 
1

With this code you can easily see the load and store:
 8048407:       dc 0d 18 85 04 08       fmull  0x8048518
 804840d:       dd 5d f0                fstpl  -0x10(%ebp)
 8048410:       dd 45 f0                fldl   -0x10(%ebp)
 8048413:       d9 e5                   fxam   

While if you remove volatile, the load and store doesn't happen (at least on
-O3, on -O0 it hasn't been optimised away):
 8048407:       dc 0d 18 85 04 08       fmull  0x8048518
 804840d:       c7 44 24 04 10 85 04    movl   $0x8048510,0x4(%esp)
 8048414:       08 
 8048415:       c7 04 24 01 00 00 00    movl   $0x1,(%esp)
 804841c:       d9 e5                   fxam   


This is also a regression from 4.2.4 as it just calls isinf() and doesn't
expand the 387 code inline. My guess is the 387 optimisation was added in 4.3.

Recommended fix: store and load in the 387 version so to operate on same
precision as elsewhere.


-- 
           Summary: 387 optimised __builtin_isinf() gives incorrect result
           Product: gcc
           Version: 4.3.2
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: regression
        AssignedTo: unassigned at gcc dot gnu dot org
        ReportedBy: stewart at flamingspork dot com
 GCC build triplet: gcc version 4.3.2 (Ubuntu 4.3.2-1ubuntu12)
  GCC host triplet: i486-linux-gnu
GCC target triplet: i486-linux-gnu


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=39228

Reply via email to