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]

RFC: TS 18661-3 and related floating-point interfaces


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


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