diff --git a/compiler-rt/lib/builtins/divtc3.c b/compiler-rt/lib/builtins/divtc3.c --- a/compiler-rt/lib/builtins/divtc3.c +++ b/compiler-rt/lib/builtins/divtc3.c @@ -12,44 +12,45 @@ #define QUAD_PRECISION #include "fp_lib.h" -#include "int_lib.h" -#include "int_math.h" + +#if defined(CRT_HAS_TF_MODE) // Returns: the quotient of (a + ib) / (c + id) -COMPILER_RT_ABI Lcomplex __divtc3(long double __a, long double __b, - long double __c, long double __d) { +COMPILER_RT_ABI Qcomplex __divtc3(f128 __a, f128 __b, f128 __c, f128 __d) { int __ilogbw = 0; - long double __logbw = - __compiler_rt_logbl(__compiler_rt_fmaxl(crt_fabsl(__c), crt_fabsl(__d))); + f128 __logbw = __compiler_rt_logbf128( + __compiler_rt_fmaxf128(crt_fabsf128(__c), crt_fabsf128(__d))); if (crt_isfinite(__logbw)) { __ilogbw = (int)__logbw; - __c = __compiler_rt_scalbnl(__c, -__ilogbw); - __d = __compiler_rt_scalbnl(__d, -__ilogbw); + __c = __compiler_rt_scalbnf128(__c, -__ilogbw); + __d = __compiler_rt_scalbnf128(__d, -__ilogbw); } - long double __denom = __c * __c + __d * __d; - Lcomplex z; - COMPLEX_REAL(z) = - __compiler_rt_scalbnl((__a * __c + __b * __d) / __denom, -__ilogbw); - COMPLEX_IMAGINARY(z) = - __compiler_rt_scalbnl((__b * __c - __a * __d) / __denom, -__ilogbw); - if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z))) { + f128 __denom = __c * __c + __d * __d; + Qcomplex z; + COMPLEX128_REAL(z) = + __compiler_rt_scalbnf128((__a * __c + __b * __d) / __denom, -__ilogbw); + COMPLEX128_IMAGINARY(z) = + __compiler_rt_scalbnf128((__b * __c - __a * __d) / __denom, -__ilogbw); + if (crt_isnan(COMPLEX128_REAL(z)) && crt_isnan(COMPLEX128_IMAGINARY(z))) { if ((__denom == 0.0) && (!crt_isnan(__a) || !crt_isnan(__b))) { - COMPLEX_REAL(z) = crt_copysignl(CRT_INFINITY, __c) * __a; - COMPLEX_IMAGINARY(z) = crt_copysignl(CRT_INFINITY, __c) * __b; + COMPLEX128_REAL(z) = crt_copysignf128(CRT_INFINITY, __c) * __a; + COMPLEX128_IMAGINARY(z) = crt_copysignf128(CRT_INFINITY, __c) * __b; } else if ((crt_isinf(__a) || crt_isinf(__b)) && crt_isfinite(__c) && crt_isfinite(__d)) { - __a = crt_copysignl(crt_isinf(__a) ? 1.0 : 0.0, __a); - __b = crt_copysignl(crt_isinf(__b) ? 1.0 : 0.0, __b); - COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c + __b * __d); - COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__b * __c - __a * __d); + __a = crt_copysignf128(crt_isinf(__a) ? (f128)1.0 : (f128)0.0, __a); + __b = crt_copysignf128(crt_isinf(__b) ? (f128)1.0 : (f128)0.0, __b); + COMPLEX128_REAL(z) = CRT_INFINITY * (__a * __c + __b * __d); + COMPLEX128_IMAGINARY(z) = CRT_INFINITY * (__b * __c - __a * __d); } else if (crt_isinf(__logbw) && __logbw > 0.0 && crt_isfinite(__a) && crt_isfinite(__b)) { - __c = crt_copysignl(crt_isinf(__c) ? 1.0 : 0.0, __c); - __d = crt_copysignl(crt_isinf(__d) ? 1.0 : 0.0, __d); - COMPLEX_REAL(z) = 0.0 * (__a * __c + __b * __d); - COMPLEX_IMAGINARY(z) = 0.0 * (__b * __c - __a * __d); + __c = crt_copysignf128(crt_isinf(__c) ? (f128)1.0 : (f128)0.0, __c); + __d = crt_copysignf128(crt_isinf(__d) ? (f128)1.0 : (f128)0.0, __d); + COMPLEX128_REAL(z) = 0.0 * (__a * __c + __b * __d); + COMPLEX128_IMAGINARY(z) = 0.0 * (__b * __c - __a * __d); } } return z; } + +#endif diff --git a/compiler-rt/lib/builtins/extenddftf2.c b/compiler-rt/lib/builtins/extenddftf2.c --- a/compiler-rt/lib/builtins/extenddftf2.c +++ b/compiler-rt/lib/builtins/extenddftf2.c @@ -14,8 +14,6 @@ #define DST_QUAD #include "fp_extend_impl.inc" -COMPILER_RT_ABI fp_t __extenddftf2(double a) { - return __extendXfYf2__(a); -} +COMPILER_RT_ABI f128 __extenddftf2(double a) { return __extendXfYf2__(a); } #endif diff --git a/compiler-rt/lib/builtins/extendhftf2.c b/compiler-rt/lib/builtins/extendhftf2.c --- a/compiler-rt/lib/builtins/extendhftf2.c +++ b/compiler-rt/lib/builtins/extendhftf2.c @@ -15,8 +15,6 @@ #define DST_QUAD #include "fp_extend_impl.inc" -COMPILER_RT_ABI long double __extendhftf2(_Float16 a) { - return __extendXfYf2__(a); -} +COMPILER_RT_ABI f128 __extendhftf2(src_t a) { return __extendXfYf2__(a); } #endif diff --git a/compiler-rt/lib/builtins/extendsftf2.c b/compiler-rt/lib/builtins/extendsftf2.c --- a/compiler-rt/lib/builtins/extendsftf2.c +++ b/compiler-rt/lib/builtins/extendsftf2.c @@ -14,8 +14,6 @@ #define DST_QUAD #include "fp_extend_impl.inc" -COMPILER_RT_ABI fp_t __extendsftf2(float a) { - return __extendXfYf2__(a); -} +COMPILER_RT_ABI f128 __extendsftf2(float a) { return __extendXfYf2__(a); } #endif diff --git a/compiler-rt/lib/builtins/floattitf.c b/compiler-rt/lib/builtins/floattitf.c --- a/compiler-rt/lib/builtins/floattitf.c +++ b/compiler-rt/lib/builtins/floattitf.c @@ -67,7 +67,7 @@ // a is now rounded to LDBL_MANT_DIG bits } - long_double_bits fb; + f128_bits fb; fb.u.high.all = (s & 0x8000000000000000LL) // sign | (du_int)(e + 16383) << 48 // exponent | ((a >> 64) & 0x0000ffffffffffffLL); // significand diff --git a/compiler-rt/lib/builtins/floatuntitf.c b/compiler-rt/lib/builtins/floatuntitf.c --- a/compiler-rt/lib/builtins/floatuntitf.c +++ b/compiler-rt/lib/builtins/floatuntitf.c @@ -65,7 +65,7 @@ // a is now rounded to TF_MANT_DIG bits } - long_double_bits fb; + f128_bits fb; fb.u.high.all = (du_int)(e + 16383) << 48 // exponent | ((a >> 64) & 0x0000ffffffffffffLL); // significand fb.u.low.all = (du_int)(a); diff --git a/compiler-rt/lib/builtins/fp_extend.h b/compiler-rt/lib/builtins/fp_extend.h --- a/compiler-rt/lib/builtins/fp_extend.h +++ b/compiler-rt/lib/builtins/fp_extend.h @@ -67,7 +67,7 @@ static const int dstSigBits = 52; #elif defined DST_QUAD -typedef long double dst_t; +typedef f128 dst_t; typedef __uint128_t dst_rep_t; #define DST_REP_C (__uint128_t) static const int dstSigBits = 112; diff --git a/compiler-rt/lib/builtins/fp_lib.h b/compiler-rt/lib/builtins/fp_lib.h --- a/compiler-rt/lib/builtins/fp_lib.h +++ b/compiler-rt/lib/builtins/fp_lib.h @@ -105,17 +105,12 @@ COMPILER_RT_ABI fp_t __adddf3(fp_t a, fp_t b); #elif defined QUAD_PRECISION -#if __LDBL_MANT_DIG__ == 113 && defined(__SIZEOF_INT128__) -// TODO: Availability of the *tf functions should not depend on long double -// being IEEE 128, but instead on being able to use a 128-bit floating-point -// type, which includes __float128. -// Right now this (incorrectly) stops the builtins from being used for x86. -#define CRT_LDBL_128BIT +#if defined(CRT_HAS_128BIT) && defined(CRT_HAS_F128) #define CRT_HAS_TF_MODE typedef uint64_t half_rep_t; typedef __uint128_t rep_t; typedef __int128_t srep_t; -typedef long double fp_t; +typedef f128 fp_t; #define HALF_REP_C UINT64_C #define REP_C (__uint128_t) // Note: Since there is no explicit way to tell compiler the constant is a @@ -206,13 +201,13 @@ #undef Word_HiMask #undef Word_LoMask #undef Word_FullMask -#endif // __LDBL_MANT_DIG__ == 113 && __SIZEOF_INT128__ +#endif // defined(CRT_HAS_128BIT) && defined(CRT_HAS_F128) #else #error SINGLE_PRECISION, DOUBLE_PRECISION or QUAD_PRECISION must be defined. #endif #if defined(SINGLE_PRECISION) || defined(DOUBLE_PRECISION) || \ - defined(CRT_LDBL_128BIT) + (defined(QUAD_PRECISION) && defined(CRT_HAS_TF_MODE)) #define typeWidth (sizeof(rep_t) * CHAR_BIT) #define exponentBits (typeWidth - significandBits - 1) #define maxExponent ((1 << exponentBits) - 1) @@ -392,31 +387,32 @@ #endif } -#elif defined(QUAD_PRECISION) +#elif defined(QUAD_PRECISION) && defined(CRT_HAS_TF_MODE) -#if defined(CRT_LDBL_128BIT) -static __inline fp_t __compiler_rt_logbl(fp_t x) { +// The generic implementation only works for ieee754 floating point. For other +// floating point types, continue to rely on the libm implementation for now. +#if defined(CRT_HAS_IEEE_F128) +static __inline f128 __compiler_rt_logbf128(f128 x) { return __compiler_rt_logbX(x); } -static __inline fp_t __compiler_rt_scalbnl(fp_t x, int y) { +static __inline f128 __compiler_rt_scalbnf128(f128 x, int y) { return __compiler_rt_scalbnX(x, y); } -static __inline fp_t __compiler_rt_fmaxl(fp_t x, fp_t y) { +static __inline f128 __compiler_rt_fmaxf128(f128 x, f128 y) { return __compiler_rt_fmaxX(x, y); } #else -// The generic implementation only works for ieee754 floating point. For other -// floating point types, continue to rely on the libm implementation for now. -static __inline long double __compiler_rt_logbl(long double x) { +static __inline long double __compiler_rt_logbf128(long double x) { return crt_logbl(x); } -static __inline long double __compiler_rt_scalbnl(long double x, int y) { +static __inline long double __compiler_rt_scalbnf128(long double x, int y) { return crt_scalbnl(x, y); } -static __inline long double __compiler_rt_fmaxl(long double x, long double y) { +static __inline long double __compiler_rt_fmaxf128(long double x, + long double y) { return crt_fmaxl(x, y); } -#endif // CRT_LDBL_128BIT +#endif // CRT_HAS_F128 #endif // *_PRECISION diff --git a/compiler-rt/lib/builtins/fp_trunc.h b/compiler-rt/lib/builtins/fp_trunc.h --- a/compiler-rt/lib/builtins/fp_trunc.h +++ b/compiler-rt/lib/builtins/fp_trunc.h @@ -28,7 +28,7 @@ static const int srcSigBits = 52; #elif defined SRC_QUAD -typedef long double src_t; +typedef f128 src_t; typedef __uint128_t src_rep_t; #define SRC_REP_C (__uint128_t) static const int srcSigBits = 112; diff --git a/compiler-rt/lib/builtins/int_math.h b/compiler-rt/lib/builtins/int_math.h --- a/compiler-rt/lib/builtins/int_math.h +++ b/compiler-rt/lib/builtins/int_math.h @@ -65,6 +65,12 @@ #define crt_copysign(x, y) __builtin_copysign((x), (y)) #define crt_copysignf(x, y) __builtin_copysignf((x), (y)) #define crt_copysignl(x, y) __builtin_copysignl((x), (y)) +#if __has_builtin(__builtin_copysignf128) +#define crt_copysignf128(x, y) __builtin_copysignf128((x), (y)) +#elif __has_builtin(__builtin_copysignq) || (defined(__GNUC__) && __GNUC__ >= 7) +#define crt_copysignf128(x, y) __builtin_copysignq((x), (y)) +#elif +#endif #endif #if defined(_MSC_VER) && !defined(__clang__) @@ -75,6 +81,11 @@ #define crt_fabs(x) __builtin_fabs((x)) #define crt_fabsf(x) __builtin_fabsf((x)) #define crt_fabsl(x) __builtin_fabsl((x)) +#if __has_builtin(__builtin_fabsf128) +#define crt_fabsf128(x) __builtin_fabsf128((x)) +#elif __has_builtin(__builtin_fabsq) || (defined(__GNUC__) && __GNUC__ >= 7) +#define crt_fabsf128(x) __builtin_fabsq((x)) +#endif #endif #if defined(_MSC_VER) && !defined(__clang__) diff --git a/compiler-rt/lib/builtins/int_types.h b/compiler-rt/lib/builtins/int_types.h --- a/compiler-rt/lib/builtins/int_types.h +++ b/compiler-rt/lib/builtins/int_types.h @@ -165,6 +165,45 @@ #define HAS_80_BIT_LONG_DOUBLE 0 #endif +#ifdef __powerpc64__ +// From https://gcc.gnu.org/wiki/Ieee128PowerPC: +// PowerPC64 uses the following suffixes: +// IFmode: IBM extended double +// KFmode: IEEE 128-bit floating point +// TFmode: Matches the default for long double. With -mabi=ieeelongdouble, +// it is IEEE 128-bit, with -mabi=ibmlongdouble IBM extended double +// Since compiler-rt only implements the tf set of libcalls, we use long double +// for the f128 typedef. +typedef long double f128; +#define CRT_LDBL_128BIT +#define CRT_HAS_F128 +#ifndef __LONG_DOUBLE_IBM128__ +#warning compiler-rt builtins implementation may assume IEEE representation \ + and return incorrect results for tf functions +#else +#define CRT_HAS_IEEE_F128 +#endif +#elif __LDBL_MANT_DIG__ == 113 +// Use long double instead of __float128 if it matches the IEEE 128-bit format. +#define CRT_LDBL_128BIT +#define CRT_HAS_F128 +#define CRT_HAS_IEEE_F128 +typedef long double f128; +#elif defined(__FLOAT128__) || defined(__SIZEOF_FLOAT128__) +#define CRT_HAS___FLOAT128_KEYWORD +#define CRT_HAS_F128 +// NB: we assume the __float128 type uses IEEE representation. +#define CRT_HAS_IEEE_F128 +typedef __float128 f128; +#endif + +#ifdef CRT_HAS_F128 +typedef union { + uqwords u; + f128 f; +} f128_bits; +#endif + #if CRT_HAS_FLOATING_POINT typedef union { uqwords u; @@ -175,6 +214,20 @@ typedef float _Complex Fcomplex; typedef double _Complex Dcomplex; typedef long double _Complex Lcomplex; +#if defined(CRT_LDBL_128BIT) +typedef Lcomplex Qcomplex; +#define CRT_HAS_NATIVE_COMPLEX_F128 +#elif defined(CRT_HAS___FLOAT128_KEYWORD) +#if defined(__clang_major__) && __clang_major__ > 10 +// Clang prior to 11 did not support __float128 _Complex. +typedef __float128 _Complex Qcomplex; +#define CRT_HAS_NATIVE_COMPLEX_F128 +#elif defined(__GNUC__) && __GNUC__ >= 7 +// GCC does not allow __float128 _Complex, but accepts _Float128 _Complex. +typedef _Float128 _Complex Qcomplex; +#define CRT_HAS_NATIVE_COMPLEX_F128 +#endif +#endif #define COMPLEX_REAL(x) __real__(x) #define COMPLEX_IMAGINARY(x) __imag__(x) @@ -194,5 +247,17 @@ #define COMPLEX_REAL(x) (x).real #define COMPLEX_IMAGINARY(x) (x).imaginary #endif + +#ifdef CRT_HAS_NATIVE_COMPLEX_F128 +#define COMPLEX128_REAL(x) __real__(x) +#define COMPLEX128_IMAGINARY(x) __imag__(x) +#elif defined(CRT_HAS_F128) +typedef struct { + f128 real, imaginary; +} Qcomplex; +#define COMPLEX128_REAL(x) (x).real +#define COMPLEX128_IMAGINARY(x) (x).imaginary +#endif + #endif #endif // INT_TYPES_H diff --git a/compiler-rt/lib/builtins/multc3.c b/compiler-rt/lib/builtins/multc3.c --- a/compiler-rt/lib/builtins/multc3.c +++ b/compiler-rt/lib/builtins/multc3.c @@ -10,56 +10,61 @@ // //===----------------------------------------------------------------------===// +#define QUAD_PRECISION +#include "fp_lib.h" #include "int_lib.h" #include "int_math.h" +#if defined(CRT_HAS_TF_MODE) + // Returns: the product of a + ib and c + id -COMPILER_RT_ABI long double _Complex __multc3(long double a, long double b, - long double c, long double d) { - long double ac = a * c; - long double bd = b * d; - long double ad = a * d; - long double bc = b * c; - long double _Complex z; - __real__ z = ac - bd; - __imag__ z = ad + bc; - if (crt_isnan(__real__ z) && crt_isnan(__imag__ z)) { +COMPILER_RT_ABI Qcomplex __multc3(f128 a, f128 b, f128 c, f128 d) { + f128 ac = a * c; + f128 bd = b * d; + f128 ad = a * d; + f128 bc = b * c; + Qcomplex z; + COMPLEX128_REAL(z) = ac - bd; + COMPLEX128_IMAGINARY(z) = ad + bc; + if (crt_isnan(COMPLEX128_REAL(z)) && crt_isnan(COMPLEX128_IMAGINARY(z))) { int recalc = 0; if (crt_isinf(a) || crt_isinf(b)) { - a = crt_copysignl(crt_isinf(a) ? 1 : 0, a); - b = crt_copysignl(crt_isinf(b) ? 1 : 0, b); + a = crt_copysignf128(crt_isinf(a) ? 1 : 0, a); + b = crt_copysignf128(crt_isinf(b) ? 1 : 0, b); if (crt_isnan(c)) - c = crt_copysignl(0, c); + c = crt_copysignf128(0, c); if (crt_isnan(d)) - d = crt_copysignl(0, d); + d = crt_copysignf128(0, d); recalc = 1; } if (crt_isinf(c) || crt_isinf(d)) { - c = crt_copysignl(crt_isinf(c) ? 1 : 0, c); - d = crt_copysignl(crt_isinf(d) ? 1 : 0, d); + c = crt_copysignf128(crt_isinf(c) ? 1 : 0, c); + d = crt_copysignf128(crt_isinf(d) ? 1 : 0, d); if (crt_isnan(a)) - a = crt_copysignl(0, a); + a = crt_copysignf128(0, a); if (crt_isnan(b)) - b = crt_copysignl(0, b); + b = crt_copysignf128(0, b); recalc = 1; } if (!recalc && (crt_isinf(ac) || crt_isinf(bd) || crt_isinf(ad) || crt_isinf(bc))) { if (crt_isnan(a)) - a = crt_copysignl(0, a); + a = crt_copysignf128(0, a); if (crt_isnan(b)) - b = crt_copysignl(0, b); + b = crt_copysignf128(0, b); if (crt_isnan(c)) - c = crt_copysignl(0, c); + c = crt_copysignf128(0, c); if (crt_isnan(d)) - d = crt_copysignl(0, d); + d = crt_copysignf128(0, d); recalc = 1; } if (recalc) { - __real__ z = CRT_INFINITY * (a * c - b * d); - __imag__ z = CRT_INFINITY * (a * d + b * c); + COMPLEX128_REAL(z) = CRT_INFINITY * (a * c - b * d); + COMPLEX128_IMAGINARY(z) = CRT_INFINITY * (a * d + b * c); } } return z; } + +#endif diff --git a/compiler-rt/lib/builtins/powitf2.c b/compiler-rt/lib/builtins/powitf2.c --- a/compiler-rt/lib/builtins/powitf2.c +++ b/compiler-rt/lib/builtins/powitf2.c @@ -17,9 +17,9 @@ // Returns: a ^ b -COMPILER_RT_ABI long double __powitf2(long double a, int b) { +COMPILER_RT_ABI f128 __powitf2(f128 a, int b) { const int recip = b < 0; - long double r = 1; + f128 r = 1; while (1) { if (b & 1) r *= a; diff --git a/compiler-rt/lib/builtins/trunctfdf2.c b/compiler-rt/lib/builtins/trunctfdf2.c --- a/compiler-rt/lib/builtins/trunctfdf2.c +++ b/compiler-rt/lib/builtins/trunctfdf2.c @@ -14,6 +14,6 @@ #define DST_DOUBLE #include "fp_trunc_impl.inc" -COMPILER_RT_ABI double __trunctfdf2(long double a) { return __truncXfYf2__(a); } +COMPILER_RT_ABI double __trunctfdf2(f128 a) { return __truncXfYf2__(a); } #endif diff --git a/compiler-rt/lib/builtins/trunctfhf2.c b/compiler-rt/lib/builtins/trunctfhf2.c --- a/compiler-rt/lib/builtins/trunctfhf2.c +++ b/compiler-rt/lib/builtins/trunctfhf2.c @@ -15,8 +15,6 @@ #define DST_HALF #include "fp_trunc_impl.inc" -COMPILER_RT_ABI _Float16 __trunctfhf2(long double a) { - return __truncXfYf2__(a); -} +COMPILER_RT_ABI dst_t __trunctfhf2(f128 a) { return __truncXfYf2__(a); } #endif diff --git a/compiler-rt/lib/builtins/trunctfsf2.c b/compiler-rt/lib/builtins/trunctfsf2.c --- a/compiler-rt/lib/builtins/trunctfsf2.c +++ b/compiler-rt/lib/builtins/trunctfsf2.c @@ -14,6 +14,6 @@ #define DST_SINGLE #include "fp_trunc_impl.inc" -COMPILER_RT_ABI float __trunctfsf2(long double a) { return __truncXfYf2__(a); } +COMPILER_RT_ABI float __trunctfsf2(f128 a) { return __truncXfYf2__(a); } #endif diff --git a/compiler-rt/test/builtins/Unit/addtf3_test.c b/compiler-rt/test/builtins/Unit/addtf3_test.c --- a/compiler-rt/test/builtins/Unit/addtf3_test.c +++ b/compiler-rt/test/builtins/Unit/addtf3_test.c @@ -10,7 +10,7 @@ #include "fp_test.h" // Returns: a + b -COMPILER_RT_ABI long double __addtf3(long double a, long double b); +COMPILER_RT_ABI f128 __addtf3(f128 a, f128 b); int test__addtf3(long double a, long double b, uint64_t expectedHi, uint64_t expectedLo) diff --git a/compiler-rt/test/builtins/Unit/divtc3_test.c b/compiler-rt/test/builtins/Unit/divtc3_test.c --- a/compiler-rt/test/builtins/Unit/divtc3_test.c +++ b/compiler-rt/test/builtins/Unit/divtc3_test.c @@ -9,194 +9,190 @@ #include #include "int_lib.h" -#include +#include "int_math.h" #include +#include // Returns: the quotient of (a + ib) / (c + id) -COMPILER_RT_ABI long double _Complex -__divtc3(long double __a, long double __b, long double __c, long double __d); +COMPILER_RT_ABI Qcomplex __divtc3(f128 __a, f128 __b, f128 __c, f128 __d); enum {zero, non_zero, inf, NaN, non_zero_nan}; -int -classify(long double _Complex x) -{ - if (x == 0) - return zero; - if (isinf(creall(x)) || isinf(cimagl(x))) - return inf; - if (isnan(creall(x)) && isnan(cimagl(x))) - return NaN; - if (isnan(creall(x))) - { - if (cimagl(x) == 0) - return NaN; - return non_zero_nan; - } - if (isnan(cimagl(x))) - { - if (creall(x) == 0) - return NaN; - return non_zero_nan; - } - return non_zero; +static int classify(Qcomplex x) { + f128 real = COMPLEX128_REAL(x); + f128 imag = COMPLEX128_IMAGINARY(x); + if (real == 0.0 && imag == 0.0) + return zero; + if (crt_isinf(real) || crt_isinf(imag)) + return inf; + if (crt_isnan(real) && crt_isnan(imag)) + return NaN; + if (crt_isnan(real)) { + if (imag == 0.0) + return NaN; + return non_zero_nan; + } + if (crt_isnan(imag)) { + if (real == 0.0) + return NaN; + return non_zero_nan; + } + return non_zero; } -int test__divtc3(long double a, long double b, long double c, long double d) -{ - long double _Complex r = __divtc3(a, b, c, d); -// printf("test__divtc3(%Lf, %Lf, %Lf, %Lf) = %Lf + I%Lf\n", -// a, b, c, d, creall(r), cimagl(r)); - - long double _Complex dividend; - long double _Complex divisor; - - __real__ dividend = a; - __imag__ dividend = b; - __real__ divisor = c; - __imag__ divisor = d; - - switch (classify(dividend)) - { +static int test__divtc3(f128 a, f128 b, f128 c, f128 d) { + Qcomplex r = __divtc3(a, b, c, d); + Qcomplex dividend; + Qcomplex divisor; + + COMPLEX128_REAL(dividend) = a; + COMPLEX128_IMAGINARY(dividend) = b; + COMPLEX128_REAL(divisor) = c; + COMPLEX128_IMAGINARY(divisor) = d; + + switch (classify(dividend)) { + case zero: + switch (classify(divisor)) { + case zero: + if (classify(r) != NaN) + return 1; + break; + case non_zero: + if (classify(r) != zero) + return 1; + break; + case inf: + if (classify(r) != zero) + return 1; + break; + case NaN: + if (classify(r) != NaN) + return 1; + break; + case non_zero_nan: + if (classify(r) != NaN) + return 1; + break; + } + break; + case non_zero: + switch (classify(divisor)) { + case zero: + if (classify(r) != inf) + return 1; + break; + case non_zero: + if (classify(r) != non_zero) + return 1; + { + f128 zReal = (a * c + b * d) / (c * c + d * d); + f128 zImag = (b * c - a * d) / (c * c + d * d); + Qcomplex diff = __divtc3(COMPLEX128_REAL(r) - zReal, COMPLEX128_IMAGINARY(r) - zImag, + COMPLEX128_REAL(r), COMPLEX128_IMAGINARY(r)); + // cabsl(z) == hypotl(creall(z), cimagl(z)) +#ifdef CRT_LDBL_128BIT + if (hypotl(COMPLEX128_REAL(diff), COMPLEX128_IMAGINARY(diff)) > 1.e-6) +#else + // Avoid dependency on __trunctfxf2 for ld80 platforms and use double instead. + if (hypot(COMPLEX128_REAL(diff), COMPLEX128_IMAGINARY(diff)) > 1.e-6) +#endif + return 1; + } + break; + case inf: + if (classify(r) != zero) + return 1; + break; + case NaN: + if (classify(r) != NaN) + return 1; + break; + case non_zero_nan: + if (classify(r) != NaN) + return 1; + break; + } + break; + case inf: + switch (classify(divisor)) { + case zero: + if (classify(r) != inf) + return 1; + break; + case non_zero: + if (classify(r) != inf) + return 1; + break; + case inf: + if (classify(r) != NaN) + return 1; + break; + case NaN: + if (classify(r) != NaN) + return 1; + break; + case non_zero_nan: + if (classify(r) != NaN) + return 1; + break; + } + break; + case NaN: + switch (classify(divisor)) { case zero: - switch (classify(divisor)) - { - case zero: - if (classify(r) != NaN) - return 1; - break; - case non_zero: - if (classify(r) != zero) - return 1; - break; - case inf: - if (classify(r) != zero) - return 1; - break; - case NaN: - if (classify(r) != NaN) - return 1; - break; - case non_zero_nan: - if (classify(r) != NaN) - return 1; - break; - } - break; + if (classify(r) != NaN) + return 1; + break; case non_zero: - switch (classify(divisor)) - { - case zero: - if (classify(r) != inf) - return 1; - break; - case non_zero: - if (classify(r) != non_zero) - return 1; - { - long double _Complex z = (a * c + b * d) / (c * c + d * d) - + (b * c - a * d) / (c * c + d * d) * _Complex_I; - if (cabsl((r - z)/r) > 1.e-6) - return 1; - } - break; - case inf: - if (classify(r) != zero) - return 1; - break; - case NaN: - if (classify(r) != NaN) - return 1; - break; - case non_zero_nan: - if (classify(r) != NaN) - return 1; - break; - } - break; + if (classify(r) != NaN) + return 1; + break; case inf: - switch (classify(divisor)) - { - case zero: - if (classify(r) != inf) - return 1; - break; - case non_zero: - if (classify(r) != inf) - return 1; - break; - case inf: - if (classify(r) != NaN) - return 1; - break; - case NaN: - if (classify(r) != NaN) - return 1; - break; - case non_zero_nan: - if (classify(r) != NaN) - return 1; - break; - } - break; + if (classify(r) != NaN) + return 1; + break; case NaN: - switch (classify(divisor)) - { - case zero: - if (classify(r) != NaN) - return 1; - break; - case non_zero: - if (classify(r) != NaN) - return 1; - break; - case inf: - if (classify(r) != NaN) - return 1; - break; - case NaN: - if (classify(r) != NaN) - return 1; - break; - case non_zero_nan: - if (classify(r) != NaN) - return 1; - break; - } - break; + if (classify(r) != NaN) + return 1; + break; case non_zero_nan: - switch (classify(divisor)) - { - case zero: - if (classify(r) != inf) - return 1; - break; - case non_zero: - if (classify(r) != NaN) - return 1; - break; - case inf: - if (classify(r) != NaN) - return 1; - break; - case NaN: - if (classify(r) != NaN) - return 1; - break; - case non_zero_nan: - if (classify(r) != NaN) - return 1; - break; - } - break; + if (classify(r) != NaN) + return 1; + break; } - - return 0; + break; + case non_zero_nan: + switch (classify(divisor)) { + case zero: + if (classify(r) != inf) + return 1; + break; + case non_zero: + if (classify(r) != NaN) + return 1; + break; + case inf: + if (classify(r) != NaN) + return 1; + break; + case NaN: + if (classify(r) != NaN) + return 1; + break; + case non_zero_nan: + if (classify(r) != NaN) + return 1; + break; + } + break; + } + + return 0; } -long double x[][2] = +static f128 x[][2] = { { 1.e-6, 1.e-6}, {-1.e-6, 1.e-6}, @@ -352,19 +348,20 @@ }; -int main() -{ - const unsigned N = sizeof(x) / sizeof(x[0]); - unsigned i, j; - for (i = 0; i < N; ++i) - { - for (j = 0; j < N; ++j) - { - if (test__divtc3(x[i][0], x[i][1], x[j][0], x[j][1])) - return 1; - } +int main() { + const unsigned N = sizeof(x) / sizeof(x[0]); + unsigned i, j; + for (i = 0; i < N; ++i) { + for (j = 0; j < N; ++j) { + if (test__divtc3(x[i][0], x[i][1], x[j][0], x[j][1])) { + fprintf(stderr, "Failed for %g, %g, %g, %g\n", + (double)x[i][0], (double)x[i][1], + (double)x[j][0], (double)x[j][1]); + return 1; + } } + } -// printf("No errors found.\n"); - return 0; + fprintf(stderr, "No errors found.\n"); + return 0; } diff --git a/compiler-rt/test/builtins/Unit/divtf3_test.c b/compiler-rt/test/builtins/Unit/divtf3_test.c --- a/compiler-rt/test/builtins/Unit/divtf3_test.c +++ b/compiler-rt/test/builtins/Unit/divtf3_test.c @@ -9,7 +9,7 @@ #include "fp_test.h" // Returns: a / b -COMPILER_RT_ABI long double __divtf3(long double a, long double b); +COMPILER_RT_ABI f128 __divtf3(f128 a, f128 b); int test__divtf3(long double a, long double b, uint64_t expectedHi, uint64_t expectedLo) diff --git a/compiler-rt/test/builtins/Unit/floatunditf_test.c b/compiler-rt/test/builtins/Unit/floatunditf_test.c --- a/compiler-rt/test/builtins/Unit/floatunditf_test.c +++ b/compiler-rt/test/builtins/Unit/floatunditf_test.c @@ -12,7 +12,7 @@ // Returns: long integer converted to long double -COMPILER_RT_ABI long double __floatunditf(du_int a); +COMPILER_RT_ABI f128 __floatunditf(du_int a); int test__floatunditf(du_int a, uint64_t expectedHi, uint64_t expectedLo) { diff --git a/compiler-rt/test/builtins/Unit/powitf2_test.c b/compiler-rt/test/builtins/Unit/powitf2_test.c --- a/compiler-rt/test/builtins/Unit/powitf2_test.c +++ b/compiler-rt/test/builtins/Unit/powitf2_test.c @@ -10,7 +10,7 @@ // Returns: a ^ b -COMPILER_RT_ABI long double __powitf2(long double a, int b); +COMPILER_RT_ABI f128 __powitf2(f128 a, int b); int test__powitf2(long double a, int b, long double expected) { diff --git a/compiler-rt/test/builtins/Unit/subtf3_test.c b/compiler-rt/test/builtins/Unit/subtf3_test.c --- a/compiler-rt/test/builtins/Unit/subtf3_test.c +++ b/compiler-rt/test/builtins/Unit/subtf3_test.c @@ -10,7 +10,7 @@ #include "fp_test.h" // Returns: a - b -COMPILER_RT_ABI long double __subtf3(long double a, long double b); +COMPILER_RT_ABI f128 __subtf3(long double a, long double b); int test__subtf3(long double a, long double b, uint64_t expectedHi, uint64_t expectedLo)