[compiler-rt] [builtins] Support building the 128-bit float functions on ld80 platforms (PR #68132)

Alexander Richardson via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 17 14:43:04 PDT 2023


https://github.com/arichardson updated https://github.com/llvm/llvm-project/pull/68132

>From c9411123f344dbc15e536ea7b6b2ac03df7728d8 Mon Sep 17 00:00:00 2001
From: Alex Richardson <alexrichardson at google.com>
Date: Tue, 17 Oct 2023 14:06:57 -0700
Subject: [PATCH] [builtins] Support building the 128-bit float functions on
 x86

GCC provides these functions (e.g. __addtf3, etc.) in libgcc on x86_64.
Since Clang supports float128, we can also enable the existing code by
using float128 for fp_t if either __FLOAT128__ or __SIZEOF_FLOAT128__
is defined instead of only supporting these builtins for platforms with
128-bit IEEE long doubles.
This commit defines a new tf_float typedef that matches a float with
attribute((mode(TF)) on each given architecture.

There are more tests that could be enabled for x86, but to keep the diff
smaller, I restricted test changes to ones that started failing as part of
this refactoring.

This change has been tested on x86 (natively) and aarch64,powerpc64,riscv64
and sparc64 via qemu-user.

This supersedes https://reviews.llvm.org/D98261.
---
 compiler-rt/lib/builtins/CMakeLists.txt       |   2 -
 compiler-rt/lib/builtins/README.txt           |  21 +-
 compiler-rt/lib/builtins/divtc3.c             |  51 +-
 compiler-rt/lib/builtins/extenddftf2.c        |   4 +-
 compiler-rt/lib/builtins/extendhftf2.c        |   4 +-
 compiler-rt/lib/builtins/extendsftf2.c        |   4 +-
 compiler-rt/lib/builtins/floattitf.c          |   2 +-
 compiler-rt/lib/builtins/floatuntitf.c        |   2 +-
 compiler-rt/lib/builtins/fp_extend.h          |   8 +-
 compiler-rt/lib/builtins/fp_lib.h             |  50 +-
 compiler-rt/lib/builtins/fp_trunc.h           |   8 +-
 compiler-rt/lib/builtins/int_math.h           |  10 +
 compiler-rt/lib/builtins/int_types.h          |  73 ++
 compiler-rt/lib/builtins/multc3.c             |  53 +-
 compiler-rt/lib/builtins/powitf2.c            |   4 +-
 compiler-rt/lib/builtins/trunctfdf2.c         |   2 +-
 compiler-rt/lib/builtins/trunctfhf2.c         |   4 +-
 compiler-rt/lib/builtins/trunctfsf2.c         |   2 +-
 compiler-rt/test/builtins/Unit/addtf3_test.c  | 147 ++--
 .../builtins/Unit/compiler_rt_fmaxl_test.c    |  12 +-
 .../builtins/Unit/compiler_rt_logbl_test.c    |  14 +-
 .../builtins/Unit/compiler_rt_scalbnl_test.c  |  14 +-
 compiler-rt/test/builtins/Unit/divtc3_test.c  | 639 +++++++++---------
 .../test/builtins/Unit/floattitf_test.c       |  11 +-
 .../test/builtins/Unit/floatunditf_test.c     |   2 +-
 .../test/builtins/Unit/floatuntitf_test.c     |  12 +-
 26 files changed, 607 insertions(+), 548 deletions(-)

diff --git a/compiler-rt/lib/builtins/CMakeLists.txt b/compiler-rt/lib/builtins/CMakeLists.txt
index 4f210a5c0fef90f..ccca2da20fd688a 100644
--- a/compiler-rt/lib/builtins/CMakeLists.txt
+++ b/compiler-rt/lib/builtins/CMakeLists.txt
@@ -187,8 +187,6 @@ set(BF16_SOURCES
     truncsfbf2.c
 )
 
-# TODO: Several "tf" files (and divtc3.c, but not multc3.c) are in
-# GENERIC_SOURCES instead of here.
 set(GENERIC_TF_SOURCES
   addtf3.c
   comparetf2.c
diff --git a/compiler-rt/lib/builtins/README.txt b/compiler-rt/lib/builtins/README.txt
index 5637183cc3b4551..2d213d95f333af3 100644
--- a/compiler-rt/lib/builtins/README.txt
+++ b/compiler-rt/lib/builtins/README.txt
@@ -137,49 +137,54 @@ si_int __ucmpti2(tu_int a, tu_int b);
 di_int __fixsfdi(      float a);
 di_int __fixdfdi(     double a);
 di_int __fixxfdi(long double a);
+di_int __fixtfdi(   tf_float a);
 
 ti_int __fixsfti(      float a);
 ti_int __fixdfti(     double a);
 ti_int __fixxfti(long double a);
-uint64_t __fixtfdi(long double input);  // ppc only, doesn't match documentation
+ti_int __fixtfti(   tf_float a);
 
 su_int __fixunssfsi(      float a);
 su_int __fixunsdfsi(     double a);
 su_int __fixunsxfsi(long double a);
+su_int __fixunstfsi(   tf_float a);
 
 du_int __fixunssfdi(      float a);
 du_int __fixunsdfdi(     double a);
 du_int __fixunsxfdi(long double a);
+du_int __fixunstfdi(   tf_float a);
 
 tu_int __fixunssfti(      float a);
 tu_int __fixunsdfti(     double a);
 tu_int __fixunsxfti(long double a);
-uint64_t __fixunstfdi(long double input);  // ppc only
+tu_int __fixunstfti(   tf_float a);
 
 float       __floatdisf(di_int a);
 double      __floatdidf(di_int a);
 long double __floatdixf(di_int a);
-long double __floatditf(int64_t a);        // ppc only
+tf_float    __floatditf(int64_t a);
 
 float       __floattisf(ti_int a);
 double      __floattidf(ti_int a);
 long double __floattixf(ti_int a);
+tf_float    __floattitf(ti_int a);
 
 float       __floatundisf(du_int a);
 double      __floatundidf(du_int a);
 long double __floatundixf(du_int a);
-long double __floatunditf(uint64_t a);     // ppc only
+tf_float    __floatunditf(du_int a);
 
 float       __floatuntisf(tu_int a);
 double      __floatuntidf(tu_int a);
 long double __floatuntixf(tu_int a);
+tf_float    __floatuntixf(tu_int a);
 
 //  Floating point raised to integer power
 
 float       __powisf2(      float a, int b);  // a ^ b
 double      __powidf2(     double a, int b);  // a ^ b
 long double __powixf2(long double a, int b);  // a ^ b
-long double __powitf2(long double a, int b);  // ppc only, a ^ b
+tf_float    __powitf2(   tf_float a, int b);  // a ^ b
 
 //  Complex arithmetic
 
@@ -189,8 +194,7 @@ long double __powitf2(long double a, int b);  // ppc only, a ^ b
      double _Complex __muldc3(double a, double b, double c, double d);
 long double _Complex __mulxc3(long double a, long double b,
                               long double c, long double d);
-long double _Complex __multc3(long double a, long double b,
-                              long double c, long double d); // ppc only
+   tf_float _Complex __multc3(tf_float a, tf_float b, tf_float c, tf_float d);
 
 //  (a + ib) / (c + id)
 
@@ -198,8 +202,7 @@ long double _Complex __multc3(long double a, long double b,
      double _Complex __divdc3(double a, double b, double c, double d);
 long double _Complex __divxc3(long double a, long double b,
                               long double c, long double d);
-long double _Complex __divtc3(long double a, long double b,
-                              long double c, long double d);  // ppc only
+   tf_float _Complex __divtc3(tf_float a, tf_float b, tf_float c, tf_float d);
 
 
 //         Runtime support
diff --git a/compiler-rt/lib/builtins/divtc3.c b/compiler-rt/lib/builtins/divtc3.c
index 0e4799295f32fe3..e970cef574b21dd 100644
--- 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(fp_t __a, fp_t __b, fp_t __c, fp_t __d) {
   int __ilogbw = 0;
-  long double __logbw =
-      __compiler_rt_logbl(__compiler_rt_fmaxl(crt_fabsl(__c), crt_fabsl(__d)));
+  fp_t __logbw = __compiler_rt_logbtf(
+      __compiler_rt_fmaxtf(crt_fabstf(__c), crt_fabstf(__d)));
   if (crt_isfinite(__logbw)) {
     __ilogbw = (int)__logbw;
-    __c = __compiler_rt_scalbnl(__c, -__ilogbw);
-    __d = __compiler_rt_scalbnl(__d, -__ilogbw);
+    __c = __compiler_rt_scalbntf(__c, -__ilogbw);
+    __d = __compiler_rt_scalbntf(__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))) {
+  fp_t __denom = __c * __c + __d * __d;
+  Qcomplex z;
+  COMPLEXTF_REAL(z) =
+      __compiler_rt_scalbntf((__a * __c + __b * __d) / __denom, -__ilogbw);
+  COMPLEXTF_IMAGINARY(z) =
+      __compiler_rt_scalbntf((__b * __c - __a * __d) / __denom, -__ilogbw);
+  if (crt_isnan(COMPLEXTF_REAL(z)) && crt_isnan(COMPLEXTF_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;
+      COMPLEXTF_REAL(z) = crt_copysigntf(CRT_INFINITY, __c) * __a;
+      COMPLEXTF_IMAGINARY(z) = crt_copysigntf(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_copysigntf(crt_isinf(__a) ? (fp_t)1.0 : (fp_t)0.0, __a);
+      __b = crt_copysigntf(crt_isinf(__b) ? (fp_t)1.0 : (fp_t)0.0, __b);
+      COMPLEXTF_REAL(z) = CRT_INFINITY * (__a * __c + __b * __d);
+      COMPLEXTF_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_copysigntf(crt_isinf(__c) ? (fp_t)1.0 : (fp_t)0.0, __c);
+      __d = crt_copysigntf(crt_isinf(__d) ? (fp_t)1.0 : (fp_t)0.0, __d);
+      COMPLEXTF_REAL(z) = 0.0 * (__a * __c + __b * __d);
+      COMPLEXTF_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
index 835076be1f2080d..a61ef53147abcfb 100644
--- 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 dst_t __extenddftf2(src_t a) { return __extendXfYf2__(a); }
 
 #endif
diff --git a/compiler-rt/lib/builtins/extendhftf2.c b/compiler-rt/lib/builtins/extendhftf2.c
index a2cb0f771ee9aa9..7609db6f06e4ad4 100644
--- 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 dst_t __extendhftf2(src_t a) { return __extendXfYf2__(a); }
 
 #endif
diff --git a/compiler-rt/lib/builtins/extendsftf2.c b/compiler-rt/lib/builtins/extendsftf2.c
index 0739859bcbc18fa..4ab2982ce5142ba 100644
--- 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 dst_t __extendsftf2(src_t a) { return __extendXfYf2__(a); }
 
 #endif
diff --git a/compiler-rt/lib/builtins/floattitf.c b/compiler-rt/lib/builtins/floattitf.c
index fff0755c3bb46a3..c0e61edee8d522d 100644
--- a/compiler-rt/lib/builtins/floattitf.c
+++ b/compiler-rt/lib/builtins/floattitf.c
@@ -67,7 +67,7 @@ COMPILER_RT_ABI fp_t __floattitf(ti_int a) {
     // a is now rounded to LDBL_MANT_DIG bits
   }
 
-  long_double_bits fb;
+  tf_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
index 33a81b34eeb195b..b774bb1c37c4351 100644
--- a/compiler-rt/lib/builtins/floatuntitf.c
+++ b/compiler-rt/lib/builtins/floatuntitf.c
@@ -65,7 +65,7 @@ COMPILER_RT_ABI fp_t __floatuntitf(tu_int a) {
     // a is now rounded to TF_MANT_DIG bits
   }
 
-  long_double_bits fb;
+  tf_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
index d640bdcb0ec1fa4..fcd3102bbf9da24 100644
--- a/compiler-rt/lib/builtins/fp_extend.h
+++ b/compiler-rt/lib/builtins/fp_extend.h
@@ -102,13 +102,7 @@ static const int dstSigFracBits = 52;
 static const int dstExpBits = 11;
 
 #elif defined DST_QUAD
-// TODO: use fp_lib.h once QUAD_PRECISION is available on x86_64.
-#if __LDBL_MANT_DIG__ == 113
-typedef long double dst_t;
-#elif defined(__x86_64__) &&                                                   \
-    (defined(__FLOAT128__) || defined(__SIZEOF_FLOAT128__))
-typedef __float128 dst_t;
-#endif
+typedef tf_float dst_t;
 typedef __uint128_t dst_rep_t;
 #define DST_REP_C (__uint128_t)
 static const int dstBits = sizeof(dst_t) * CHAR_BIT;
diff --git a/compiler-rt/lib/builtins/fp_lib.h b/compiler-rt/lib/builtins/fp_lib.h
index 58eb45fcc729296..43bbdd5f8736575 100644
--- a/compiler-rt/lib/builtins/fp_lib.h
+++ b/compiler-rt/lib/builtins/fp_lib.h
@@ -105,18 +105,11 @@ static __inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
 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
-#define CRT_HAS_TF_MODE
-#define TF_C(c) c##L
+#if defined(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 tf_float 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
@@ -207,13 +200,13 @@ static __inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
 #undef Word_HiMask
 #undef Word_LoMask
 #undef Word_FullMask
-#endif // __LDBL_MANT_DIG__ == 113 && __SIZEOF_INT128__
+#endif // defined(CRT_HAS_TF_MODE)
 #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)
@@ -393,31 +386,40 @@ static __inline fp_t __compiler_rt_fmax(fp_t x, fp_t y) {
 #endif
 }
 
-#elif defined(QUAD_PRECISION)
-
-#if defined(CRT_LDBL_128BIT)
-static __inline fp_t __compiler_rt_logbl(fp_t x) {
+#elif defined(QUAD_PRECISION) && defined(CRT_HAS_TF_MODE)
+// 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_TF)
+static __inline tf_float __compiler_rt_logbtf(tf_float x) {
   return __compiler_rt_logbX(x);
 }
-static __inline fp_t __compiler_rt_scalbnl(fp_t x, int y) {
+static __inline tf_float __compiler_rt_scalbntf(tf_float x, int y) {
   return __compiler_rt_scalbnX(x, y);
 }
-static __inline fp_t __compiler_rt_fmaxl(fp_t x, fp_t y) {
+static __inline tf_float __compiler_rt_fmaxtf(tf_float x, tf_float 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) {
+#define __compiler_rt_logbl __compiler_rt_logbtf
+#define __compiler_rt_scalbnl __compiler_rt_scalbntf
+#define __compiler_rt_fmaxl __compiler_rt_fmaxtf
+#define crt_fabstf crt_fabsf128
+#define crt_copysigntf crt_copysignf128
+#elif defined(CRT_LDBL_128BIT)
+static __inline tf_float __compiler_rt_logbtf(tf_float x) {
   return crt_logbl(x);
 }
-static __inline long double __compiler_rt_scalbnl(long double x, int y) {
+static __inline tf_float __compiler_rt_scalbntf(tf_float x, int y) {
   return crt_scalbnl(x, y);
 }
-static __inline long double __compiler_rt_fmaxl(long double x, long double y) {
+static __inline tf_float __compiler_rt_fmaxtf(tf_float x, tf_float y) {
   return crt_fmaxl(x, y);
 }
-#endif // CRT_LDBL_128BIT
+#define __compiler_rt_logbl crt_logbl
+#define __compiler_rt_scalbnl crt_scalbnl
+#define __compiler_rt_fmaxl crt_fmaxl
+#else
+#error Unsupported TF mode type
+#endif
 
 #endif // *_PRECISION
 
diff --git a/compiler-rt/lib/builtins/fp_trunc.h b/compiler-rt/lib/builtins/fp_trunc.h
index f62f8bafc7995f7..5e81eb73f94103d 100644
--- a/compiler-rt/lib/builtins/fp_trunc.h
+++ b/compiler-rt/lib/builtins/fp_trunc.h
@@ -36,13 +36,7 @@ static const int srcSigFracBits = 52;
 static const int srcExpBits = 11;
 
 #elif defined SRC_QUAD
-// TODO: use fp_lib.h once QUAD_PRECISION is available on x86_64.
-#if __LDBL_MANT_DIG__ == 113
-typedef long double src_t;
-#elif defined(__x86_64__) &&                                                   \
-    (defined(__FLOAT128__) || defined(__SIZEOF_FLOAT128__))
-typedef __float128 src_t;
-#endif
+typedef tf_float src_t;
 typedef __uint128_t src_rep_t;
 #define SRC_REP_C (__uint128_t)
 static const int srcBits = sizeof(src_t) * CHAR_BIT;
diff --git a/compiler-rt/lib/builtins/int_math.h b/compiler-rt/lib/builtins/int_math.h
index 48b9580f5961b01..74d3e311db5e710 100644
--- a/compiler-rt/lib/builtins/int_math.h
+++ b/compiler-rt/lib/builtins/int_math.h
@@ -65,6 +65,11 @@
 #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))
+#endif
 #endif
 
 #if defined(_MSC_VER) && !defined(__clang__)
@@ -75,6 +80,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
index e94d3154c6d4ef6..f705844610f6ac5 100644
--- a/compiler-rt/lib/builtins/int_types.h
+++ b/compiler-rt/lib/builtins/int_types.h
@@ -165,6 +165,53 @@ typedef struct {
 #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 tf_float typedef.
+typedef long double tf_float;
+#define CRT_LDBL_128BIT
+#define CRT_HAS_F128
+#if __LDBL_MANT_DIG__ == 113 && !defined(__LONG_DOUBLE_IBM128__)
+#define CRT_HAS_IEEE_TF
+#define CRT_LDBL_IEEE_F128
+#endif
+#define TF_C(x) x##L
+#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_TF
+#define CRT_LDBL_IEEE_F128
+typedef long double tf_float;
+#define TF_C(x) x##L
+#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_TF
+typedef __float128 tf_float;
+#define TF_C(x) x##Q
+#endif
+
+#ifdef CRT_HAS_F128
+typedef union {
+  uqwords u;
+  tf_float f;
+} tf_bits;
+#endif
+
+// __(u)int128_t is currently needed to compile the *tf builtins as we would
+// otherwise need to manually expand the bit manipulation on two 64-bit value.
+#if defined(CRT_HAS_128BIT) && defined(CRT_HAS_F128)
+#define CRT_HAS_TF_MODE
+#endif
+
 #if CRT_HAS_FLOATING_POINT
 typedef union {
   uqwords u;
@@ -175,6 +222,20 @@ typedef union {
 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 +255,17 @@ typedef struct {
 #define COMPLEX_REAL(x) (x).real
 #define COMPLEX_IMAGINARY(x) (x).imaginary
 #endif
+
+#ifdef CRT_HAS_NATIVE_COMPLEX_F128
+#define COMPLEXTF_REAL(x) __real__(x)
+#define COMPLEXTF_IMAGINARY(x) __imag__(x)
+#elif defined(CRT_HAS_F128)
+typedef struct {
+  tf_float real, imaginary;
+} Qcomplex;
+#define COMPLEXTF_REAL(x) (x).real
+#define COMPLEXTF_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
index bb7f6aabfe2c8ec..f20e53ccbf233bb 100644
--- 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(fp_t a, fp_t b, fp_t c, fp_t d) {
+  fp_t ac = a * c;
+  fp_t bd = b * d;
+  fp_t ad = a * d;
+  fp_t bc = b * c;
+  Qcomplex z;
+  COMPLEXTF_REAL(z) = ac - bd;
+  COMPLEXTF_IMAGINARY(z) = ad + bc;
+  if (crt_isnan(COMPLEXTF_REAL(z)) && crt_isnan(COMPLEXTF_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_copysigntf(crt_isinf(a) ? 1 : 0, a);
+      b = crt_copysigntf(crt_isinf(b) ? 1 : 0, b);
       if (crt_isnan(c))
-        c = crt_copysignl(0, c);
+        c = crt_copysigntf(0, c);
       if (crt_isnan(d))
-        d = crt_copysignl(0, d);
+        d = crt_copysigntf(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_copysigntf(crt_isinf(c) ? 1 : 0, c);
+      d = crt_copysigntf(crt_isinf(d) ? 1 : 0, d);
       if (crt_isnan(a))
-        a = crt_copysignl(0, a);
+        a = crt_copysigntf(0, a);
       if (crt_isnan(b))
-        b = crt_copysignl(0, b);
+        b = crt_copysigntf(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_copysigntf(0, a);
       if (crt_isnan(b))
-        b = crt_copysignl(0, b);
+        b = crt_copysigntf(0, b);
       if (crt_isnan(c))
-        c = crt_copysignl(0, c);
+        c = crt_copysigntf(0, c);
       if (crt_isnan(d))
-        d = crt_copysignl(0, d);
+        d = crt_copysigntf(0, d);
       recalc = 1;
     }
     if (recalc) {
-      __real__ z = CRT_INFINITY * (a * c - b * d);
-      __imag__ z = CRT_INFINITY * (a * d + b * c);
+      COMPLEXTF_REAL(z) = CRT_INFINITY * (a * c - b * d);
+      COMPLEXTF_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
index 74fe707a4e8c40e..e02db40767ac03d 100644
--- 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 fp_t __powitf2(fp_t a, int b) {
   const int recip = b < 0;
-  long double r = 1;
+  fp_t 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
index f0d2e4141f3b04d..a5bdded53751fdb 100644
--- 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 dst_t __trunctfdf2(src_t a) { return __truncXfYf2__(a); }
 
 #endif
diff --git a/compiler-rt/lib/builtins/trunctfhf2.c b/compiler-rt/lib/builtins/trunctfhf2.c
index f7776327251c79f..3f031e0f844510c 100644
--- 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(src_t a) { return __truncXfYf2__(a); }
 
 #endif
diff --git a/compiler-rt/lib/builtins/trunctfsf2.c b/compiler-rt/lib/builtins/trunctfsf2.c
index 242735f738c1373..b65b5af2fc00178 100644
--- 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 dst_t __trunctfsf2(src_t 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
index e6986c236a64f5e..5f2530745126652 100644
--- a/compiler-rt/test/builtins/Unit/addtf3_test.c
+++ b/compiler-rt/test/builtins/Unit/addtf3_test.c
@@ -6,100 +6,85 @@
 
 #if __LDBL_MANT_DIG__ == 113
 
-#include "int_lib.h"
-#include "fp_test.h"
+#  include "int_lib.h"
+#  include "fp_test.h"
 
 // Returns: a + b
-COMPILER_RT_ABI long double __addtf3(long double a, long double b);
+COMPILER_RT_ABI tf_float __addtf3(tf_float a, tf_float b);
 
-int test__addtf3(long double a, long double b,
-                 uint64_t expectedHi, uint64_t expectedLo)
-{
-    long double x = __addtf3(a, b);
-    int ret = compareResultF128(x, expectedHi, expectedLo);
+int test__addtf3(tf_float a, tf_float b, uint64_t expectedHi,
+                 uint64_t expectedLo) {
+  tf_float x = __addtf3(a, b);
+  int ret = compareResultF128(x, expectedHi, expectedLo);
 
-    if (ret){
-        printf("error in test__addtf3(%.20Lf, %.20Lf) = %.20Lf, "
-               "expected %.20Lf\n", a, b, x,
-               fromRep128(expectedHi, expectedLo));
-    }
+  if (ret) {
+    printf("error in test__addtf3(%.20Lf, %.20Lf) = %.20Lf, "
+           "expected %.20Lf\n",
+           a, b, x, fromRep128(expectedHi, expectedLo));
+  }
 
-    return ret;
+  return ret;
 }
 
-char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0};
+char assumption_1[sizeof(tf_float) * CHAR_BIT == 128] = {0};
 
 #endif
 
-int main()
-{
+int main() {
 #if __LDBL_MANT_DIG__ == 113
-    // qNaN + any = qNaN
-    if (test__addtf3(makeQNaN128(),
-                     0x1.23456789abcdefp+5L,
-                     UINT64_C(0x7fff800000000000),
-                     UINT64_C(0x0)))
-        return 1;
-    // NaN + any = NaN
-    if (test__addtf3(makeNaN128(UINT64_C(0x800030000000)),
-                     0x1.23456789abcdefp+5L,
-                     UINT64_C(0x7fff800000000000),
-                     UINT64_C(0x0)))
-        return 1;
-    // inf + inf = inf
-    if (test__addtf3(makeInf128(),
-                     makeInf128(),
-                     UINT64_C(0x7fff000000000000),
-                     UINT64_C(0x0)))
-        return 1;
-    // inf + any = inf
-    if (test__addtf3(makeInf128(),
-                     0x1.2335653452436234723489432abcdefp+5L,
-                     UINT64_C(0x7fff000000000000),
-                     UINT64_C(0x0)))
-        return 1;
-    // any + any
-    if (test__addtf3(0x1.23456734245345543849abcdefp+5L,
-                     0x1.edcba52449872455634654321fp-1L,
-                     UINT64_C(0x40042afc95c8b579),
-                     UINT64_C(0x61e58dd6c51eb77c)))
-        return 1;
-
-#if (defined(__arm__) || defined(__aarch64__)) && defined(__ARM_FP) || \
-    defined(i386) || defined(__x86_64__) || (defined(__loongarch__) && \
-    __loongarch_frlen != 0)
-    // Rounding mode tests on supported architectures
-    const long double m = 1234.0L, n = 0.01L;
-
-    fesetround(FE_UPWARD);
-    if (test__addtf3(m, n,
-                     UINT64_C(0x40093480a3d70a3d),
-                     UINT64_C(0x70a3d70a3d70a3d8)))
-        return 1;
-
-    fesetround(FE_DOWNWARD);
-    if (test__addtf3(m, n,
-                     UINT64_C(0x40093480a3d70a3d),
-                     UINT64_C(0x70a3d70a3d70a3d7)))
-        return 1;
-
-
-    fesetround(FE_TOWARDZERO);
-    if (test__addtf3(m, n,
-                     UINT64_C(0x40093480a3d70a3d),
-                     UINT64_C(0x70a3d70a3d70a3d7)))
-        return 1;
-
-    fesetround(FE_TONEAREST);
-    if (test__addtf3(m, n,
-                     UINT64_C(0x40093480a3d70a3d),
-                     UINT64_C(0x70a3d70a3d70a3d7)))
-        return 1;
-#endif
+  // qNaN + any = qNaN
+  if (test__addtf3(makeQNaN128(), 0x1.23456789abcdefp+5L,
+                   UINT64_C(0x7fff800000000000), UINT64_C(0x0)))
+    return 1;
+  // NaN + any = NaN
+  if (test__addtf3(makeNaN128(UINT64_C(0x800030000000)),
+                   TF_C(0x1.23456789abcdefp+5), UINT64_C(0x7fff800000000000),
+                   UINT64_C(0x0)))
+    return 1;
+  // inf + inf = inf
+  if (test__addtf3(makeInf128(), makeInf128(), UINT64_C(0x7fff000000000000),
+                   UINT64_C(0x0)))
+    return 1;
+  // inf + any = inf
+  if (test__addtf3(makeInf128(), TF_C(0x1.2335653452436234723489432abcdefp+5),
+                   UINT64_C(0x7fff000000000000), UINT64_C(0x0)))
+    return 1;
+  // any + any
+  if (test__addtf3(TF_C(0x1.23456734245345543849abcdefp+5),
+                   TF_C(0x1.edcba52449872455634654321fp-1),
+                   UINT64_C(0x40042afc95c8b579), UINT64_C(0x61e58dd6c51eb77c)))
+    return 1;
+
+#  if (defined(__arm__) || defined(__aarch64__)) && defined(__ARM_FP) ||       \
+      defined(i386) || defined(__x86_64__) ||                                  \
+      (defined(__loongarch__) && __loongarch_frlen != 0)
+  // Rounding mode tests on supported architectures
+  const tf_float m = 1234.0L, n = 0.01L;
+
+  fesetround(FE_UPWARD);
+  if (test__addtf3(m, n, UINT64_C(0x40093480a3d70a3d),
+                   UINT64_C(0x70a3d70a3d70a3d8)))
+    return 1;
+
+  fesetround(FE_DOWNWARD);
+  if (test__addtf3(m, n, UINT64_C(0x40093480a3d70a3d),
+                   UINT64_C(0x70a3d70a3d70a3d7)))
+    return 1;
+
+  fesetround(FE_TOWARDZERO);
+  if (test__addtf3(m, n, UINT64_C(0x40093480a3d70a3d),
+                   UINT64_C(0x70a3d70a3d70a3d7)))
+    return 1;
+
+  fesetround(FE_TONEAREST);
+  if (test__addtf3(m, n, UINT64_C(0x40093480a3d70a3d),
+                   UINT64_C(0x70a3d70a3d70a3d7)))
+    return 1;
+#  endif
 
 #else
-    printf("skipped\n");
+  printf("skipped\n");
 
 #endif
-    return 0;
+  return 0;
 }
diff --git a/compiler-rt/test/builtins/Unit/compiler_rt_fmaxl_test.c b/compiler-rt/test/builtins/Unit/compiler_rt_fmaxl_test.c
index 7b99514aad4e30a..693461452455d9e 100644
--- a/compiler-rt/test/builtins/Unit/compiler_rt_fmaxl_test.c
+++ b/compiler-rt/test/builtins/Unit/compiler_rt_fmaxl_test.c
@@ -6,7 +6,9 @@
 #include <stdio.h>
 #include "fp_lib.h"
 
-#if defined(CRT_HAS_TF_MODE)
+// TODO: This test currently only works if long double is the same as fp_t.
+// On x86_64 we get undefined references to __trunctfxf2 and __extendxftf2
+#if defined(CRT_HAS_TF_MODE) && defined(CRT_LDBL_IEEE_F128)
 
 int test__compiler_rt_fmaxl(fp_t x, fp_t y) {
   fp_t crt_value = __compiler_rt_fmaxl(x, y);
@@ -40,10 +42,7 @@ fp_t cases[] = {
   -1.001, 1.001, -1.002, 1.002,
 };
 
-#endif
-
 int main() {
-#if defined(CRT_HAS_TF_MODE)
   const unsigned N = sizeof(cases) / sizeof(cases[0]);
   unsigned i, j;
   for (i = 0; i < N; ++i) {
@@ -51,8 +50,11 @@ int main() {
       if (test__compiler_rt_fmaxl(cases[i], cases[j])) return 1;
     }
   }
+  return 0;
+}
 #else
+int main() {
   printf("skipped\n");
-#endif
   return 0;
 }
+#endif
diff --git a/compiler-rt/test/builtins/Unit/compiler_rt_logbl_test.c b/compiler-rt/test/builtins/Unit/compiler_rt_logbl_test.c
index f48e67e7887cdc7..d169d18274867bd 100644
--- a/compiler-rt/test/builtins/Unit/compiler_rt_logbl_test.c
+++ b/compiler-rt/test/builtins/Unit/compiler_rt_logbl_test.c
@@ -6,7 +6,9 @@
 #include "fp_lib.h"
 #include "int_lib.h"
 
-#if defined(CRT_HAS_TF_MODE)
+// TODO: This test currently only works if long double is the same as fp_t.
+// On x86_64 we get undefined references to __trunctfxf2 and __extendxftf2
+#if defined(CRT_HAS_TF_MODE) && defined(CRT_LDBL_IEEE_F128)
 
 int test__compiler_rt_logbl(fp_t x) {
 #if defined(__ve__)
@@ -39,10 +41,7 @@ double cases[] = {
     -0.0,  0.0,    1,   -2,   2,        -0.5,      0.5,
 };
 
-#endif
-
 int main() {
-#if defined(CRT_HAS_TF_MODE)
   const unsigned N = sizeof(cases) / sizeof(cases[0]);
   unsigned i;
   for (i = 0; i < N; ++i) {
@@ -64,9 +63,12 @@ int main() {
     if (test__compiler_rt_logbl(fromRep(signBit ^ x))) return 1;
     x >>= 1;
   }
+
+  return 0;
+}
 #else
+int main() {
   printf("skipped\n");
-#endif
-
   return 0;
 }
+#endif
diff --git a/compiler-rt/test/builtins/Unit/compiler_rt_scalbnl_test.c b/compiler-rt/test/builtins/Unit/compiler_rt_scalbnl_test.c
index 79193334c65d9f9..09a5fdc87af2743 100644
--- a/compiler-rt/test/builtins/Unit/compiler_rt_scalbnl_test.c
+++ b/compiler-rt/test/builtins/Unit/compiler_rt_scalbnl_test.c
@@ -8,7 +8,9 @@
 #include <stdio.h>
 #include "fp_lib.h"
 
-#if defined(CRT_HAS_TF_MODE)
+// TODO: This test currently only works if long double is the same as fp_t.
+// On x86_64 we get undefined references to __trunctfxf2 and __extendxftf2
+#if defined(CRT_HAS_TF_MODE) && defined(CRT_LDBL_IEEE_F128)
 
 int test__compiler_rt_scalbnl(const char *mode, fp_t x, int y) {
 #if defined(__ve__)
@@ -64,18 +66,18 @@ int iterate_cases(const char *mode) {
   return 0;
 }
 
-#endif
-
 int main() {
-#if defined(CRT_HAS_TF_MODE)
   if (iterate_cases("default")) return 1;
 
   // Skip rounding mode tests (fesetround) because compiler-rt's quad-precision
   // multiply also ignores the current rounding mode.
 
+  return 0;
+}
+
 #else
+int main() {
   printf("skipped\n");
-#endif
-
   return 0;
 }
+#endif
diff --git a/compiler-rt/test/builtins/Unit/divtc3_test.c b/compiler-rt/test/builtins/Unit/divtc3_test.c
index 18042031ccf0ba1..9ba4880f4a11027 100644
--- a/compiler-rt/test/builtins/Unit/divtc3_test.c
+++ b/compiler-rt/test/builtins/Unit/divtc3_test.c
@@ -9,362 +9,357 @@
 #include <stdio.h>
 
 #include "int_lib.h"
-#include <math.h>
+#include "int_math.h"
 #include <complex.h>
-
+#include <math.h>
 
 // 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(tf_float __a, tf_float __b, tf_float __c,
+                                  tf_float __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) {
+  tf_float real = COMPLEXTF_REAL(x);
+  tf_float imag = COMPLEXTF_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(tf_float a, tf_float b, tf_float c, tf_float d) {
+  Qcomplex r = __divtc3(a, b, c, d);
+  Qcomplex dividend;
+  Qcomplex divisor;
+
+  COMPLEXTF_REAL(dividend) = a;
+  COMPLEXTF_IMAGINARY(dividend) = b;
+  COMPLEXTF_REAL(divisor) = c;
+  COMPLEXTF_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;
+      {
+        tf_float zReal = (a * c + b * d) / (c * c + d * d);
+        tf_float zImag = (b * c - a * d) / (c * c + d * d);
+        Qcomplex diff =
+            __divtc3(COMPLEXTF_REAL(r) - zReal, COMPLEXTF_IMAGINARY(r) - zImag,
+                     COMPLEXTF_REAL(r), COMPLEXTF_IMAGINARY(r));
+        // cabsl(z) == hypotl(creall(z), cimagl(z))
+#ifdef CRT_LDBL_128BIT
+        if (hypotl(COMPLEXTF_REAL(diff), COMPLEXTF_IMAGINARY(diff)) > 1.e-6)
+#else
+        // Avoid dependency on __trunctfxf2 for ld80 platforms and use double instead.
+        if (hypot(COMPLEXTF_REAL(diff), COMPLEXTF_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:
+      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;
+  case non_zero_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) != inf)
+        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;
+  }
+
+  return 0;
 }
 
-long double x[][2] =
-{
-    { 1.e-6,  1.e-6},
-    {-1.e-6,  1.e-6},
-    {-1.e-6, -1.e-6},
-    { 1.e-6, -1.e-6},
+tf_float x[][2] = {{1.e-6, 1.e-6},
+                   {-1.e-6, 1.e-6},
+                   {-1.e-6, -1.e-6},
+                   {1.e-6, -1.e-6},
 
-    { 1.e+6,  1.e-6},
-    {-1.e+6,  1.e-6},
-    {-1.e+6, -1.e-6},
-    { 1.e+6, -1.e-6},
+                   {1.e+6, 1.e-6},
+                   {-1.e+6, 1.e-6},
+                   {-1.e+6, -1.e-6},
+                   {1.e+6, -1.e-6},
 
-    { 1.e-6,  1.e+6},
-    {-1.e-6,  1.e+6},
-    {-1.e-6, -1.e+6},
-    { 1.e-6, -1.e+6},
+                   {1.e-6, 1.e+6},
+                   {-1.e-6, 1.e+6},
+                   {-1.e-6, -1.e+6},
+                   {1.e-6, -1.e+6},
 
-    { 1.e+6,  1.e+6},
-    {-1.e+6,  1.e+6},
-    {-1.e+6, -1.e+6},
-    { 1.e+6, -1.e+6},
+                   {1.e+6, 1.e+6},
+                   {-1.e+6, 1.e+6},
+                   {-1.e+6, -1.e+6},
+                   {1.e+6, -1.e+6},
 
-    {NAN, NAN},
-    {-INFINITY, NAN},
-    {-2, NAN},
-    {-1, NAN},
-    {-0.5, NAN},
-    {-0., NAN},
-    {+0., NAN},
-    {0.5, NAN},
-    {1, NAN},
-    {2, NAN},
-    {INFINITY, NAN},
+                   {NAN, NAN},
+                   {-INFINITY, NAN},
+                   {-2, NAN},
+                   {-1, NAN},
+                   {-0.5, NAN},
+                   {-0., NAN},
+                   {+0., NAN},
+                   {0.5, NAN},
+                   {1, NAN},
+                   {2, NAN},
+                   {INFINITY, NAN},
 
-    {NAN, -INFINITY},
-    {-INFINITY, -INFINITY},
-    {-2, -INFINITY},
-    {-1, -INFINITY},
-    {-0.5, -INFINITY},
-    {-0., -INFINITY},
-    {+0., -INFINITY},
-    {0.5, -INFINITY},
-    {1, -INFINITY},
-    {2, -INFINITY},
-    {INFINITY, -INFINITY},
+                   {NAN, -INFINITY},
+                   {-INFINITY, -INFINITY},
+                   {-2, -INFINITY},
+                   {-1, -INFINITY},
+                   {-0.5, -INFINITY},
+                   {-0., -INFINITY},
+                   {+0., -INFINITY},
+                   {0.5, -INFINITY},
+                   {1, -INFINITY},
+                   {2, -INFINITY},
+                   {INFINITY, -INFINITY},
 
-    {NAN, -2},
-    {-INFINITY, -2},
-    {-2, -2},
-    {-1, -2},
-    {-0.5, -2},
-    {-0., -2},
-    {+0., -2},
-    {0.5, -2},
-    {1, -2},
-    {2, -2},
-    {INFINITY, -2},
+                   {NAN, -2},
+                   {-INFINITY, -2},
+                   {-2, -2},
+                   {-1, -2},
+                   {-0.5, -2},
+                   {-0., -2},
+                   {+0., -2},
+                   {0.5, -2},
+                   {1, -2},
+                   {2, -2},
+                   {INFINITY, -2},
 
-    {NAN, -1},
-    {-INFINITY, -1},
-    {-2, -1},
-    {-1, -1},
-    {-0.5, -1},
-    {-0., -1},
-    {+0., -1},
-    {0.5, -1},
-    {1, -1},
-    {2, -1},
-    {INFINITY, -1},
+                   {NAN, -1},
+                   {-INFINITY, -1},
+                   {-2, -1},
+                   {-1, -1},
+                   {-0.5, -1},
+                   {-0., -1},
+                   {+0., -1},
+                   {0.5, -1},
+                   {1, -1},
+                   {2, -1},
+                   {INFINITY, -1},
 
-    {NAN, -0.5},
-    {-INFINITY, -0.5},
-    {-2, -0.5},
-    {-1, -0.5},
-    {-0.5, -0.5},
-    {-0., -0.5},
-    {+0., -0.5},
-    {0.5, -0.5},
-    {1, -0.5},
-    {2, -0.5},
-    {INFINITY, -0.5},
+                   {NAN, -0.5},
+                   {-INFINITY, -0.5},
+                   {-2, -0.5},
+                   {-1, -0.5},
+                   {-0.5, -0.5},
+                   {-0., -0.5},
+                   {+0., -0.5},
+                   {0.5, -0.5},
+                   {1, -0.5},
+                   {2, -0.5},
+                   {INFINITY, -0.5},
 
-    {NAN, -0.},
-    {-INFINITY, -0.},
-    {-2, -0.},
-    {-1, -0.},
-    {-0.5, -0.},
-    {-0., -0.},
-    {+0., -0.},
-    {0.5, -0.},
-    {1, -0.},
-    {2, -0.},
-    {INFINITY, -0.},
+                   {NAN, -0.},
+                   {-INFINITY, -0.},
+                   {-2, -0.},
+                   {-1, -0.},
+                   {-0.5, -0.},
+                   {-0., -0.},
+                   {+0., -0.},
+                   {0.5, -0.},
+                   {1, -0.},
+                   {2, -0.},
+                   {INFINITY, -0.},
 
-    {NAN, 0.},
-    {-INFINITY, 0.},
-    {-2, 0.},
-    {-1, 0.},
-    {-0.5, 0.},
-    {-0., 0.},
-    {+0., 0.},
-    {0.5, 0.},
-    {1, 0.},
-    {2, 0.},
-    {INFINITY, 0.},
+                   {NAN, 0.},
+                   {-INFINITY, 0.},
+                   {-2, 0.},
+                   {-1, 0.},
+                   {-0.5, 0.},
+                   {-0., 0.},
+                   {+0., 0.},
+                   {0.5, 0.},
+                   {1, 0.},
+                   {2, 0.},
+                   {INFINITY, 0.},
 
-    {NAN, 0.5},
-    {-INFINITY, 0.5},
-    {-2, 0.5},
-    {-1, 0.5},
-    {-0.5, 0.5},
-    {-0., 0.5},
-    {+0., 0.5},
-    {0.5, 0.5},
-    {1, 0.5},
-    {2, 0.5},
-    {INFINITY, 0.5},
+                   {NAN, 0.5},
+                   {-INFINITY, 0.5},
+                   {-2, 0.5},
+                   {-1, 0.5},
+                   {-0.5, 0.5},
+                   {-0., 0.5},
+                   {+0., 0.5},
+                   {0.5, 0.5},
+                   {1, 0.5},
+                   {2, 0.5},
+                   {INFINITY, 0.5},
 
-    {NAN, 1},
-    {-INFINITY, 1},
-    {-2, 1},
-    {-1, 1},
-    {-0.5, 1},
-    {-0., 1},
-    {+0., 1},
-    {0.5, 1},
-    {1, 1},
-    {2, 1},
-    {INFINITY, 1},
+                   {NAN, 1},
+                   {-INFINITY, 1},
+                   {-2, 1},
+                   {-1, 1},
+                   {-0.5, 1},
+                   {-0., 1},
+                   {+0., 1},
+                   {0.5, 1},
+                   {1, 1},
+                   {2, 1},
+                   {INFINITY, 1},
 
-    {NAN, 2},
-    {-INFINITY, 2},
-    {-2, 2},
-    {-1, 2},
-    {-0.5, 2},
-    {-0., 2},
-    {+0., 2},
-    {0.5, 2},
-    {1, 2},
-    {2, 2},
-    {INFINITY, 2},
+                   {NAN, 2},
+                   {-INFINITY, 2},
+                   {-2, 2},
+                   {-1, 2},
+                   {-0.5, 2},
+                   {-0., 2},
+                   {+0., 2},
+                   {0.5, 2},
+                   {1, 2},
+                   {2, 2},
+                   {INFINITY, 2},
 
-    {NAN, INFINITY},
-    {-INFINITY, INFINITY},
-    {-2, INFINITY},
-    {-1, INFINITY},
-    {-0.5, INFINITY},
-    {-0., INFINITY},
-    {+0., INFINITY},
-    {0.5, INFINITY},
-    {1, INFINITY},
-    {2, INFINITY},
-    {INFINITY, INFINITY}
+                   {NAN, INFINITY},
+                   {-INFINITY, INFINITY},
+                   {-2, INFINITY},
+                   {-1, INFINITY},
+                   {-0.5, INFINITY},
+                   {-0., INFINITY},
+                   {+0., INFINITY},
+                   {0.5, INFINITY},
+                   {1, INFINITY},
+                   {2, INFINITY},
+                   {INFINITY, INFINITY}
 
 };
 
-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/floattitf_test.c b/compiler-rt/test/builtins/Unit/floattitf_test.c
index abd3006135b38f7..34eed3cdaceb21d 100644
--- a/compiler-rt/test/builtins/Unit/floattitf_test.c
+++ b/compiler-rt/test/builtins/Unit/floattitf_test.c
@@ -7,7 +7,7 @@
 #include <float.h>
 #include <stdio.h>
 
-#if defined(CRT_HAS_TF_MODE)
+#if defined(CRT_HAS_TF_MODE) && defined(CRT_LDBL_IEEE_F128)
 
 /* Returns: convert a ti_int to a fp_t, rounding toward even. */
 
@@ -36,10 +36,7 @@ char assumption_1[sizeof(ti_int) == 2 * sizeof(di_int)] = {0};
 char assumption_2[sizeof(ti_int) * CHAR_BIT == 128] = {0};
 char assumption_3[sizeof(fp_t) * CHAR_BIT == 128] = {0};
 
-#endif
-
 int main() {
-#if defined(CRT_HAS_TF_MODE)
   if (test__floattitf(0, 0.0))
     return 1;
 
@@ -215,8 +212,12 @@ int main() {
   if (test__floattitf(make_ti(0x123456789ABCDEF0LL, 0x123456789ABC57FFLL),
                       TF_C(0x1.23456789ABCDEF0123456789ABC5p+124)))
     return 1;
+  return 0;
+}
+
 #else
+int main() {
   printf("skipped\n");
-#endif
   return 0;
 }
+#endif
diff --git a/compiler-rt/test/builtins/Unit/floatunditf_test.c b/compiler-rt/test/builtins/Unit/floatunditf_test.c
index 8da78da9760293a..aee4f52fa409fde 100644
--- 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 tf_float __floatunditf(du_int a);
 
 int test__floatunditf(du_int a, uint64_t expectedHi, uint64_t expectedLo)
 {
diff --git a/compiler-rt/test/builtins/Unit/floatuntitf_test.c b/compiler-rt/test/builtins/Unit/floatuntitf_test.c
index db25f2b0230cd14..39cc6ea6aab60dd 100644
--- a/compiler-rt/test/builtins/Unit/floatuntitf_test.c
+++ b/compiler-rt/test/builtins/Unit/floatuntitf_test.c
@@ -9,9 +9,9 @@
 
 #if defined(CRT_HAS_TF_MODE)
 
-/* Returns: convert a tu_int to a fp_t, rounding toward even. */
+/* Returns: convert a tu_int to a tf_float, rounding toward even. */
 
-/* Assumption: fp_t is a IEEE 128 bit floating point type
+/* Assumption: tf_float is a IEEE 128 bit floating point type
  *             tu_int is a 128 bit integral type
  */
 
@@ -19,10 +19,10 @@
  * mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
  */
 
-COMPILER_RT_ABI fp_t __floatuntitf(tu_int a);
+COMPILER_RT_ABI tf_float __floatuntitf(tu_int a);
 
-int test__floatuntitf(tu_int a, fp_t expected) {
-  fp_t x = __floatuntitf(a);
+int test__floatuntitf(tu_int a, tf_float expected) {
+  tf_float x = __floatuntitf(a);
   if (x != expected) {
     utwords at;
     at.all = a;
@@ -34,7 +34,7 @@ int test__floatuntitf(tu_int a, fp_t expected) {
 
 char assumption_1[sizeof(tu_int) == 2 * sizeof(du_int)] = {0};
 char assumption_2[sizeof(tu_int) * CHAR_BIT == 128] = {0};
-char assumption_3[sizeof(fp_t) * CHAR_BIT == 128] = {0};
+char assumption_3[sizeof(tf_float) * CHAR_BIT == 128] = {0};
 
 #endif
 



More information about the llvm-commits mailing list