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

From: Andrey Simonenko <simon_at_comsys.ntu-kpi.kiev.ua>
Date: Wed, 4 Apr 2012 12:29:23 +0300
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.

The true result from finite() is non-zero value, but GCC generated always
false value, so any program that uses finite() and has -ffinite-math-only
works incorrectly if it was built by this version of gcc.

Here is the correction for builtins.c:

--- builtins.c.orig	2012-01-06 14:50:41.000000000 +0200
+++ builtins.c	2012-04-04 10:27:23.000000000 +0300
_at__at_ -8738,7 +8738,7 _at__at_ fold_builtin_classify (tree fndecl, tree
     case BUILT_IN_FINITE:
       if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg)))
 	  && !HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (arg))))
-	return omit_one_operand (type, integer_zero_node, arg);
+	return omit_one_operand (type, integer_one_node, arg);
 
       if (TREE_CODE (arg) == REAL_CST)
 	{

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
Received on Wed Apr 04 2012 - 07:29:26 UTC

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