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: Adding __float128 (i.e TS 18661-3)


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


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