This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: Adding __float128 (i.e TS 18661-3)
- From: Joseph Myers <joseph at codesourcery dot com>
- To: "Paul E. Murphy" <murphyp at linux dot vnet dot ibm dot com>
- Cc: "libc-alpha at sourceware dot org" <libc-alpha at sourceware dot org>, Steve Munroe <sjmunroe at us dot ibm dot com>, Tulio Magno Quites Machado Filho <tuliom at linux dot vnet dot ibm dot com>
- Date: Fri, 6 May 2016 22:03:40 +0000
- Subject: Re: Adding __float128 (i.e TS 18661-3)
- Authentication-results: sourceware.org; auth=none
- References: <572BB6DF dot 7090709 at linux dot vnet dot ibm dot com> <alpine dot DEB dot 2 dot 20 dot 1605052236310 dot 24016 at digraph dot polyomino dot org dot uk> <572CD397 dot 2090405 at linux dot vnet dot ibm dot com>
On Fri, 6 May 2016, Paul E. Murphy wrote:
> > * All functions that both (a) exist for long double in glibc at present,
> > and (b) exist for _Float128 in TS 18661-3, should have versions for
> > _Float128. This includes the <complex.h> functions, which you omitted
> > from your list (and <tgmath.h> support would be updated for both real and
> > complex functions). (Some preparatory changes would refactor the existing
> > complex function implementations so that float / double / long double
> > share most of the code, included with different macros defined. This is
> > the sort of thing that's a good idea anyway, independent of adding new
> > types, simply to make the functions easier to maintain.)
>
> Admittedly, the list was my imperfect attempt to list those functions
> which TS 18661-3 declares for which there is a mathematically equivalent
> long double function already implemented in libm,.
>
> Likewise, we should implement those which diverge from the base C11
> standard in an attempt to improve the removed function. Such functions
> may demand more discussion. Anyhow, str{to,from} and their GNU
> derivatives must be included with the preliminary support. Likewise
> for next{up,down}.
>
> Do you think it is beneficial to exhaustively list each function?
For the glibc functions (both public API, and internal functions forming
part of the public ABI because of use from macros etc.) that include long
double in their interface (so qualify under (a) above), but do not qualify
under (b) above, I think they should be listed exhaustively, with the
rationale for whether for each function it is proposed to have a float128
version. (That is, functions where long double is involved in the return
type or a declared argument type. Not printf / scanf / strfmon functions
where it's only involved through formats for variable arguments, because
the TS 18661-3 direction is that no new formats are added for the new
types; string conversions for such types should be handled through the
strto* and strfrom* functions.)
Much the same applies to non-function interfaces. For example, the M_*l
constants (a GNU extension, whereas the double versions are in POSIX).
Clearly M_*f128 are needed for internal use in glibc (at least M_PIl is
used in ldbl-128 code, and more are used in the complex function
implementations), and I think they should form part of the public API as
well (for _GNU_SOURCE, on platforms where float128 is supported).
Naturally, non-function interfaces that are in TS 18661-3 and whose long
double versions are in glibc should all be added and don't need individual
enumeration for that reason. That covers at least HUGE_VAL_F128, and
FP_FAST_FMAF128 if the fused operation is fast. HUGE_VAL_F128 should be
defined to (__builtin_huge_valq ()) (given the minimal set of built-in
functions __builtin_infq, __builtin_huge_valq, __builtin_fabsq,
__builtin_copysignq, that should be added for powerpc as previously
discussed to match the set available for x86).
> I intentionally omitted tgmath and complex as I view them as an isolated
> chunk of work at this time. They broaden the the scope of the initial
> work too much.
I think they should be included to provide the most logical coverage of
float128 support. (That is, included in the same patch series and
entering glibc in the same release. No doubt in separate patches from
other features, but that's simply a convenience for review of such a big
patch series.)
tgmath is fiddly, but an early step should be a careful analysis of all
the various type-generic floating-point macros in glibc, whether in
<math.h>, <tgmath.h> or internal such as fabs_tg, min_of_type in
math_private.h. I suspect it should be possible to produce some common
infrastructure for use by all such macros, that will handle all the
different cases of what types and compiler features are available, at
which point tgmath support for float128 may become more straightforward.
(Of course, you need to keep watching for WG14 resolution of the issues
with feature test macros. The resolution proposed in N2029, to require
feature test macros to be consistent between header inclusions without
requiring any diagnostic if they are not, is certainly simpler to
implement than other versions previously proposed.)
I don't think the complex functions are a particularly hard part, compared
to the overall complexity of systematically eliminating assumptions
everywhere about there being three floating-point types that have been
there since the start of glibc; they could do with being macroized anyway
to make bug fixes across the three existing types less repetitive.
> >> # if __GNUC_PREREQ (4,6) && !defined __SUPPORT_SNAN__ \
> >> && !defined __OPTIMIZE_SIZE__
> >> # define fpclassify(x) __builtin_fpclassify (FP_NAN, FP_INFINITE, \
> >> FP_NORMAL, FP_SUBNORMAL, FP_ZERO, x)
> >> # else
> >> # define fpclassify(x) _Generic( (x), \
> >
> > You need to keep supporting compilers without _Generic (although you might
> > choose not to have type-generic macros support __float128 with such
> > compilers).
>
> Is it possible to determine if a compiler supports it? GCC enabled some
You'll need conditions in sys/cdefs.h that check __GNUC_PREREQ, and any
appropriate conditions for other compilers, falling back to
__STDC_VERSION__ for unknown compilers or those where it implies the
support is present.
> C11 support in 4.6, but _Generic was added in 4.9. Anyhow, if my history
> is correct, GCC supported __float128 in 4.8, so a third alternative is
> needed anyways.
For powerpc64le, we can take 6.1 as the minimum __float128 version, with
any support in older versions not being usable. (For x86_64 it's 4.3, for
ia64 and 32-bit x86 it's 4.4, but my understanding is you're starting with
powerpc64le so don't need alternatives only relevant to x86_64 / x86 /
ia64. Anyway, __builtin_types_compatible_p and __builtin_choose_expr are
in all GCC versions supporting __float128 on those platforms, so support
for handling __float128 there shouldn't be hard when needed.)
[6.1 of course does not have the complex support or the built-in functions
I listed. Let's assume they are added for 6.2, and 6.1 may still be good
enough for compiling programs only using __float128 and not the complex
type or HUGE_VAL_F128, although not good enough for compiling glibc
itself. Really I wouldn't be surprised if existing GCC versions have
serious bugs in their __float128 support - until glibc is being built with
float128 support, and testcases run for it, it's hard to have much
confidence in the robustness of the support when applied to nontrivial
code.]
> Where do we draw the line for TS 18661 support? Must the compiler support
> _Generic and __STDC_IEC_60559_TYPES__ >= 201506L, or must it be a GCC
> compiler of some minimum version when a user defines
> __STDC_WANT_IEC_60559_TYPES_EXT__?
Clearly we can't rely on __STDC_IEC_60559_TYPES__. That would rule out
all currently existing GCC versions on all platforms. [I think it would
be desirable to have proper TS 18661-3 support in GCC - meaning support
for the new keywords and constant suffixes and float.h macros, etc.,
complete with various subtleties such as keywords existing even if the
types don't and e.g. _Float32 not being promoted to binary64 in variable
arguments - and indeed support on a par with existing types - meaning lots
more including making all the built-in functions have variants for the new
types for optimization for constant arguments etc. and adapting various
optimizations that currently assume only three types. But that's not
something that could sensibly gate the glibc support, and it's not
suitable for backporting to GCC 6 branch unlike the minimal complex
support and the handful of built-in functions I listed.]
So, the functions need to be supported in cases when __float128 is
supported, but not _Float128 (and given the WANT macro is defined when the
relevant headers are included, or _GNU_SOURCE is defined before including
any standard header - feature test macro handling is another thing needing
careful consideration and design). Doing so also helps for C++ support.
It's not clear what shape standard C++ support for such types might take,
but for decimal floating point it involved classes rather than built-in
types, with special compiler support to make them ABI-compatible. So
__float128 is something available for C++, where as a keyword _Float128
might not be even when supported for C.
> Let's say glibc + GCC on a given platform supports a hypothetical _Float128
> and _Float16 type, and exposes some subset of TS 18661 functionality for
> both types. Someone attempts to use a compiler which only supports _Float128,
> is there a standards compliant mechanism to prevent exposing the _Float16
> machinery without including float.h?
We need a bits/*.h header (installed) giving information about the formats
available with the compiler used to build code against the glibc header,
and the type names (such as long double, __float128 or _Float128)
corresponding to those formats, where those formats have corresponding
glibc functions (there's no need for it to describe any formats without
glibc functions). Practically, this header might start with just the
information relevant to __float128 and long double possibly being
equivalent thereto; it might be hard to design something fully general and
be confident in it without actually having the compiler support.
> >> * matherr and other legacy behavior should stick around.
> >> Why? This should enable trivial mapping between similar
> >> ldbl and f128 symbols, saving a little codespace.
> >
> > I don't think it should be present for the new functions; that would mean
> > e.g. extending legacy __kernel_standard code, which otherwise could remain
> > untouched, to handle more types. I think there's a strong case for
> > several of the preliminary patches to deal with deprecation of matherr and
> > setting up a new set of macroized wrappers that don't use
> > __kernel_standard but handle errno setting directly without reference to
> > _LIB_VERSION (on most architectures for existing types maybe they'd only
> > be used in static libm unless we decide to add new symbol versions for
> > many libm functions, for new architectures and new types they'd be used in
> > both shared and static libm).
>
> Those macros only appear to be used by the wrapper functions, so
> removing them for the new variants shouldn't be too convoluted without
> adding too much bloat to the library?
I don't think new wrapper variants should be complicated. If the approach
is that new variants are only used for new formats, new ports and static
linking, so shared libm never contains both old and new wrappers for the
same functions, maybe the new variants (appropriately macroized to reduce
duplication) would #include the old ones under some SHLIB_COMPAT
conditionals.
> > Given appropriate obsoletion of matherr support for new binaries (meaning
> > matherr and _LIB_VERSION become compat symbols, so that in new links libm
> > will never refer to the program's copy of them), then of course future
> > support for long double on powerpc64le being __float128 would have the
> > long double functions not supporting matherr at all (this wouldn't be any
> > sort of problematic inconsistency between types for users, because no
> > newly linked program could use matherr for any type).
>
> Would that require versioning all the existing wrappers? It might save
> a little space on platforms with a binary128 ldbl. Though, such a change
> sounds quite complex by itself.
Any symbol versioning for existing wrappers would need careful
consideration as part of the discussion of the design for obsoleting
matherr support. But my inclination is not to add new symbol versions for
existing functions in existing platforms, as the performance cost of the
_LIB_VERSION checks and calling __kernel_standard should be fairly small.
> > * sysdeps/ieee754/float128 (for example) is the primary location of the
> > sources for these functions, whenever these functions are present. It
> > defines e.g. __ieee754_<func>f128 or __<func>f128 (depending on the
> > function) as internal names, with appropriate *f128 aliases as exported
> > names.
>
> Ideally, such a change seems sensible, but ultimately is it not a trivial
> naming change which carries a more intensive verification?
Readability and maintainability of source code are important. That means
keeping the macroization of these functions down to the unavoidable
minimum, and thinking carefully about what the optimal arrangements for
the source code are.
> Likewise, should these also expose appropriate *_finite symbols too? Or,
> is such even permissible under this standard?
__*_finite are in the implementation namespace. So it's always fine to
have those aliases. *But* the principles of ABI minimization (keeping
down the number of shared library exports) mean that if float128 and long
double functions alias each other (on existing platforms where long double
is binary128), those functions should not have two sets of aliases
__*l_finite and __*f128_finite. The design for math-finite.h needs to
allow for that. (For normal public functions, if we add *f128 API support
when it's the same format as long double - and I think we should, just
like *f32 *f64 *f32x *f64x variants as applicable - then ISO C rules about
when you can declare a function yourself mean that most functions
unavoidably do need duplicate shared library exports.)
--
Joseph S. Myers
joseph@codesourcery.com