diff mbox series

[v5] Fix for powerpc64 long double complex divide failure

Message ID 1630094373-18151-1-git-send-email-patrick.mcgehearty@oracle.com
State New
Headers show
Series [v5] Fix for powerpc64 long double complex divide failure | expand

Commit Message

Patrick McGehearty Aug. 27, 2021, 7:59 p.m. UTC
This revision (v5) adds a test in libgcc/libgcc2.c for when
"__LIBGCC_TF_MANT_DIG__ == 106" to use __LIBGCC_DF_EPSILON__ instead
of __LIBGCC_TF_EPSILON__. That is specific to IBM 128-bit format long
doubles where EPSILON is very, very small and 1/EPSILON oveflows to
infinity. This change avoids the overflow without affecting any other
platform. Discussion in the patch is adjusted to reflect this
limitation.

It does not make any changes to .../rs6000/_divkc3.c, leaving it to
use __LIBGCC_KF__*. That means the upstream gcc will not build in
older IBM environments that do not recognize the KF floating point
mode properly. Environments that do not need IBM longdouble support do
build cleanly.

- - - -
This patch addresses the failure of powerpc64 long double complex divide
in native ibm long double format after the patch "Practical improvement
to libgcc complex divide".

The new code uses the following macros which are intended to be mapped
to appropriate values according to the underlying hardware representation.
See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101104

RBIG     a value near the maximum representation
RMIN     a value near the minimum representation
         (but not in the subnormal range)
RMIN2    a value moderately less than 1
RMINSCAL the inverse of RMIN2
RMAX2    RBIG * RMIN2  - a value to limit scaling to not overflow

When "long double" values were not using the IEEE 128-bit format but
the traditional IBM 128-bit, the previous code used the LDBL values
which caused overflow for RMINSCAL. The new code uses the DBL values.

RBIG  LDBL_MAX = 0x1.fffffffffffff800p+1022
      DBL_MAX  = 0x1.fffffffffffff000p+1022

RMIN  LDBL_MIN = 0x1.0000000000000000p-969
RMIN  DBL_MIN  = 0x1.0000000000000000p-1022

RMIN2 LDBL_EPSILON = 0x0.0000000000001000p-1022 = 0x1.0p-1074
RMIN2 DBL_EPSILON  = 0x1.0000000000000000p-52

RMINSCAL 1/LDBL_EPSILON = inf (1.0p+1074 does not fit in IBM 128-bit).
         1/DBL_EPSILON  = 0x1.0000000000000000p+52

RMAX2 = RBIG * RMIN2 = 0x1.fffffffffffff800p-52
        RBIG * RMIN2 = 0x1.fffffffffffff000p+970

The MAX and MIN values have only modest changes since the maximum and
minimum values are about the same as for double precision.  The
EPSILON field is considerably different. Due to how very small values
can be represented in the lower 64 bits of the IBM 128-bit floating
point, EPSILON is extremely small, so far beyond the desired value
that inversion of the value overflows and even without the overflow,
the RMAX2 is so small as to eliminate most usage of the test.

The change has been tested on gcc135.fsffrance.org and gains the
expected improvements in accuracy for long double complex divide.

libgcc/
	PR target/101104
	* libgcc2.c (RMIN2, RMINSCAL, RMAX2):
	Use more correct values for native IBM 128-bit.
---
 libgcc/libgcc2.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

Comments

Patrick McGehearty Sept. 8, 2021, 7:48 p.m. UTC | #1
Ping
Note: I don't have commit privileges for gcc.

