Re: -ffast-math in Ports and wrong generated code

From: Andrey Simonenko <simon_at_comsys.ntu-kpi.kiev.ua>
Date: Thu, 5 Apr 2012 09:46:10 +0300
On Wed, Apr 04, 2012 at 09:45:25AM -0500, Pedro Giffuni wrote:
> On 04/04/12 04:29, Andrey Simonenko wrote:
> > On Tue, Apr 03, 2012 at 06:43:00AM -0700, Steve Kargl wrote:
> >> On Tue, Apr 03, 2012 at 02:21:11PM +0300, Andrey Simonenko wrote:
> >>> I use one port from the Ports Collection, that works with FP.  Having
> >>> reinstalled it (its version was not changed) I noticed that it started
> >>> to work incorrectly.  After debugging and disassembling its code I found
> >>> out that the -ffast-math option used for building was the result of
> >>> wrongly generated code (I did not specify this option in /etc/make.conf).
> >>>
> >>> At least finite() function call was eliminated from the result Assembler
> >>> code when -ffast-math option is used, tested on 9.0-STABLE and 10.0-CURRENT.
> >>>
> >>> Example test source code and generated code under 9.0-STABLE on amd64
> >>> by gcc from the base system:
> >>>
> >>> -----------------------------
> >>> #include<math.h>
> >>> #include<stdio.h>
> >>>
> >>> void
> >>> check_finite(double x)
> >>> {
> >>> 	printf("%d\n", finite(x));
> >>> }
> >>> -----------------------------
> >>>
> >>> % gcc -Wall -O2 -S finite.c
> >>> -----------------------------
> >>> check_finite:
> >>> .LFB3:
> >>> 	subq	$8, %rsp
> >>> .LCFI0:
> >>> 	call	finite			<-- call to finite()
> >>> 	movl	$.LC0, %edi
> >>> 	movl	%eax, %esi
> >>> 	addq	$8, %rsp
> >>> 	xorl	%eax, %eax
> >>> 	jmp	printf
> >>> .LFE3:
> >>> 	.size	check_finite, .-check_finite
> >>> -----------------------------
> >>>
> >>> % gcc -Wall -O2 -ffast-math -S finite.c
> >>> -----------------------------
> >>> check_finite:
> >>> .LFB3:
> >>> 	xorl	%esi, %esi		<-- fake result from finite()
> >>> 	movl	$.LC0, %edi
> >>> 	xorl	%eax, %eax
> >>> 	jmp	printf
> >>> .LFE3:
> >>> 	.size	check_finite, .-check_finite
> >>> -----------------------------
> >>>
> >>> Can somebody comment this?
> >> Read the man page for gcc.  With --fast-math,
> >> gcc assumes that the result of any FP operation
> >> is finite.  So, the function call to finite()
> >> is eliminated as it is always true.
> > Looks like that I was misunderstood.  I did not ask why finite() was
> > eliminated, I asked why fake result from finite() is wrong.  Obviously
> > that -ffast-math can optimize FP arithmetics and as a result some functions
> > can be eliminated.  The problem is not respecting IEEE specifications for
> > FP, the problem is wrongly generated code when -ffast-math is used.
> >
> > Actually there is a bug in GCC used in the base system.  There was made
> > a change to builtins.c from gcc in revision 1.12 [1] and as a result gcc
> > started to eliminate finite() function calls with -ffinite-math-only.
> >
> > ...
> >
> > After this change the corresponding Assembler code for my test file is:
> >
> > % gcc -Wall -O2 -ffast-math -S finite.c
> > -----------------------------
> > check_finite:
> > .LFB3:
> > 	movl	$1, %esi		<-- fake result from finite()
> > 	movl	$.LC0, %edi
> > 	xorl	%eax, %eax
> > 	jmp	printf
> > .LFE3:
> > 	.size	check_finite, .-check_finite
> > -----------------------------
> >
> > What do you think?  If there is no objections, I'll create PR.
> >
> > [1] http://www.freebsd.org/cgi/cvsweb.cgi/src/contrib/gcc/builtins.c.diff?r1=1.11;r2=1.12
> > _______________________________________________
> 
> The SVN commit
> 
> http://svnweb.freebsd.org/base?view=revision&revision=228756
> 
> will point you to this:
> 
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=28796
> 
> and we are keeping consistency with both upstream and Apple's gcc.

Well, I've found exact commit to upstream gcc source tree that
corrects the bug described above:

http://gcc.gnu.org/viewcvs/trunk/gcc/builtins.c?r1=117751&r2=117929

I think that nobody even tried to run my test program, so I'll post
here results from my system (I did not post this test before just to
make the post brief):

% uname -omr
FreeBSD 9.0-STABLE amd64

% cc -v
Using built-in specs.
Target: amd64-undermydesk-freebsd
Configured with: FreeBSD/amd64 system compiler
Thread model: posix
gcc version 4.2.1 20070831 patched [FreeBSD]

% cat finite.c
#include <math.h>
#include <stdio.h>

void
check_finite(double x)
{
	printf(" %d ", finite(x));
}

int
main(void)
{
	double x;

	for (x = -2; x < 2; x += 0.5) {
		printf("%.1f", x);
		check_finite(x);
	}
	printf("\n");
	return (0);
}

% cc -Wall -O2 finite.c -lm
% ./a.out
-2.0 1 -1.5 1 -1.0 1 -0.5 1 0.0 1 0.5 1 1.0 1 1.5 1 

% cc -Wall -O2 -ffinite-math-only finite.c -lm
% ./a.out
-2.0 0 -1.5 0 -1.0 0 -0.5 0 0.0 0 0.5 0 1.0 0 1.5 0 

Should not both results be the same?
Received on Thu Apr 05 2012 - 04:46:17 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:40:25 UTC