[PATCH 7/7] stdio-common: Skip the a and A conversions for the IBM extended format

Adhemerval Zanella Netto adhemerval.zanella@linaro.org
Wed Sep 2 17:22:46 GMT 2026



On 24/08/26 19:16, Matt Turner wrote:
> The reference implementation renders the a and A conversions by
> splitting the value into a significand of the width the type has and a
> power of two. That presumes the type is a single binary floating-point
> format.  The IBM extended format is a pair of doubles instead, whose
> combined significand has no fixed width and whose subnormals are those
> of the low double rather than of the type, so what glibc produces for it
> does not follow from PREC and MINEXP: LDBL_MAX comes out as
> 0x1.fffffffffffff7ffffffffffff8p+1023 with twenty-eight fractional
> digits where the value has at most twenty-six worth of significand, and
> LDBL_TRUE_MIN as 0x0.0000000000001p-1022, which is the smallest
> subnormal double and nowhere near LDBL_MIN_EXP.
> 
> The remaining conversions are unaffected, as they work from the value
> rather than from a decomposition of it, and were verified to be.
> 
> Add an UNSUPPORTED_CONVS definition to the skeleton for conversions that
> cannot be modeled for the type at hand, and set it to the a and A pair
> where long double has that format, the generator then producing no
> records and an unsupported status which the long double wrapper reports.
> 
> This does not come up in practice: powerpc64le is the one target with
> the format, and it builds everything with the IEEE format instead, so
> the test programs there see a 113 bit significand.  

The IBM extended precision is also used on powerpc32 and powerpc64 (where
it is the default), and still the default ABI on powerpc64le:

* cfarm121 (powerpc32/powerpc64 BE ELFv1):

$ cat /etc/debian_version
forky/sid
$ echo | gcc -E -dM -xc - | grep -E 'LDBL_MANT_DIG|LONG_DOUBLE'
#define __LDBL_MANT_DIG__ 106
#define __SIZEOF_LONG_DOUBLE__ 16
#define __LONG_DOUBLE_IBM128__ 1
#define __LONG_DOUBLE_128__ 1
$ gcc -v 2>&1 | tr ' ' '\n' | grep -i long-double
--with-long-double-128


* cfarm120 (powerpc64le LE ELFv2):

$ cat /etc/redhat-release
AlmaLinux release 9.8 (Olive Jaguar)
$ echo | gcc -E -dM -xc - | grep -E 'LDBL_MANT_DIG|LONG_DOUBLE'
#define __LDBL_MANT_DIG__ 106
#define __SIZEOF_LONG_DOUBLE__ 16
#define __LONG_DOUBLE_IBM128__ 1
#define __LONG_DOUBLE_128__ 1
$ gcc -v 2>&1 | tr ' ' '\n' | grep -i long-double
--with-long-double-128

The last powerpc64le ABI did 'phase-in' the IEEE Binary 128 [1], and
it is fully supported on gcc (and for -mcpu=power9 it generates 
proper VSX instruction without the need to call libgcc). But unless
you explicit configure gcc to default for this format you will need
to use '-mabi=ieeelongdouble' to enable it.

I think it would be better to remove this paragraph.

[1] https://openpowerfoundation.org/specifications/64bitelfabi/

That is done for
> shared builds only though, which leaves the conversions failing where
> shared libraries have been turned off.
> 
> Tested on x86_64-linux-gnu and powerpc64le-linux-gnu, where all 672
> results pass, and with the long double conversions forced to the IBM
> extended format, where the a and A ones report unsupported and the rest
> continue to pass.

The rest look ok, thanks.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org)

> ---
>  stdio-common/tst-printf-format-ldouble.sh         | 13 +++++++++++--
>  stdio-common/tst-printf-format-skeleton-ldouble.c |  9 +++++++++
>  stdio-common/tst-printf-format-skeleton.c         | 15 ++++++++++++++-
>  3 files changed, 34 insertions(+), 3 deletions(-)
> 
> diff --git ./stdio-common/tst-printf-format-ldouble.sh ./stdio-common/tst-printf-format-ldouble.sh
> index 2be2a592e0..b62296b11c 100644
> --- ./stdio-common/tst-printf-format-ldouble.sh
> +++ ./stdio-common/tst-printf-format-ldouble.sh
> @@ -26,13 +26,22 @@ test_program_prefix=$1; shift
>  
>  status=0
>  
> -echo Verifying $format
> +rc=0
>  (set -o pipefail
>   ${test_program_prefix} \
>    ${common_objpfx}stdio-common/tst-printf-format-${xprintf}-ldouble $format |
>     ${PYTHON:-python3} tst-printf-format.py 2>&1 |
>     head -n 1 |
>     sed "s/^/Conversion $format output error, first line:\n/") 2>&1 ||
> -  status=1
> +  rc=$?
> +
> +# The generator produces no records and reports an unsupported status for
> +# a conversion the verification cannot model for the long double format in
> +# use; see UNSUPPORTED_CONVS in tst-printf-format-skeleton-ldouble.c.
> +case $rc in
> +0)  echo Verifying $format ;;
> +77) echo Unsupported $format; status=77 ;;
> +*)  echo Verifying $format; status=1 ;;
> +esac
>  
>  exit $status

