On Thu, 26 May 2005, Scott Robert Ladd wrote:
> I prefer breaking out the hardware intrinsics from
> -funsafe-math-optimizations, such that people can compile to use their
> hardware *without* the other transformations implicit in the current
> collective.
>
> If someone can explain how this hurts anything, please let me know.


I apologise for coming into this argument late.  I'll admit that I
haven't even caught up on the entire thread, but an interesting
relevant article that may or may not have already been mentioned is:

http://web.archive.org/web/20040409144725/http://www.naturalbridge.com/floatingpoint/intelfp.html

[My bookmark 404'd, so I had to use the wayback machine to find it!]

The crux of the issue is that only two GCC targets have ever supported
trigonometic functions in hardware; the x87 coprocessor on IA-32 systems
and the 68881 co-processor on m68k systems.  Of these two, GCC builtin
support has only ever been added for the i386 backend and as mentioned
in the article above the FSIN and FCOS functions produce results well
outside the 1ulp allowed by the relevant standards, even for arguments
in the range [0...2PI].  As such, the reason why hardware support for
these intrinsics is considered part of flag_unsafe_math_optimizations,
is that, for some applications, they are exactly that, "unsafe".

Admittedly on many IA-32 systems there's little difference between
using FSIN vs calling the OS's libm's sin function, as glibc and
microsoft's runtimes (for example) themselves use the x87 intrinsics.
GCC, however, is not to know this and assumes that the user might
provide a high-precision library, such as Lefevre's perfect O.5ulp
implementation.  [It's nice to see him join this argument! :)]


In this instance, "unsafe" math need only be different.  For example,
if the compile-time evaluation, the run-time library and the hardware
intrinsic could potentially return different results, even if the
change is to return a more accurate result, then it is potentially
unsafe.  Tests such as:

        double x = 2.0;
        if (sin(x) != sin(2.0))
          abort();

and

        double (*fptr)(double) = &sin;
        if (sin(x) != fptr(x))
          abort();

should continue to work as expected.  This might also explain some
of your accuracy results.  Even if GCC can determine a way of
evaluating an expression that results in less loss of precision,
e.g. "(x + 1.0) - 1.0" -> "x", it can't do so unless allowed to
be "unsafe".

Sorry if all this has been mentioned before.  Your own results
show that you get different results using x87 hardware intrinsics,
and this alone classifies their use as "unsafe" in GCC terminology,
i.e. may potentially produce different results.

Roger
--

Reply via email to