On 8/27/2021 2:59 PM, Patrick McGehearty via Gcc-patches wrote:
> This revision (v5) adds a test in libgcc/libgcc2.c for when
> "__LIBGCC_TF_MANT_DIG__ == 106" to use __LIBGCC_DF_EPSILON__ instead
> of __LIBGCC_TF_EPSILON__. That is specific to IBM 128-bit format long
> doubles where EPSILON is very, very small and 1/EPSILON oveflows to
> infinity. This change avoids the overflow without affecting any other
> platform. Discussion in the patch is adjusted to reflect this
> limitation.
>
> It does not make any changes to .../rs6000/_divkc3.c, leaving it to
> use __LIBGCC_KF__*. That means the upstream gcc will not build in
> older IBM environments that do not recognize the KF floating point
> mode properly. Environments that do not need IBM longdouble support do
> build cleanly.
>
> - - - -
> This patch addresses the failure of powerpc64 long double complex divide
> in native ibm long double format after the patch "Practical improvement
> to libgcc complex divide".
>
> The new code uses the following macros which are intended to be mapped
> to appropriate values according to the underlying hardware representation.
> See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101104
>
> RBIG     a value near the maximum representation
> RMIN     a value near the minimum representation
>           (but not in the subnormal range)
> RMIN2    a value moderately less than 1
> RMINSCAL the inverse of RMIN2
> RMAX2    RBIG * RMIN2  - a value to limit scaling to not overflow
>
> When "long double" values were not using the IEEE 128-bit format but
> the traditional IBM 128-bit, the previous code used the LDBL values
> which caused overflow for RMINSCAL. The new code uses the DBL values.
>
> RBIG  LDBL_MAX = 0x1.fffffffffffff800p+1022
>        DBL_MAX  = 0x1.fffffffffffff000p+1022
>
> RMIN  LDBL_MIN = 0x1.0000000000000000p-969
> RMIN  DBL_MIN  = 0x1.0000000000000000p-1022
>
> RMIN2 LDBL_EPSILON = 0x0.0000000000001000p-1022 = 0x1.0p-1074
> RMIN2 DBL_EPSILON  = 0x1.0000000000000000p-52
>
> RMINSCAL 1/LDBL_EPSILON = inf (1.0p+1074 does not fit in IBM 128-bit).
>           1/DBL_EPSILON  = 0x1.0000000000000000p+52
>
> RMAX2 = RBIG * RMIN2 = 0x1.fffffffffffff800p-52
>          RBIG * RMIN2 = 0x1.fffffffffffff000p+970
>
> The MAX and MIN values have only modest changes since the maximum and
> minimum values are about the same as for double precision.  The
> EPSILON field is considerably different. Due to how very small values
> can be represented in the lower 64 bits of the IBM 128-bit floating
> point, EPSILON is extremely small, so far beyond the desired value
> that inversion of the value overflows and even without the overflow,
> the RMAX2 is so small as to eliminate most usage of the test.
>
> The change has been tested on gcc135.fsffrance.org and gains the
> expected improvements in accuracy for long double complex divide.
>
> libgcc/
> 	PR target/101104
> 	* libgcc2.c (RMIN2, RMINSCAL, RMAX2):
> 	Use more correct values for native IBM 128-bit.
> ---
>   libgcc/libgcc2.c | 9 +++++++--
>   1 file changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/libgcc/libgcc2.c b/libgcc/libgcc2.c
> index 38f935e..bf45576 100644
> --- a/libgcc/libgcc2.c
> +++ b/libgcc/libgcc2.c
> @@ -1906,8 +1906,13 @@ NAME (TYPE x, int m)
>   # define NOTRUNC (!__LIBGCC_TF_EXCESS_PRECISION__)
>   # define RBIG	(__LIBGCC_TF_MAX__ / 2)
>   # define RMIN	(__LIBGCC_TF_MIN__)
> -# define RMIN2	(__LIBGCC_TF_EPSILON__)
> -# define RMINSCAL (1 / __LIBGCC_TF_EPSILON__)
> +# if __LIBGCC_TF_MANT_DIG__ == 106
> +#  define RMIN2  (__LIBGCC_DF_EPSILON__)
> +#  define RMINSCAL (1 / __LIBGCC_DF_EPSILON__)
> +# else
> +#  define RMIN2	(__LIBGCC_TF_EPSILON__)
> +#  define RMINSCAL (1 / __LIBGCC_TF_EPSILON__)
> +# endif
>   # define RMAX2	(RBIG * RMIN2)
>   #else
>   # error
diff mbox series

Patch

diff --git a/libgcc/libgcc2.c b/libgcc/libgcc2.c
index 38f935e..bf45576 100644
--- a/libgcc/libgcc2.c
+++ b/libgcc/libgcc2.c
@@ -1906,8 +1906,13 @@  NAME (TYPE x, int m)
 # define NOTRUNC (!__LIBGCC_TF_EXCESS_PRECISION__)
 # define RBIG	(__LIBGCC_TF_MAX__ / 2)
 # define RMIN	(__LIBGCC_TF_MIN__)
-# define RMIN2	(__LIBGCC_TF_EPSILON__)
-# define RMINSCAL (1 / __LIBGCC_TF_EPSILON__)
+# if __LIBGCC_TF_MANT_DIG__ == 106
+#  define RMIN2  (__LIBGCC_DF_EPSILON__)
+#  define RMINSCAL (1 / __LIBGCC_DF_EPSILON__)
+# else
+#  define RMIN2	(__LIBGCC_TF_EPSILON__)
+#  define RMINSCAL (1 / __LIBGCC_TF_EPSILON__)
+# endif
 # define RMAX2	(RBIG * RMIN2)
 #else
 # error