This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Macros using __NO_LONG_DOUBLE_MATH


On Thu, 4 Jun 2015, Wilco Dijkstra wrote:

> Hi,
> 
> Looking at math/math.h, a common idiom is:
> 
> # ifdef __NO_LONG_DOUBLE_MATH
> #  define isnan(x) \
>      (sizeof (x) == sizeof (float) ? __isnanf (x) : __isnan (x))
> # else
> #  define isnan(x) \
>      (sizeof (x) == sizeof (float)                                            \
>       ? __isnanf (x)                                                          \
>       : sizeof (x) == sizeof (double)                                         \
>       ? __isnan (x) : __isnanl (x))
> # endif
> 
> This looks unnecessary - given that it is OK to use the double version when
> __NO_LONG_DOUBLE_MATH is defined, sizeof (long double) == sizeof (double)
> when long double math is not supported. Also sysdeps/ieee754/ldbl-opt
> defines all the long double functions using double, so even we did accidentally
> expand into __isnanl, it would be the same as __isnan anyway.
> 
> So can we simplify the logic to this?
> 
> #define isnan(x) \
>      (sizeof (x) == sizeof (float)                                            \
>       ? __isnanf (x)                                                          \
>       : sizeof (x) == sizeof (double)                                         \
>       ? __isnan (x) : __isnanl (x))
> 
> This would make adding inlines using GCC built-ins far less messy.

ldbl-opt is specifically for cases where an architecture supports both 
long double with the same representation and alignment as double, and long 
double distinct from double - it doesn't cover cases where an architecture 
doesn't support distinct long double at all.

Now, it's true that in such cases sysdeps/ieee754/dbl-64/s_isnan.c defines 
__isnanl as an alias to __isnan.  However, I think the issue is about 
declarations, not definitions.  It was formerly the case, before commit 
998832a46688b9fb3a101eccae77bc45e7c1d7ab, that math.h didn't generally 
declare long double functions at all in the long double = double case.  
When this was fixed, it remained the case that the declarations don't 
appear if _LIBC.  And the declarations can't readily appear in the _LIBC 
case, because of the long double functions being defined as aliases of the 
double ones - this would give errors about incompatible types if they'd 
previously been declared with long double rather than double argument and 
return types.

So no __isnanl declaration is generally visible in the 
__NO_LONG_DOUBLE_MATH case if _LIBC, preventing a definition using 
__isnanl from being used.

I don't see how such a change would benefit using GCC built-in functions 
anyway.  Presumably you'd do

# if __GNUC_PREREQ (6, 0)
#  define isnan(x) __builtin_isnan (x)
# elif defined __NO_LONG_DOUBLE_MATH
 ...
# else
 ...
# endif

if GCC 6 is the version for which you fix __builtin_isnan to be 
universally usable including in the signaling NaN case, or something more 
complicated if you want to handle older GCC versions as well - but in any 
case, the new cases can just go before the existing ones.  Note that:

(a) All these GCC built-in functions, except for __builtin_signbit (GCC 
bug 36757), are type-generic (which is good for avoiding the expansion 
text containing the argument text more than once).  (But depending on the 
conditions under which such functions are used, watch out for some having 
been added in earlier GCC versions than they became type-generic.)

(b) You'd only use the GCC built-in functions when guaranteed to expand 
inline rather than to an external function call - so, when using them, you 
don't need to worry about whether the corresponding external function 
exists or not.

(c) When we no longer support building glibc with GCC versions before GCC 
6, the __NO_LONG_DOUBLE_MATH case could indeed be removed (as the issue 
with long double functions not being declared is one only applying when 
building glibc, not when using it with older / non-GCC compilers).

(d) There is, deliberately, no __issignalingl alias for __issignaling in 
the case where long double has the same representation and alignment as 
double, so in that case we are relying on the header macros not calling 
__issignalingl (in ISO C terms, there are only certain contexts when an 
unevaluated function call doesn't require the function to be defined at 
all, and the false part of ?: isn't one of them).  So you couldn't remove 
the __NO_LONG_DOUBLE_MATH case in that case (but also GCC has no 
__builtin_issignaling at all at present).  I'd propose a similar practice 
if implementing other new type-generic macros from TS 18661-1: don't add 
more functions than required to the libm ABI (so something defined as a 
function gets aliases in that case, but functions underlying something 
defined as a macro don't get such aliases).

-- 
Joseph S. Myers
joseph@codesourcery.com


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]