[llvm-commits] Patch: Math Lib call optimization

Stephen Canon scanon at apple.com
Wed Nov 2 14:19:33 PDT 2011


On Nov 2, 2011, at 3:42 PM, Weiming Zhao wrote:

> The precision loss will happen when the results of sin((double)x) and
> sinf(x) differ within a single precision ulps. It might happen only in very
> rare cases. So, theoretically, you're right. :D 
> But in practice, I did experiments by comparing the results of (float)sin(x)
> and sinf(x) for random inputs. The results are the same. And for users who
> are really concern about precision, they can disable this pass.

This is entirely dependent on the target platform's libm, and very much not true in general.  This is not a safe optimization to perform unless it is explicitly licensed by the user.  There exist platforms on which even basic single-precision functions like powf( ) have many ulps of error, and calling the double-precision function instead is a standard way for users to guard against this.  (Note that a pow( ) implementation with thousands of ulps of error still gives a sub-ulp accurate powf( )).

Certainly flag it in the front end.  Suggest to the user that they should enable this optimization.  But this should not be enabled by default.

I question your methodology of comparing the results for random inputs.  There are only 4 billion single-precision numbers, it is easy enough to compare all of them.  However, I will save you the time: on most platforms with decent math libraries, there exist inputs for which sinf(x) != sin(x).  In order to make a good accuracy/performance tradeoff, most good math libraries aim for ~.5x ulps of error (where x is some digit, depending on the library).  As there exist single-precision values for which the mathematically-precise sinf(x) is within .01 ulps of an exact halfway point for rounding, there will almost certainly be cases for which sin(x) != sinf(x).  In fact, nearly the only way to avoid this is to simply implement sinf(x) as (float)sin(x), in which case no performance is gained.

Note that there are many libm functions for which this is a viable optimization: all of the rounding functions (assuming the result is subsequently converted back to single), fmod and remainder (because they are always exact), sqrt (because only 2p+2 bits are required to round square root correctly, and double has more than twice the bits of float plus two).  As far as I know, some of these are already implemented in llvm (sqrt, at the very least).

Cheers,
- Steve



More information about the llvm-commits mailing list