[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