Re: Optimization bug with floating-point?

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Thu, 14 Mar 2019 14:03:16 -0700
On 3/14/19 1:08 PM, Steve Kargl wrote:
> On Fri, Mar 15, 2019 at 05:50:37AM +1100, Peter Jeremy wrote:
>> On 2019-Mar-13 23:30:07 -0700, Steve Kargl <sgk_at_troutmask.apl.washington.edu> wrote:
>>> AFAICT, all libm float routines need to be modified to conditional
>>> include ieeefp.h and call fpsetprec(FP_PD).  This will work around
>>> issues is FP and libm.  FreeBSD needs to issue an erratum about 
>>> the numerical issues with clang.
>>
>> I vaguely recall looking into the x87 initialisation a long time ago
>> and STR that the startup code (either crtX or in the kernel) does
>> a fninit() to set the precision.  I don't recall exactly where.
>>
>> IMO, calling fpsetprec() in every libm float function is overkill. It
>> should be enough to fpsetprec() before main() and add a note in the
>> man pages that libm is built to use the default FPU configuration and
>> changing the configuration (precision or rounding) may result in larger
>> errors.
> 
> My understanding of the situation is that FreeBSD i386/387 sets
> the FPU to 53-bit precision (whether at start up or first access
> is immaterial).  This was done long ago to prevent issues with
> different optimization levels leaving different intermediate
> results is registers with extended precision.  You can observe
> the problem with the toy program I posted and clang.  Compile it
> with -O0 and -O2.  With the former you have max ULP of 2.9 (the
> desired result); with the latter you have a max ULP of 23.xxx.
> I have observed a 6 billion ULP issue when running my testsuite.
> As pointed out by John Baldwin, GCC is aware of the FPU setting.
> The problem with clang is that it seems to unconditionally assume
> the FPU is set to 64-bit precision.   It is unclear if clang is
> generated the desired result for float routines in libm.  The
> only to gaurantee the desired resut is to use fpsetprec(FP_PD),
> or fix clang to take into account the FPU environment.

OTOH, note that every other OS in 32-bit mode uses 64-bit precision,
and amd64 also uses 64-bit precision by default IIUC.  FreeBSD/i386
is definitely unique in this regard.  Linux doesn't do it, none of
the other BSD's do it (only Dragonfly does b/c they inherited it
from FreeBSD).  None of Solaris, Windows, etc. do it either if the
gcc sources are to be trusted as a reference.

That said, I think it must have to do with how clang vs GCC is
handling saving the values in memory and whether or not it does
truncation to 53 bits when stored in memory somehow.  I was trying
to poke around in GCC's sources to figure out if it was doing anything
differently, but I couldn't find a difference in terms of function
pointers, etc.  The only difference is is the constants used in a set
of structures.  I haven't tried to track down what those struct
member values control though.

-- 
John Baldwin
Received on Thu Mar 14 2019 - 20:03:20 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:41:20 UTC