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: Thu, 5 May 2016 23:35:04 +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>
On Thu, 5 May 2016, Paul E. Murphy wrote:
> As Joseph pointed out earlier in [1] and [2] we can't hack and slash our
> way into supporting this, but IMO, the consensus driven model doesn't
> encourage a large upfront design, as interested parties only seem to
> show up at the tail end (during patch submissions). I think we need
> consensus on what the end result will look like, and what steps will
> get us there.
A lot of the maybe 50 (rough guess, could be more, unlikely to be much
less) preparatory patches could actually be justified directly on their
own merits without the full design - for example, refactoring a particular
testcase to be easier to instantiate for all floating-point types, thereby
improving test coverage right now by making that testcase cover all three
current types rather than just one.
It's true that some of the trickier and larger pieces can only really be
justified by later patches showing that (for example) a particular
refactoring is in fact adequate to enable some functionality to be
extended to more types. And so it may be easier to produce an up-front
list of 50 patches that will be needed, than to identify the precise
internal APIs that patch 28 should contain in order to enable patch 46 to
extend some functionality to more types (or to submit some such patches
without submitting a lot of later patches at the same time).
> For the initial support, I want to focus on math.h. I suggest the
> following should be the minimal set of libm/c functions required to
> enable a new TS 18661-3 type:
>
> copysign modf scalbn frexp ldexp sin cos ceil erf expm1 fabs
> floor log1p logb nextafter rint scalbln tan tanh fmax fmin fdim trunc
> remquo round lround llround nextup nextdown acos acosh asin asinh
> atan2 atanh cosh exp exp10 fmod hypot log log2 log10 pow scalbn ilogb
> exp2 lgamma_r lgamma
I don't know where this list came from, but it's missing, for example,
sinh and remainder.
In the case of remainder, one of the many preparatory patches would be to
change the documentation to express that remainder is the primary name and
drem is a legacy alias, since it presently describes drem as the main
name. (drem should *not* get a dremf128 version, remainderf128 is
sufficient.)
I think the starting point is:
* 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.)
* All functions that exist for long double in glibc at present, but do not
exist for _Float128 in TS 18661-3, need a careful analysis. Some should
be added for _Float128 (e.g. lgammaf128_r, strtof128_l, as in your list,
and the Bessel functions, missing from your list). Some should not (e.g.
legacy aliases such as drem and gamma should not get _Float128 versions;
nor should other legacy functions such as scalb even though they would
need versions added to support it as an alternative long double type).
* The minimum set of new functions from TS 18661-1 that should be added to
get _Float128 versions is, I think, nextup nextdown strfrom (all on your
list). Of course that means earlier patches in the series would add such
functions (with test coverage, documentation etc.) for all existing
floating-point types / formats on all architectures, before the _Float128
versions are added later. [Other functions that are new in TS 18661 can
be ignored.]
* Internal functions need careful consideration - but in general, a few
such functions as __isinff128 will need adding as backing for macros in
standard headers. And where we have __*l_finite, I think consistency
probably means adding __*f128_finite (and working out a clean way to
handle this in bits/math-finite.h).
* If a function is internal, or if its type involves some standard header
typedef, then in the case where __float128 and long double have the same
representation it should *not* get an additional ABI exported from the
shared libraries as an alias.
Working out the exact set of additions to the ABI and the API is the most
critical thing to get consensus on.
> #define __C11_GENEN(t,f) \
> t: f, \
> const t: f, \
> volatile t: f, \
> volatile const t: f,
WG14 consensus is that qualifiers are not needed with _Generic (the
relevant type is always the unqualified type), so they should not be
included here. If you want backwards compatibility with non-GCC compilers
predating that consensus, using unary + in the _Generic call is a much
less intrusive way of removing qualifiers.
> # 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).
> TS 18661-3 also calls out a number of macros which should be included by
> float.h, which would need to be added through GCC. Would adding a new
> public header like float-ts18661.h be permissible or should such
> definitions be held in private headers for internal usage in the meantime?
I think such definitions belong in glibc's internal include/float.h
(doesn't exist at present), wrapping GCC's float.h and adding any required
definitions it's missing (possibly via including architecture-specific
headers).
> I consider the build changes as including the test fixtures. How
> exactly the test fixtures are extended is less important, it just needs
> to work, and should be easily expandable to future formats.
In general, all tests for functions that exist for different
floating-point types need to be adapted to be type-generic - meaning that
now they would run for all three types (many such functions are only
well-tested for one type) and later could run for more.
> My proposed design for source structure is:
> * sysdeps/ieee754/f128/ holds all the __float128
> (e.g sysdeps/ieee754/f64x-ibm for a _Float64x type based off ibm128)
_Float64x cannot be based on ibm128; it must have IEEE semantics. It
could be an alias for __float128, or for x86 extended (I don't see any
circumstances in which it would be anything else).
> * 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).
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).
> As for source, we should avoid duplication of non-trivial assets, and
> that requires refactoring most of the ldbl-128 sources. I'd rather
> not use Makefile/script tricks to generate the files. The only truly
> ugly thing I've encountered thus far is using a macro to add the
> correct suffix (L for long double, Q for __float128).
I think macros like that are indeed needed. It's critical that the
conversion is scripted, as reviewability of the conversion will mean that
what's reviewed must be a small clean script that does the conversion and
maybe a small subsequent fix-up patch, not an enormous patch with massive
semi-automatic source changes which are effectively unreviewable. (Of
course it should also be tested that such a conversion does not change the
generated code for some existing configuration using ldbl-128.)
There is one way in which the extent of macro use can be reduced. Given
that we want to support these APIs, there's a clear case for them existing
on architectures where long double has binary128 representation, as
aliases for the long double functions (with the usual issues about
defining aliases between functions with incompatible types). What that
indicates to me is:
* 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.
* sysdeps/ieee754/ldbl-128 then appears in sysdeps only in the case where
this format is long double. It somehow causes the functions to be built
with additional long double aliases, in the case where this format is long
double. Either through lots of small wrappers (in which case
sysdeps/ieee754/float128 does *not* appear in sysdeps unless it's a
separate type), or through an alternative implementation of a header that
gets included by the main implementations (in which case both directories
would appear in sysdeps, but *l.c files wouldn't get built in that case
because *f128.c build the *l aliases). Or some other such approach.
* The functions can then call e.g. __ieee754_logf128 directly; there's no
need to macroize calls to internal function names, because the internal
names always use *f128 on all platforms. Similarly, they can refer
directly to FLT128_MAX instead of needing to macroize a choice between
that and LDBL_MAX. (Some care is still needed about built-in function
calls, e.g. using __builtin_fabsq versus fabsl, since it's best to get
that inlined even for __float128, which requires using the __builtin_fabsq
name in the case - note that's one of the handful of built-in functions
that should be present in any compiler supported for building glibc with
float128 support.) [Eventually, if GCC were to get support for _Float128
with *f128 constants on all relevant platforms, once a sufficiently recent
GCC version is required to build glibc everywhere the code could get the
macros around constants removed and just use *f128 constants directly.
But that would be several years down the line; for a long time, the code
will clearly need to use macros for all constants that might be long
double or __float128, while being made more readable by just using
unsuffixed constants for at least small integers, maybe cases like 0.5 as
well.]
* In the case where four versions of functions need to be built, rather
than extending math/Makefile's existing settings such as
long-m-routines = $(patsubst %_rl,%l_r,$(libm-calls:=l))
I think it would be better to chamge libm-calls to list patterns with a %
in them, that then get instantiated for any number of suffices (for
example, it would contain e_lgamma%_r, so removing the need for the
special %_rl adjustment to be repeated for every format).
--
Joseph S. Myers
joseph@codesourcery.com