This patch resolves the failure of powerpc64 long double complex divide in native ibm long double format after the patch "Practical improvement to libgcc complex divide". See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101104
The new code uses the following macros which are intended to be mapped to appropriate values according to the underlying hardware representation. 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 exponent field for IBM 128-bit floating point values is the same size as the exponent field for IBM 64-bit floating point values. However the EPSILON field is considerably different. Due to how 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. In addition, the gcc support for the KF fields (IBM native long double format) does not exist on older gcc compilers such as the default compilers on the gcc compiler farm. That adds build complexity for users who's environment is only a few years out of date. Instead of just replacing the use of KF_EPSILON with DF_ESPILON, we replace all uses of KF_* with DF_*. The change has been tested on gcc135.fsffrance.org and gains the expected improvements in accuracy for long double complex divide. libgcc/ * config/rs6000/_divkc3.c (RBIG, RMIN, RMIN2, RMINSCAL, RMAX2): Fix long double complex divide for native IBM 128-bit --- libgcc/config/rs6000/_divkc3.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libgcc/config/rs6000/_divkc3.c b/libgcc/config/rs6000/_divkc3.c index a1d29d2..2b229c8 100644 --- a/libgcc/config/rs6000/_divkc3.c +++ b/libgcc/config/rs6000/_divkc3.c @@ -38,10 +38,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #endif #ifndef __LONG_DOUBLE_IEEE128__ -#define RBIG (__LIBGCC_KF_MAX__ / 2) -#define RMIN (__LIBGCC_KF_MIN__) -#define RMIN2 (__LIBGCC_KF_EPSILON__) -#define RMINSCAL (1 / __LIBGCC_KF_EPSILON__) +#define RBIG (__LIBGCC_DF_MAX__ / 2) +#define RMIN (__LIBGCC_DF_MIN__) +#define RMIN2 (__LIBGCC_DF_EPSILON__) +#define RMINSCAL (1 / __LIBGCC_DF_EPSILON__) #define RMAX2 (RBIG * RMIN2) #else #define RBIG (__LIBGCC_TF_MAX__ / 2) -- 1.8.3.1