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


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