Mapping NAN to ZERO / When does gcc generate MOVcc and FCMOVcc instructions?
Michael James
james.me@gmail.com
Fri Nov 3 20:28:00 GMT 2006
On 11/2/06, Uros Bizjak <ubizjak@gmail.com> wrote:
>
> This testcase (similar to yours, but it actually compiles):
>
Hello,
Uros, thank you for the attention to my problem. I upgraded gcc to 4.2
and have been using -march=i686 instead of -march=pentium4 for my
tests now. gcc 4.2 resolved some but not all of my concerns. Please
see below.
> double test(int n, double a)
> {
> double sum = 0.0;
> int i;
>
> for(i=0; i<n; ++i)
> {
> float x = logf((float)i);
> sum += isnan(x) ? 0 : x;
> }
>
> return sum;
> }
>
> produces exactly the code you are looking for (using gcc-4.2 with -march=i686):
>
> .L5:
> pushl %ebx
> fildl (%esp)
> addl $4, %esp
> fstps (%esp)
> fstpl -24(%ebp)
> call logf
> fucomi %st(0), %st
> fldz
> fcmovnu %st(1), %st
> fstp %st(1)
> addl $1, %ebx
> cmpl %esi, %ebx
> fldl -24(%ebp)
> faddp %st, %st(1)
> jne .L5
>
I was unable to replicate your results with gcc 4.0.3, so I installed
gcc 4.2.0 20061103 (prerelease) from SVN. Using that, I am able to
replicate the loop above exactly with
-O2 -march=i686. It looks like gcc 4.2 is willing to do this
optimization; gcc 4.0 would not. :-)
> logf() function will be inlined by specifying
> -funsafe-math-optimizations, this flag also enables implicit
> float->double extensions for x87 math. As you probably don't need math
> errno from log(), -fno-math-errno should be added.
>
> Those two flags produce IMO optimal loop:
>
> .L5:
> pushl %eax
> fildl (%esp)
> addl $4, %esp
> fldln2
> fxch %st(1)
> fyl2x
> fucomi %st(0), %st
> fldz
> fcmovnu %st(1), %st
> fstp %st(1)
> addl $1, %eax
> cmpl %edx, %eax
> faddp %st, %st(1)
> jne .L5
>
I have been unable to replicate this result. Still, gcc 4.0.3 and gcc
4.2.0 completely omit the fucomi test and the associated semantics
with testing for NAN:
I compiled exactly the verbatim test case above, and compile using these flags:
-O2 -march=i686 -funsafe-math-optimizations -fno-math-errno
The loop I get is:
.L5:
pushl %eax
addl $1, %eax
fildl (%esp)
addl $4, %esp
cmpl %edx, %eax
fldln2
fxch %st(1)
fyl2x
faddp %st, %st(1)
jne .L5
Now, for this particular code, that loop may be considered a valid
optimization because log can not produce NAN from a non-negative
parameter. To be sure, I then modified the code as follows:
double test(int i0, int n, double a)
{
double sum = 0.0;
int i;
for(i=i0; i<n; ++i)
{
float x = logf((float)i);
sum += isnan(x) ? 0 : x;
}
return sum;
}
And recompiled with the same flags. The assembly code for the loop
portion is identical to the one I posted above. Now though the code is
actually capable of producing NANs.
Just to be sure, I also tested this on my modified loop:
int main(void) {
printf("test(4, 6, 0) = %f\n", test(4,6,0));
printf("test(0, 2, 0) = %f\n", test(0,2,0));
printf("test(-2, 3, 0) = %f\n", test(-2,3,0));
return 0;
}
james@recoil:~/project/cf/util$ /home/james/local/gcc/bin/gcc -O2
-march=i686 -funsafe-math-optimizations -fno-math-errno uros-test.c -o
test
james@recoil:~/project/cf/util$ ./test
test(4, 6, 0) = 2.995732
test(0, 2, 0) = -inf
test(-2, 3, 0) = nan
james@recoil:~/project/cf/util$ /home/james/local/gcc/bin/gcc -O2
-march=i686 uros-test.c -o test -lm
james@recoil:~/project/cf/util$ ./uros
test(4, 6, 0) = 2.995732
test(0, 2, 0) = -inf
test(-2, 3, 0) = -inf
james@recoil:~/project/cf/util$ /home/james/local/gcc/bin/gcc -v
Using built-in specs.
Target: i686-pc-linux-gnu
Configured with: ../gcc-4-2/configure --prefix=/home/james/local/gcc
Thread model: posix
gcc version 4.2.0 20061103 (prerelease)
Perhaps I have not replicated your working environment closely enough,
or you have a different macro in place of the isnan call. I compiled
all code above both with and without include headers <math.h>,
<stdio.h>. I get the same results either way.
Again, help is appreciated. -- Thanks.
Regards,
Michael James
More information about the Gcc
mailing list