This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: Macros using __NO_LONG_DOUBLE_MATH
- From: Joseph Myers <joseph at codesourcery dot com>
- To: Wilco Dijkstra <wdijkstr at arm dot com>
- Cc: GNU C Library <libc-alpha at sourceware dot org>
- Date: Thu, 4 Jun 2015 15:17:57 +0000
- Subject: Re: Macros using __NO_LONG_DOUBLE_MATH
- Authentication-results: sourceware.org; auth=none
- References: <000801d09eb7$48f0aa80$dad1ff80$ at com>
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