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 |
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 --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