This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
RFC: TS 18661-3 and related floating-point interfaces
- From: Joseph Myers <joseph at codesourcery dot com>
- To: <libc-alpha at sourceware dot org>
- Date: Mon, 16 Jan 2017 23:28:36 +0000
- Subject: RFC: TS 18661-3 and related floating-point interfaces
- Authentication-results: sourceware.org; auth=none
ISO/IEC TS 18661-3:2015 provides C interfaces for IEEE 754-2008
interchange and extended types, such as _FloatN and _FloatNx type
names. I've implemented the compiler side of support for those type
names (and constant suffixes, <float.h> macros etc.) for GCC 7.
We have existing consensus for adding support for _Float128 functions
to glibc for powerpc64le (and for other architectures where the GCC
support is present, the type is ABI-distinct from long double and
someone wishes to implement the glibc support), following the naming
scheme (*f128 functions) from TS 18661-3. This includes such
functions for non-obsolescent glibc interfaces present for other
floating-point types, that do not appear in TS 18661-3. The following
is not intended to affect that existing consensus or to impose any new
requirements on the powerpc64le work; rather, it's intended to
establish a more general consensus about support for such types in
glibc, fully consistent with what's been discussed for float128.
Everything here is also only concerned with binary types (_FloatN and
_FloatNx), not decimal types (_DecimalN and _DecimalNx). This builds
on the provisional consensus for TS 18661 binary functions following
from <https://sourceware.org/ml/libc-alpha/2015-11/msg00162.html>.
The following general principles apply to adding interfaces for such
types:
* For each ABI (as listed at
<https://sourceware.org/glibc/wiki/ABIList>), the set of functions
provided by each glibc shared library must not depend on the
compiler used to build glibc. Thus, to support such a type in glibc
for a given ABI means that all GCC versions that are supported for
building glibc for that ABI must be able to build the functions for
that type (possibly under another name, such as __float128).
* At any given time, there is a set of APIs that should be supported
for any such floating-point type. Roughly, this consists of
non-obsolescent interfaces that are supported for long double (have
explicit long double versions rather than variadic printf / scanf /
strfmon functions) (plus type-generic macros). For any (ABI, type)
pair, either all such interfaces should be supported, or none of
them should be supported (modulo the ability of some type-generic
macros to work for types otherwise unknown to glibc by using
type-generic GCC built-in functions). However, support for a given
type may be added in different glibc versions for different ABIs.
* New functions should not support the obsolescent matherr /
_LIB_VERSION error handling system. For newly supported formats,
this means using new wrapper versions (as in the float128 branch).
For types ABI-compatible with float, double or long double, either
new wrappers must be used, or existing ones can be aliased in shared
libm only provided matherr and _LIB_VERSION have *first* been made
into compat symbols so that no release allows binaries to be built
where the new functions can see nondefault _LIB_VERSION values or
use matherr.
* All the usual test and documentation requirements apply to new
functions where the corresponding functions for existing types are
tested or documented (but without requiring tests or documentation
to be added if the corresponding float / double / long double
functions are completely untested or undocumented). (Documentation
might list functions generically for _FloatN rather than naming each
separate version of every function individually - so the
documentation for sin could document sinf@var{n} and sinf@var{n}x
rather than separately listing sinf32, sinf64, sinf128, etc.)
In more detail:
* Where the public interface is a function, a function export is added
to the appropriate library (generally libm) even if it aliases an
existing function. Where an implementation-namespace function is
used as part of implementating a type-generic macro, or through asm
redirection for a function, it is *only* added for newly supported
formats, avoiding duplication of such functions where more than one
type has the same ABI. Thus, for example, there is no __isinff32
because the isinf type-generic macro can arrange to call __isinff
for _Float32 arguments, and no __logf32_finite because
bits/math-finite.h can arrange to redirect logf32 calls to the same
__logf_finite function as logf gets redirected to.
* The following are considered obsolescent and do *not* get versions
for _Float* types: ecvt, fcvt, gcvt functions; pow10 (alias of
exp10); isinf function (use isinf type-generic macro instead);
finite function (use isfinite type-generic macro instead); drem
(alias of remainder); significand; isnan function (use isnan
type-generic macro instead); gamma (alias of lgamma); nexttoward;
scalb.
* The M_* constants are defined only for double and long double, not
for float. We already agreed in the float128 discussions that
corresponding constants are to be defined for _Float128, and the
float128 patches do just that. For consistency between types, I
consider them appropriate for all the new types, even ones narrower
than double (and arguably we should add such constants for float as
well).
* The conditions under which a new interface is declared in the
headers can be complicated. The following are always necessary:
- The relevant type is supported by the compiler, possibly under a
different name such as __float128 (and with consequently different
constant suffixes etc.).
- The relevant type is supported by this glibc ABI.
- __GLIBC_USE (IEC_60559_TYPES_EXT) is true, whether through
__STDC_WANT_IEC_60559_TYPES_EXT__ having been defined, or through
being implied by another feature test macro such as _GNU_SOURCE.
If the interface is one defined in TS 18661-3, those conditions are
all that are required, with one caveat: since TS 18661-3 builds on
C11, if __STDC_WANT_IEC_60559_TYPES_EXT__ is defined, but the other
feature test macros / compiler predefines do not result in
__USE_ISOC11 being defined, it is unspecified whether the interface
is declared or not. For such combinations (18661-3 without C11), it
may depend on internal details of header conditionals whether
something gets declared or not and this may not be stable between
glibc versions. (Some IEC_60559_BFP_EXT cases in bits/mathcalls.h
are inside other conditionals, some aren't.) As a
quality-of-implementation matter, it's best for
__STDC_WANT_IEC_60559_TYPES_EXT__ alone to suffice to declare the
associated interfaces, even in the non-C11 case.
Note that the TS 18661-3 versions of TS 18661-1 interfaces are meant
to be declared if __STDC_WANT_IEC_60559_TYPES_EXT__ is defined even
if __STDC_WANT_IEC_60559_BFP_EXT__ is not defined and so the float /
double / long double versions of those functions are not declared.
(This makes more logical sense than one might think at first when
you remember that TS 18661-3 builds on either -1 or -2 so is valid
for implementations not supporting the -1 functions at all.)
For other interfaces: in general it is necessary and sufficient for
the above conditions to hold together with the conditions under
which the long double interface is declared, with the same caveat as
above about non-C11 cases of TS 18661-3 being unspecified. However,
C99 includes wcstold, but TS 18661-3 does not include wcstofN /
wcstofNx. Those new functions should be included in glibc, but need
__USE_GNU conditionals to avoid violating TS 18661-3 namespace
rules.
* Type-generic macros in math.h should always support the new types if
supported by the compiler and the glibc ABI, regardless of feature
test macros defined.
* tgmath.h macros are only expected to support expanding to call
functions for which declarations are visible. See
<http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2061.htm#dr_3>
regarding consistency of feature test macro definitions between
includes of <math.h>, <complex.h> and <tgmath.h>. There's at least
one further DR not yet in the public DR log concerning the rules for
determining which function is called by a type-generic macro (the
proposed effect of which is to align those rules with the usual
arithmetic conversions, with integer arguments treated as type
double, i.e. a lot easier to implement than the existing TS
wording); see DDR#7 in
<http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2077.pdf>. There
may well be further ambiguities left in the tgmath.h specification
for the new types and functions.
* Right now we don't support the TS 18661-1 functions that round
result to narrower type (I didn't get to those in the TS 18661-1
implementation work for 2.25). Once such functions are in glibc,
they will be expected to be included also for *pairs* of new types,
following the rules in TS 18661-3 for which such pairs get such
functions. Thus, this imposes no requirements for what functions
are supported when adding a new type until there are at least one
such function and at least two such types in glibc.
* TS 18661-3 also includes a few new interfaces that are *only* for
the new types (or non-arithmetic interchange encodings) and not for
float, double and long double. I propose these be considered
appropriate for glibc, on the basis that when a function is added
it's added for all relevant types supported in glibc and then for
any new such types added in future, but different functions may be
added at different times as long as each function present is present
for all relevant types. This applies to the following:
- For new _FloatN types: encodefN, decodefN.
- For supported interchange formats (arithmetic or non-arithmetic):
strtoencfN, strfromencfN.
- For pairs of supported interchange formats (arithmetic or
non-arithmetic): fMencfN. (This is for all pairs in any order,
including conversion from a format to itself - which is a valid
IEEE operation that quiets signaling NaNs.)
I also propose that binary16 be the only supported non-arithmetic
interchange format, with others being supported for the functions on
interchange formats only when glibc supports a floating-point type
with that format. binary16 support is required, while others are
optional, and if you support e.g. binary128 as a non-arithmetic
interchange format on a system that doesn't support it for
arithmetic, that also implies DECIMAL_DIG in <float.h> needs to be
increased accordingly.
All the functions dealing with interchange encodings would use
native endianness for the arrays of bytes (TS 18661-3 leaves the
endianness implementation-defined). This means encodefN and
decodefN can have trivial implementations that just use memcpy.
(I've just raised the question with WG14 of what these encoding
functions should do in the non-NAN2008 MIPS and HPPA case of
floating-point types using the non-preferred convention for quiet
and signaling NaNs.)
Any comments on this proposal regarding inclusion of TS 18661-3
functions and similar functions for the new types in glibc?
--
Joseph S. Myers
joseph@codesourcery.com