Ok.

> diff --git ./stdio-common/tst-printf-format-skeleton-ldouble.c ./stdio-common/tst-printf-format-skeleton-ldouble.c
> index 0c828ec3b5..860b0ace7c 100644
> --- ./stdio-common/tst-printf-format-skeleton-ldouble.c
> +++ ./stdio-common/tst-printf-format-skeleton-ldouble.c
> @@ -28,6 +28,15 @@
>  #define REF_VAL(v) (v)
>  #define PREC LDBL_MANT_DIG
>  #define MINEXP LDBL_MIN_EXP
> +#if LDBL_MANT_DIG == 106
> +/* The IBM extended format is a pair of doubles rather than a significand
> +   of a single fixed width, so what the a and A conversions produce for it
> +   does not follow from PREC and MINEXP the way the verification assumes.
> +   Leave them out where the type has that format; the one target concerned
> +   builds everything with the IEEE format instead, so this only comes up
> +   where that has been turned off.  */
> +# define UNSUPPORTED_CONVS "aA"
> +#endif
>  typedef long double type_t;
>  static const type_t vals[] =
>    { -HUGE_VAL, -LDBL_MAX, -LDBL_MIN, -0.0, -NAN, NAN, 0, LDBL_TRUE_MIN,

Ok.

> diff --git ./stdio-common/tst-printf-format-skeleton.c ./stdio-common/tst-printf-format-skeleton.c
> index 6250792d44..ab93e3f654 100644
> --- ./stdio-common/tst-printf-format-skeleton.c
> +++ ./stdio-common/tst-printf-format-skeleton.c
> @@ -41,6 +41,10 @@
>     MINEXP	[optional] Minimum exponent integer constant.  Set to the
>  		*_MIN_EXP value for the argument type handled, so that
>  		subnormal values can be told apart from normal ones.
> +   UNSUPPORTED_CONVS
> +		[optional] String of conversions the verification cannot
> +		model for the argument type handled.  Asking for one of
> +		these produces no records and an unsupported status.
>  
>     Typedefs:
>     type_t	Variadic function argument type.  Define to the promoted
> @@ -67,6 +71,7 @@
>  #include <stdio.h>
>  #include <stdlib.h>
>  #include <string.h>
> +#include <support/test-driver.h>
>  
>  /* Set to nonzero to select all possible tuples with repetitions of 1..n
>     elements from the set of flags as defined in FLAGS array below; n is
> @@ -87,6 +92,11 @@
>  #ifndef MINEXP
>  # define MINEXP 0
>  #endif
> +/* Set to the conversions that cannot be verified for the type handled;
> +   empty where they all can be, which is the usual case.  */
> +#ifndef UNSUPPORTED_CONVS
> +# define UNSUPPORTED_CONVS ""
> +#endif
>  
>  /* The list of conversions permitted for the '#' flag, the '0' flag,
>     and precision respectively.  */
> @@ -333,6 +343,10 @@ do_test (int argc, char *argv[])
>        return EXIT_FAILURE;
>      }
>  
> +  c = *argv[1];
> +  if (strchr (UNSUPPORTED_CONVS, c) != NULL)
> +    return EXIT_UNSUPPORTED;
> +
>    mtrace ();
>  
>    if (PREC != 0 && printf ("prec:%i\n", PREC) < 0)
> @@ -347,7 +361,6 @@ do_test (int argc, char *argv[])
>        return EXIT_FAILURE;
>      }
>  
> -  c = *argv[1];
>    for (v = 0; v < array_length (vals); v++)
>      {
>        if (printf ("val:%" REF_FMT "\n", REF_VAL (vals[v])) < 0)


Ok.


More information about the Libc-alpha mailing list