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: RFC Migrating PowerPC to IEEE 128-bit Floating Point


On Tue, 13 Oct 2015, Steven Munroe wrote:

> This is complicated. I thank Uli Weigand for developing this break-down 
> of long double usage.
> 
> Looking at what various targets use today, it seems that all platforms 
> supported by glibc use IEEE float and double.  As to long double, the 
> following options are in use:
> (A) "long double" is 80-bit IEEE extended (no variants): i386, x86_64, 
> ia64, m68k -- sysdeps directories: ieee754/ldbl-96

(Actually, there are two variants - m68k has one additional normal 
exponent (values with exponent representation 0 are interpreted as if it 
were a normal exponent, but with the explicit MSB of the mantissa allowed 
to be 0), resulting in the least normal value and the least subnormal 
value being half what they are in the Intel variant.  This is handled by 
e.g. gen-auto-libm-tests, but I strongly suspect that some of the code in 
sysdeps/ieee754/ldbl-96 does not handle the m68k variant fully correctly.)

> (B) "long double" is 128-bit IEEE quad (no variants): aarch64, mips64, 
> sparc64 -- sysdeps directories: ieee754/ldbl-128

(There's the MIPS variation in the quiet / signaling NaN convention, but 
very little needs to care about that.)

Neither of those variations I noted is of any direct relevance to the 
addition of __float128 support, except insofar as it probably involves 
updating testcases that deal with such variations.

> I suggest we start by creating a new source directory 
> (./ieee574/ldbl-f128) specifically for introducing __float128 support. 
> This allows us to begin work without impacting to the existing 
> platforms.

When it's being used for a type that's not long double, it's not clear 
that the name should start ldbl-.  But that's a side issue.  The main 
thing is that before adding any ABIs we should think very carefully about 
just what ABIs are appropriate, as well as about the implementation 
design.  And the same applies to APIs.  I think there is a large amount of 
work to do before any directories are added.

> In parallel we can begin the work of preparing ldbl-128ibm to move out 
> of the ieee-*l name space and prepare for the release where they will 
> become of the old version of long double for the power platform.

I don't really see the benefit in such a move.  As in, it's not 
technically complicated to change a directory name, but when all the other 
main implementations for particular floating-point formats are in 
sysdeps/ieee754, does it really make sense for one format to have its 
implementation sitting off on the side somewhere?  The name isn't exactly 
accurate, but is the move worth the disruption any more than removing the 
useless "sysv/" directory component from sysdeps/unix/sysv/linux/ would 
be?

> Finally once the ldbl-f128 target is fully implemented and tested, 
> interested platforms can migrate to ldbl-f128 or decide to merge 
> ldbl-128 and ldbl-f128 in to a single implementation supporting both 
> names/types.

You need separate sysdeps directories for the concepts of "long double is 
binary128" and "__float128 functions where that is not long double".  The 
former is ldbl-128.  The case of "*f128 as aliases for *l when long double 
is binary128" could probably be done through ldbl-128 as well.

> > I'd be wary of trusting that the set of functions with existing support 
> > for variable long double types is in fact the complete set that need 
> > fixing for such a change.  In particular, as far as I can see, none of 
> > that compatibility support is present for printf-like functions in argp.h, 
> > err.h and error.h.  Unless there's some reason I'm missing why no 
> > compatibility support was needed for those functions in the original 
> > 2004-6 changes (Jakub?), there's an ABI bug there that we can't now do 
> > anything about for the original transition (because old and new binaries 
> > use the same symbol versions for those functions, with old binaries 
> > expecting long double = double and new binaries expecting distinct long 
> > double), but that we can avoid for a future transition.  I don't know if 
> > any other affected functions are missing such compatibility support.
> > 
> Ok we will investigate this. I don't seeing what the issues are with 
> argp.h and err.h but looks like the error() and error_at_line() format 
> strings could be a problem.

argp_error and argp_failure take a format string and variable arguments.  
Thus, they are affected by the ABI for long double - users may 
legitimately pass long double arguments to those functions.  The same 
applies to v?warnx? and v?errx?.

