svn commit: r253215 - head/lib/msun/src

Tijl Coosemans tijl at coosemans.org
Sat Jul 13 19:54:44 UTC 2013


On 2013-07-12 11:14, Bruce Evans wrote:
> On Thu, 11 Jul 2013, Tijl Coosemans wrote:
>> On 2013-07-11 22:03, Tijl Coosemans wrote:
>>> On 2013-07-11 21:36, David Chisnall wrote:
>>>> On 11 Jul 2013, at 19:52, Tijl Coosemans <tijl at coosemans.org> wrote:
>>>>>> @@ -227,8 +250,6 @@ double    expm1(double);
>>>>>> double    fma(double, double, double);
>>>>>> double    hypot(double, double);
>>>>>> int    ilogb(double) __pure2;
>>>>>> -int    (isinf)(double) __pure2;
>>>>>> -int    (isnan)(double) __pure2;
>>>>>
>>>>> I think they should stay for the C90 case.
>>>>
>>>> That would completely defeat the point of this entire exercise and be
>>>> redundant unless we aim to support a compiler that only supports C90
>>>> and no GNU extensions, in which case you'll hit errors in cdefs.h,
>>>> long before you get to this point in an include.
>>>
>>> isnan(double) is part of SUSv2. It should be visible when compiling with
>>> -D_XOPEN_SOURCE=500. I think you need something like this:
>>> 
>>> #if (__BSD_VISIBLE || __XSI_VISIBLE <= 500) && __ISO_C_VISIBLE < 1999
>>> int    isinf(double) __pure2;
>>> int    isnan(double) __pure2;
>>> #endif
>>
>> Actually this:
>>
>> #if (__BSD_VISIBLE || (defined(__XSI_VISIBLE) && __XSI_VISIBLE <= 500))
>> && __ISO_C_VISIBLE < 1999
> 
> Remove the __ISO_C_VISIBLE part, since this is not in C90.  This also
> fixes a style bug (long line).

I shouldn't have mentioned C90. What I meant to say is the
not-C99-or-higher case which is further restricted by __BSD_VISIBLE
and __XSI_VISIBLE, but where the macros aren't defined.

These two symbols are the cause for the original problem report about
clang's cmath header (in C++11 isnan/isinf are functions returning bool
not int). Their visibility had to be constrained somehow and that
cascaded into redefining the isnan and isinf macros because they were
implemented using these functions. I think completely removing these
symbols is wrong however because it breaks the API in the specific case
of the #if above.

If __ISO_C_VISIBLE < 1999 isn't correct then maybe __cplusplus < 201103L?

> How can that work?  Even you forgot to restore the parentheses around
> the functions, so the above has syntax errors.

The macros aren't there for __ISO_C_VISIBLE < 1999.

> I noticed some more problems in the implementation of these macros
> and others:
> - many or all of the __pure2's in the prototypes are wrong, since even
>   the classification functions can have side effects for signaling
>   NaNs.  It is impossible to avoid these side effects for extern
>   functions in some cases, since the ABI gives them.  I think static
>   inline functions must have the same results as extern functions,
>   so compilers should pessimize inline functions as necessary to
>   get the same bad results, but compilers don't do that.

Apparently, in the 2008 version of IEEE 754 they are considered
non-computational and never generate exceptions, even for sNaN.

The old IEEE 754-1985 only mentions isfinite and isnan and says
implementations may consider them non-arithmetic.

> - classification functions are specified to convert to the semantic
>   type (remove any extra precision or exponent range) before classifying.

Yes, it makes the macros more function-like.

>   For example, if x is a double slightly larger than sqrt(DBL_MAX), and
>   if double expressions are evaluated in extra exponent range, then x*x
>   is finite with the extra range but infinite in the semantic type.  So
>   isinf(x*x) is true, and the implementation
>   #define isinf(x) (fabs(x) == INFINITY) is invalid.  clang on x86 gets
>   __builtin_isinf(x*x) this right as a side effect of its pessimization
>   of fabs() to non-inline -- parameter passing to the extern fabs()
>   converts to the semantic type.  Sometimes the arg is known not to have
>   extra range, so no conversion is needed.

If isinf isn't supposed to generate exceptions then it cannot use a
floating point comparison either. That would only leave bit operations.

> I think C11 has new mistakes for extra precision.  It specifies that
> return reduces to the semantic type, like the classification macros
> are required to do for their arg.  clang -std=c11 doesn't implement
> this bug for at least:
> 
>     #include <math.h>
>     double sq(double x) { return (x*x); }
>     double sq2(double x) { return (fabs(x*x); }
> 
> On i386 without SSE2 (so extra precision), this generates the same code
> as with -std=c99.  Squaring x gives extra precision and exponent range.
> This is not destroyed on return, so extra precision is not defeated by
> writing the squaring operation as a function.  fabs() is inlined in both
> cases, so it has little effect here (no effect unless x is NaN), but I
> think even C99 doesn't permit this.  If fabs() were not inline, then
> the ABI would force destruction of the extra precision and range when
> it is called, and I think C99 requires conversion to the semantic type
> for calls.

For function parameters both C99 and C11 state that they are converted
as if by assignment meaning extra precision should be removed. This is
also required by IEEE 754-2008. Both C99 and C11 state that making a
function inline suggests calls to the function should be as fast as
possible, but I don't think this allows skipping any conversions so
even if a function is inlined the compiler should remove extra
precision.

If a floating point value already has the right precision then
assignment and as-if-by-assignment may be seen as copy operations that
don't raise any exceptions even for sNaN. I suppose this means math
functions must always use each argument in at least one arithmetic
operation to trigger sNaNs.

For return statements both C99 and C11 state that it's not an
assignment. Only if the type of the return expression differs from the
return type is the result converted as if by assignment. There's a
footnote that says this allows floating point values to be returned with
extra precision if there's no conversion. The extra precision can be
removed with a cast. IEEE 754-2008 requires that extra precision is
removed.

Also, fabs is somewhat special. In IEEE 754-1985 it's considered equal
to copysign(x, 1.0) which may but doesn't have to raise exceptions even
for sNaN. In IEEE 754-2008, operations that only affect the sign, like
fabs, don't raise exceptions.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: OpenPGP digital signature
URL: <http://lists.freebsd.org/pipermail/svn-src-head/attachments/20130713/fa52b99b/attachment.sig>


More information about the svn-src-head mailing list