> > On point 5.2 (uses of long double in double functions): the correct fix is 
> > to remove that use, along with the multiple-precision code that can make 
> > the functions very slow, after doing sufficient error analysis of the 
> > initial code in the functions to verify that by itself it yields results 
> > with better than 1ulp accuracy, and so well within glibc's accuracy goals.  
> > That will mean that long double performance has no effect on performance 
> > of double libm functions.
> 
> I only found one example of this (./sysdeps/ieee754/dbl-64/slowpow.c) 
> and that usage was wrapped in a conditional (#ifdef 
> USE_LONG_DOUBLE_FOR_MP).

slowexp.c also has such uses.  I think those are the only cases.

> > Note that much of the glibc work could be done in the context of 
> > supporting explicit __float128 functions for x86_64 - all GCC versions 
> > supported for building glibc already support __float128, and differences 
> > between __float128 and TS 18661-4 _Float128 should be easy to work around 
> > when building with older GCC even if proper GCC _Float128 support would be 
> > a preferred stating point (it allows you e.g. to write _Complex _Float128, 
> > which isn't possible with __float128).  That wouldn't include anything 
> > related to changing the type of long double, and would still have a large 
> > amount of work on design, obtaining consensus and implementation, but 
> > would allow a large proportion of the work to go in even before the 
> > minimum GCC version for building powerpc glibc is increased and so 
> > __float128 support can be added for powerpc glibc.
> > 
> A I suggested about, creating ./ieee754/ldbl-f128 would be the simplest
> and safest way to start this effort.

I don't think you'll get consensus to add such a directory without 
substantial design work first.  I can think of several more indirectly 
related incremental changes that would be much more likely candidates for 
"simplest and safest", once things get to the point of such source code 
changes being appropriate.

As one example, a refactoring of the type-generics used (both in installed 
headers and internally) for macros such as signbit.  Because glibc would 
be supporting a set of floating-point types depending on the architecture, 
those macros would need to go via macros with architecture-specific 
definitions.  And because it will no longer be possible to distinguish all 
such types using sizeof, it will be necessary to use other features such 
as __builtin_types_compatible_p or _Generic.  __builtin_types_compatible_p 
is GCC-specific, but supported by more GCC versions than C11 _Generic, 
which also runs into issues with different handling of qualified types in 
different implementations (see DR#423) that would need allowing for.  So 
even such a small piece involves significant design and analysis work to 
determine and justify the design chosen - but is of much lower risk than 
things involving adding new functions or sysdeps directories.

(The type-generics in <tgmath.h> are much more complicated than that, but 
are one of the many things that would need addressing eventually.  See my 
recent observations on the WG14 reflector 
<http://www.open-std.org/jtc1/sc22/wg14/13831>.)

As another example, going through testcases that test for one or more of 
float / double / long double and making those testcases type-generic as 
far as possible so that (a) they may test for existing types not currently 
covered and (b) it's easy to extend them to __float128 in future and we 
have a good understanding of what tests to extend.

As a third example, refactoring the implementations of <complex.h> 
functions to make them type-generic using macros.  This would mean less 
mechanical work in future to update multiple versions of a function when 
fixing a bug, as well as making it easier to add __float128 versions of 
those functions in future.

I'm not saying that one of those should necessarily be the starting point; 
they're simply illustrative examples of some of the simpler pieces that 
might appear fairly early given a more detailed design for the issues that 
need to be addressed and the rough patch sequence involved in addressing 
them.  Even if you prototype changes involving new directories before 
filling in such pieces, I think such pieces would need to appear early in 
the long patch series (and personally I think prefetching implementation 
and mainlining work on such pieces is generally beneficial).


Now, here are some examples of issues to consider in the design and 
consensus-building process.  Where I suggest answers here, I am *not* 
asserting that only a particular answer is acceptable - what is or is not 
required is determined by the community through a consensus process, and 
generally these are cases where if making such changes myself I'd still 
want to allow for the community to reach consensus first rather than 
acting as libm maintainer to treat something as having consensus in the 
absence of discussion.  It's only the two principles I stated in 
<https://sourceware.org/ml/libc-alpha/2015-09/msg00751.html> about ABI 
compatibility requirements that I'm confident asserting as definite 
requirements here, that are well-enough established no further discussion 
of them is required to understand their application to this case.

* We need to agree that the prior rejection of __float128 support in 
<https://sourceware.org/ml/libc-alpha/2004-03/msg00326.html> and 
<https://sourceware.org/ml/libc-alpha/2004-05/msg00055.html> no longer 
stands, in the light of the existence of standard C bindings in TS 
18661-3.  I don't think there should be any controversy about superseding 
such an old decision, but it should still be clear that we are doing so.

* We need to agree on the appropriateness of APIs from TS 18661 - that is, 
to get consensus on a whole set of APIs being appropriate for glibc, so 
that doesn't need redebating every time an individual new API is proposed.  
The APIs from parts 1, 3 and 4, excluding those relating to decimal 
floating point, seem a reasonable set to consider in such a discussion 
(with a clear expectation that such APIs could then be added piecemeal, 
with individual patches still needing consensus on the merits of the 
implementation).  (If controversial, the minimal set for present purposes 
would be the _Float128 APIs from part 3 that correspond to APIs already 
present in glibc for other floating-point types, but I hope it would be 
possible to obtain consensus on a wider set of APIs.)

* We need to agree on rules for ABIs corresponding to such APIs.  My 
suggestion is: where an API meets the ISO C rules for being usable without 
including a header, the function needs an exported symbol with the same 
name (for example, if we support sinf128 on a platform where long double 
is binary128, there does actually need to be a sinf128 exported symbol, 
not just a header redirecting calls to use sinl).  But if it doesn't meet 
such rules, the number of exported symbols should be kept to a minimum 
(for example, functions that exist only for use by type-generic macros 
should not have such aliases).  Functions would go in libc or libm 
according to what header has the declaration, unless consistency with 
existing functions dictates otherwise (e.g. __isinff128 might go in libc 
because other __isinf* functions are there).

* We need to consider what to do about functions not included in TS 
18661-3.  Some possible cases: (a) function aliases such as drem or gamma 
or pow10 shouldn't have *f128 versions.  (b) Obsolescent functions such as 
scalb shouldn't either (though they'll still need long double = binary128 
versions, but not the *f128 APIs).  (c) Where TS 18661 has clearly chosen 
a different direction, do not add *f128 APIs for the old functions (so no 
nexttoward or printf variants - maybe add nextdown, nextup, strfrom 
functions instead as preparatory patches - again, long double = binary128 
verisons will still be needed).  (d) In some cases, *f128 functions as GNU 
APIs are clearly reasonable by analogy - for example, strtof128_l, 
wcstof128, lgammaf128_r.  (e) As a community, we should think especially 
carefully about what to do in cases where the above might miss some 
functionality, e.g. support for grouping when reading strings to 
__float128, or strfmon formatting of __float128 values (the answer might 
well end up being that this functionality can only be accessed in the case 
where long double = __float128).  (f) M_* constants in math.h (needed in 
the implementations in any case).  (Part of the design process is to get a 
*complete* list of such cases for consideration.)

* Would it be best to avoid the new interfaces supporting matherr / 
_LIB_VERSION?  It's been discussed before that we'd like to deprecate that 
functionality; proper deprecation could mean new symbol versions for 
affected functions that avoid using the _LIB_VERSION global at all.  It 
would be unfortunate to add multiple versions of *f128 in quick 
succession, first with _LIB_VERSION support and then without.  This seems 
desirable to discuss even if we end up concluding it's best not to make 
this a dependency.

* Many more specific questions regarding details of the design and 
implementation approach in different areas.

* While working on it, it's important to pay attention to how the work 
relates to the details of TS 18661 and to ongoing discussions in WG14 and 
to track cases where possible issues or ambiguities in TS 18661 are found 
- and to pass such information back to WG14 for consideration when it's 
considered whether to include parts of TS 18661 in the next revision of 
the C standard (actually having an implementation of parts of part 3 might 
make it more likely to be included in the next revision).

-- 
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]