[compiler-rt] [builtins] Convert more int to fp functions to use common implementation (PR #67540)

Alex Bradbury via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 27 04:10:46 PDT 2023


https://github.com/asb created https://github.com/llvm/llvm-project/pull/67540

Builds on #66903, converting the rest of the low-hanging fruit to use the common implementation.

I was holding off posting more of the patch series as it's (sadly) rather awkward on GitHub. But I'll post this next patch in the hope it better demonstrates the direction.

>From 324ecfb79cb20a31c540697ac05ef23909c3a396 Mon Sep 17 00:00:00 2001
From: Alex Bradbury <asb at igalia.com>
Date: Wed, 20 Sep 2023 13:41:56 +0100
Subject: [PATCH 1/2] [compiler-rt] Start to refactor int to fp conversion
 functions to use a common implementation

After this path, the softfp implementations of floatdidf and floatundidf
use a common implementation (int_to_fp.h and int_to_fp_impl.inc). This
roughly follows the pattern used for a wide range of other builtins,
e.g. fp_trunc_impl.inc.

Currently there is substantial copy and paste for the various int to fp
conversion functions, with just a few constants being changed. This is a
barrier to maintainability, and it's also not attractive to copy this
approach as we introduce additional int to fp conversion functions for
bf16 and half (which we currently lack, but need - see
<https://reviews.llvm.org/D157509>).

I welcome feedback on the approach taken here, as well as the best way
to move forward to land it. I've opted to conservatively start by
replacing just two functions, leaving a follow-up patch to replace
others that follow the same pattern. Also, for better or worse I've left
the logic in float[un]didf largely unchanged other than using a similar
approach to fp_trunc_impl.inc to remove the constants that are tied to a
specific output floating point format.
---
 compiler-rt/lib/builtins/floatdidf.c        | 52 ++--------------
 compiler-rt/lib/builtins/floatundidf.c      | 49 ++-------------
 compiler-rt/lib/builtins/int_to_fp.h        | 51 +++++++++++++++
 compiler-rt/lib/builtins/int_to_fp_impl.inc | 69 +++++++++++++++++++++
 4 files changed, 130 insertions(+), 91 deletions(-)
 create mode 100644 compiler-rt/lib/builtins/int_to_fp.h
 create mode 100644 compiler-rt/lib/builtins/int_to_fp_impl.inc

diff --git a/compiler-rt/lib/builtins/floatdidf.c b/compiler-rt/lib/builtins/floatdidf.c
index c994aad3f079ef3..6da81f7a05bf233 100644
--- a/compiler-rt/lib/builtins/floatdidf.c
+++ b/compiler-rt/lib/builtins/floatdidf.c
@@ -45,53 +45,11 @@ COMPILER_RT_ABI double __floatdidf(di_int a) {
 // flags to set, and we don't want to code-gen to an unknown soft-float
 // implementation.
 
-COMPILER_RT_ABI double __floatdidf(di_int a) {
-  if (a == 0)
-    return 0.0;
-  const unsigned N = sizeof(di_int) * CHAR_BIT;
-  const di_int s = a >> (N - 1);
-  a = (du_int)(a ^ s) - s;
-  int sd = N - __builtin_clzll(a); // number of significant digits
-  int e = sd - 1;                  // exponent
-  if (sd > DBL_MANT_DIG) {
-    //  start:  0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
-    //  finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
-    //                                                12345678901234567890123456
-    //  1 = msb 1 bit
-    //  P = bit DBL_MANT_DIG-1 bits to the right of 1
-    // Q = bit DBL_MANT_DIG bits to the right of 1
-    //  R = "or" of all bits to the right of Q
-    switch (sd) {
-    case DBL_MANT_DIG + 1:
-      a <<= 1;
-      break;
-    case DBL_MANT_DIG + 2:
-      break;
-    default:
-      a = ((du_int)a >> (sd - (DBL_MANT_DIG + 2))) |
-          ((a & ((du_int)(-1) >> ((N + DBL_MANT_DIG + 2) - sd))) != 0);
-    };
-    // finish:
-    a |= (a & 4) != 0; // Or P into R
-    ++a;               // round - this step may add a significant bit
-    a >>= 2;           // dump Q and R
-    // a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits
-    if (a & ((du_int)1 << DBL_MANT_DIG)) {
-      a >>= 1;
-      ++e;
-    }
-    // a is now rounded to DBL_MANT_DIG bits
-  } else {
-    a <<= (DBL_MANT_DIG - sd);
-    // a is now rounded to DBL_MANT_DIG bits
-  }
-  double_bits fb;
-  fb.u.s.high = ((su_int)s & 0x80000000) |        // sign
-                ((su_int)(e + 1023) << 20) |      // exponent
-                ((su_int)(a >> 32) & 0x000FFFFF); // mantissa-high
-  fb.u.s.low = (su_int)a;                         // mantissa-low
-  return fb.f;
-}
+#define SRC_I64
+#define DST_DOUBLE
+#include "int_to_fp_impl.inc"
+
+COMPILER_RT_ABI double __floatdidf(di_int a) { return __floatXiYf__(a); }
 #endif
 
 #if defined(__ARM_EABI__)
diff --git a/compiler-rt/lib/builtins/floatundidf.c b/compiler-rt/lib/builtins/floatundidf.c
index 2ec802cdc134ff0..9743e96ec67912a 100644
--- a/compiler-rt/lib/builtins/floatundidf.c
+++ b/compiler-rt/lib/builtins/floatundidf.c
@@ -51,50 +51,11 @@ COMPILER_RT_ABI double __floatundidf(du_int a) {
 // flags to set, and we don't want to code-gen to an unknown soft-float
 // implementation.
 
-COMPILER_RT_ABI double __floatundidf(du_int a) {
-  if (a == 0)
-    return 0.0;
-  const unsigned N = sizeof(du_int) * CHAR_BIT;
-  int sd = N - __builtin_clzll(a); // number of significant digits
-  int e = sd - 1;                  // exponent
-  if (sd > DBL_MANT_DIG) {
-    //  start:  0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
-    //  finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
-    //                                                12345678901234567890123456
-    //  1 = msb 1 bit
-    //  P = bit DBL_MANT_DIG-1 bits to the right of 1
-    //  Q = bit DBL_MANT_DIG bits to the right of 1
-    //  R = "or" of all bits to the right of Q
-    switch (sd) {
-    case DBL_MANT_DIG + 1:
-      a <<= 1;
-      break;
-    case DBL_MANT_DIG + 2:
-      break;
-    default:
-      a = (a >> (sd - (DBL_MANT_DIG + 2))) |
-          ((a & ((du_int)(-1) >> ((N + DBL_MANT_DIG + 2) - sd))) != 0);
-    };
-    // finish:
-    a |= (a & 4) != 0; // Or P into R
-    ++a;               // round - this step may add a significant bit
-    a >>= 2;           // dump Q and R
-    // a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits
-    if (a & ((du_int)1 << DBL_MANT_DIG)) {
-      a >>= 1;
-      ++e;
-    }
-    // a is now rounded to DBL_MANT_DIG bits
-  } else {
-    a <<= (DBL_MANT_DIG - sd);
-    // a is now rounded to DBL_MANT_DIG bits
-  }
-  double_bits fb;
-  fb.u.s.high = ((su_int)(e + 1023) << 20) |      // exponent
-                ((su_int)(a >> 32) & 0x000FFFFF); // mantissa-high
-  fb.u.s.low = (su_int)a;                         // mantissa-low
-  return fb.f;
-}
+#define SRC_U64
+#define DST_DOUBLE
+#include "int_to_fp_impl.inc"
+
+COMPILER_RT_ABI double __floatundidf(du_int a) { return __floatXiYf__(a); }
 #endif
 
 #if defined(__ARM_EABI__)
diff --git a/compiler-rt/lib/builtins/int_to_fp.h b/compiler-rt/lib/builtins/int_to_fp.h
new file mode 100644
index 000000000000000..dbab5130fb39e61
--- /dev/null
+++ b/compiler-rt/lib/builtins/int_to_fp.h
@@ -0,0 +1,51 @@
+//===-- int_to_fp.h - integer to floating point conversion ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Set source and destination defines in order to use a correctly
+// parameterised floatXiYf implementation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef INT_TO_FP_H
+#define INT_TO_FP_H
+
+#include "int_lib.h"
+
+#if defined SRC_I64
+typedef int64_t src_t;
+typedef uint64_t usrc_t;
+static __inline int clzSrcT(usrc_t x) { return __builtin_clzll(x); }
+
+#elif defined SRC_U64
+typedef uint64_t src_t;
+typedef uint64_t usrc_t;
+static __inline int clzSrcT(usrc_t x) { return __builtin_clzll(x); }
+
+#else
+#error Source should be a handled integer type.
+#endif
+
+#if defined DST_DOUBLE
+typedef double dst_t;
+typedef uint64_t dst_rep_t;
+#define DST_REP_C UINT64_C
+static const int dstSigBits = 52;
+
+#else
+#error Destination should be a handled floating point type
+#endif
+
+static __inline dst_t dstFromRep(dst_rep_t x) {
+  const union {
+    dst_t f;
+    dst_rep_t i;
+  } rep = {.i = x};
+  return rep.f;
+}
+
+#endif // INT_TO_FP_H
diff --git a/compiler-rt/lib/builtins/int_to_fp_impl.inc b/compiler-rt/lib/builtins/int_to_fp_impl.inc
new file mode 100644
index 000000000000000..c49f2c9607ec153
--- /dev/null
+++ b/compiler-rt/lib/builtins/int_to_fp_impl.inc
@@ -0,0 +1,69 @@
+//===-- int_to_fp_impl.inc - integer to floating point conversion ---------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Thsi file implements a generic conversion from an integer type to an
+// IEEE-754 floating point type, allowing a common implementation to be hsared
+// without copy and paste.
+//
+//===----------------------------------------------------------------------===//
+
+#include "int_to_fp.h"
+
+static __inline dst_t __floatXiYf__(src_t a) {
+  if (a == 0)
+    return 0.0;
+  const int dstMantDig = dstSigBits + 1;
+  const int srcBits = sizeof(src_t) * CHAR_BIT;
+  const int srcIsSigned = ((src_t)-1) < 0;
+  const src_t s = srcIsSigned ? a >> (srcBits - 1) : 0;
+  a = (usrc_t)(a ^ s) - s;
+  int sd = srcBits - clzSrcT(a);         // number of significant digits
+  int e = sd - 1;                        // exponent
+  if (sd > dstMantDig) {
+    //  start:  0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+    //  finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+    //                                                12345678901234567890123456
+    //  1 = msb 1 bit
+    //  P = bit dstMantDig-1 bits to the right of 1
+    //  Q = bit dstMantDig bits to the right of 1
+    //  R = "or" of all bits to the right of Q
+    switch (sd) {
+    case dstMantDig + 1:
+      a <<= 1;
+      break;
+    case dstMantDig + 2:
+      break;
+    default:
+      a = ((usrc_t)a >> (sd - (dstMantDig + 2))) |
+          ((a & ((usrc_t)(-1) >> ((srcBits + dstMantDig + 2) - sd))) != 0);
+    };
+    // finish:
+    a |= (a & 4) != 0; // Or P into R
+    ++a;               // round - this step may add a significant bit
+    a >>= 2;           // dump Q and R
+    // a is now rounded to dstMantDig or dstMantDig+1 bits
+    if (a & ((usrc_t)1 << dstMantDig)) {
+      a >>= 1;
+      ++e;
+    }
+    // a is now rounded to dstMantDig bits
+  } else {
+    a <<= (dstMantDig - sd);
+    // a is now rounded to dstMantDig bits
+  }
+  const int dstBits = sizeof(dst_t) * CHAR_BIT;
+  const dst_rep_t dstSignMask = DST_REP_C(1) << (dstBits - 1);
+  const int dstExpBits = dstBits - dstSigBits - 1;
+  const int dstExpBias = (1 << (dstExpBits - 1)) - 1;
+  const dst_rep_t dstSignificandMask = (DST_REP_C(1) << dstSigBits) - 1;
+  // Combine sign, exponent, and mantissa.
+  const dst_rep_t result = ((dst_rep_t)s & dstSignMask) |
+                           ((dst_rep_t)(e + dstExpBias) << dstSigBits) |
+                           ((dst_rep_t)(a) & dstSignificandMask);
+  return dstFromRep(result);
+}

>From 30951ffd83278dc003b1df6865559947a23ca13f Mon Sep 17 00:00:00 2001
From: Alex Bradbury <asb at igalia.com>
Date: Wed, 27 Sep 2023 06:18:16 +0100
Subject: [PATCH 2/2] [builtins] Convert more int to fp functions to use common
 implementation

Builds in #66903, converting the rest of the low-hanging fruit to use
the common implementation.
---
 compiler-rt/lib/builtins/floatdisf.c   | 51 +++----------------------
 compiler-rt/lib/builtins/floattidf.c   | 52 +++----------------------
 compiler-rt/lib/builtins/floattisf.c   | 51 +++----------------------
 compiler-rt/lib/builtins/floattitf.c   | 53 +++-----------------------
 compiler-rt/lib/builtins/floatundisf.c | 48 +++--------------------
 compiler-rt/lib/builtins/floatuntidf.c | 49 +++---------------------
 compiler-rt/lib/builtins/floatuntisf.c | 48 +++--------------------
 compiler-rt/lib/builtins/floatuntitf.c | 50 +++---------------------
 compiler-rt/lib/builtins/int_to_fp.h   | 24 +++++++++++-
 9 files changed, 63 insertions(+), 363 deletions(-)

diff --git a/compiler-rt/lib/builtins/floatdisf.c b/compiler-rt/lib/builtins/floatdisf.c
index 0b62ed8689bc691..0bb88c5c518eeca 100644
--- a/compiler-rt/lib/builtins/floatdisf.c
+++ b/compiler-rt/lib/builtins/floatdisf.c
@@ -19,52 +19,11 @@
 
 #include "int_lib.h"
 
-COMPILER_RT_ABI float __floatdisf(di_int a) {
-  if (a == 0)
-    return 0.0F;
-  const unsigned N = sizeof(di_int) * CHAR_BIT;
-  const di_int s = a >> (N - 1);
-  a = (du_int)(a ^ s) - s;
-  int sd = N - __builtin_clzll(a); // number of significant digits
-  si_int e = sd - 1;               // exponent
-  if (sd > FLT_MANT_DIG) {
-    //  start:  0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
-    //  finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
-    //                                                12345678901234567890123456
-    //  1 = msb 1 bit
-    //  P = bit FLT_MANT_DIG-1 bits to the right of 1
-    //  Q = bit FLT_MANT_DIG bits to the right of 1
-    //  R = "or" of all bits to the right of Q
-    switch (sd) {
-    case FLT_MANT_DIG + 1:
-      a <<= 1;
-      break;
-    case FLT_MANT_DIG + 2:
-      break;
-    default:
-      a = ((du_int)a >> (sd - (FLT_MANT_DIG + 2))) |
-          ((a & ((du_int)(-1) >> ((N + FLT_MANT_DIG + 2) - sd))) != 0);
-    };
-    // finish:
-    a |= (a & 4) != 0; // Or P into R
-    ++a;               // round - this step may add a significant bit
-    a >>= 2;           // dump Q and R
-    // a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits
-    if (a & ((du_int)1 << FLT_MANT_DIG)) {
-      a >>= 1;
-      ++e;
-    }
-    // a is now rounded to FLT_MANT_DIG bits
-  } else {
-    a <<= (FLT_MANT_DIG - sd);
-    // a is now rounded to FLT_MANT_DIG bits
-  }
-  float_bits fb;
-  fb.u = ((su_int)s & 0x80000000) | // sign
-         ((e + 127) << 23) |        // exponent
-         ((su_int)a & 0x007FFFFF);  // mantissa
-  return fb.f;
-}
+#define SRC_I64
+#define DST_SINGLE
+#include "int_to_fp_impl.inc"
+
+COMPILER_RT_ABI float __floatdisf(di_int a) { return __floatXiYf__(a); }
 
 #if defined(__ARM_EABI__)
 #if defined(COMPILER_RT_ARMHF_TARGET)
diff --git a/compiler-rt/lib/builtins/floattidf.c b/compiler-rt/lib/builtins/floattidf.c
index 7bfe87f53aa0257..ef8fe180e2f511d 100644
--- a/compiler-rt/lib/builtins/floattidf.c
+++ b/compiler-rt/lib/builtins/floattidf.c
@@ -14,6 +14,10 @@
 
 #ifdef CRT_HAS_128BIT
 
+#define SRC_I128
+#define DST_DOUBLE
+#include "int_to_fp_impl.inc"
+
 // Returns: convert a to a double, rounding toward even.
 
 // Assumption: double is a IEEE 64 bit floating point type
@@ -22,52 +26,6 @@
 // seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm
 // mmmm
 
-COMPILER_RT_ABI double __floattidf(ti_int a) {
-  if (a == 0)
-    return 0.0;
-  const unsigned N = sizeof(ti_int) * CHAR_BIT;
-  const ti_int s = a >> (N - 1);
-  a = (a ^ s) - s;
-  int sd = N - __clzti2(a); // number of significant digits
-  si_int e = sd - 1;        // exponent
-  if (sd > DBL_MANT_DIG) {
-    // start:  0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
-    //  finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
-    //                                               12345678901234567890123456
-    // 1 = msb 1 bit
-    // P = bit DBL_MANT_DIG-1 bits to the right of 1
-    // Q = bit DBL_MANT_DIG bits to the right of 1
-    // R = "or" of all bits to the right of Q
-    switch (sd) {
-    case DBL_MANT_DIG + 1:
-      a <<= 1;
-      break;
-    case DBL_MANT_DIG + 2:
-      break;
-    default:
-      a = ((tu_int)a >> (sd - (DBL_MANT_DIG + 2))) |
-          ((a & ((tu_int)(-1) >> ((N + DBL_MANT_DIG + 2) - sd))) != 0);
-    };
-    // finish:
-    a |= (a & 4) != 0; // Or P into R
-    ++a;               // round - this step may add a significant bit
-    a >>= 2;           // dump Q and R
-    // a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits
-    if (a & ((tu_int)1 << DBL_MANT_DIG)) {
-      a >>= 1;
-      ++e;
-    }
-    // a is now rounded to DBL_MANT_DIG bits
-  } else {
-    a <<= (DBL_MANT_DIG - sd);
-    // a is now rounded to DBL_MANT_DIG bits
-  }
-  double_bits fb;
-  fb.u.s.high = ((su_int)s & 0x80000000) |        // sign
-                ((e + 1023) << 20) |              // exponent
-                ((su_int)(a >> 32) & 0x000FFFFF); // mantissa-high
-  fb.u.s.low = (su_int)a;                         // mantissa-low
-  return fb.f;
-}
+COMPILER_RT_ABI double __floattidf(ti_int a) { return __floatXiYf__(a); }
 
 #endif // CRT_HAS_128BIT
diff --git a/compiler-rt/lib/builtins/floattisf.c b/compiler-rt/lib/builtins/floattisf.c
index 717cb361f075ad7..77589902f54417c 100644
--- a/compiler-rt/lib/builtins/floattisf.c
+++ b/compiler-rt/lib/builtins/floattisf.c
@@ -14,6 +14,10 @@
 
 #ifdef CRT_HAS_128BIT
 
+#define SRC_I128
+#define DST_SINGLE
+#include "int_to_fp_impl.inc"
+
 // Returns: convert a to a float, rounding toward even.
 
 // Assumption: float is a IEEE 32 bit floating point type
@@ -21,51 +25,6 @@
 
 // seee eeee emmm mmmm mmmm mmmm mmmm mmmm
 
-COMPILER_RT_ABI float __floattisf(ti_int a) {
-  if (a == 0)
-    return 0.0F;
-  const unsigned N = sizeof(ti_int) * CHAR_BIT;
-  const ti_int s = a >> (N - 1);
-  a = (a ^ s) - s;
-  int sd = N - __clzti2(a); // number of significant digits
-  si_int e = sd - 1;        // exponent
-  if (sd > FLT_MANT_DIG) {
-    //  start:  0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
-    // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
-    //                                                12345678901234567890123456
-    //  1 = msb 1 bit
-    //  P = bit FLT_MANT_DIG-1 bits to the right of 1
-    //  Q = bit FLT_MANT_DIG bits to the right of 1
-    //  R = "or" of all bits to the right of Q
-    switch (sd) {
-    case FLT_MANT_DIG + 1:
-      a <<= 1;
-      break;
-    case FLT_MANT_DIG + 2:
-      break;
-    default:
-      a = ((tu_int)a >> (sd - (FLT_MANT_DIG + 2))) |
-          ((a & ((tu_int)(-1) >> ((N + FLT_MANT_DIG + 2) - sd))) != 0);
-    };
-    // finish:
-    a |= (a & 4) != 0; // Or P into R
-    ++a;               // round - this step may add a significant bit
-    a >>= 2;           // dump Q and R
-    // a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits
-    if (a & ((tu_int)1 << FLT_MANT_DIG)) {
-      a >>= 1;
-      ++e;
-    }
-    // a is now rounded to FLT_MANT_DIG bits
-  } else {
-    a <<= (FLT_MANT_DIG - sd);
-    // a is now rounded to FLT_MANT_DIG bits
-  }
-  float_bits fb;
-  fb.u = ((su_int)s & 0x80000000) | // sign
-         ((e + 127) << 23) |        // exponent
-         ((su_int)a & 0x007FFFFF);  // mantissa
-  return fb.f;
-}
+COMPILER_RT_ABI float __floattisf(ti_int a) { return __floatXiYf__(a); }
 
 #endif // CRT_HAS_128BIT
diff --git a/compiler-rt/lib/builtins/floattitf.c b/compiler-rt/lib/builtins/floattitf.c
index fff0755c3bb46a3..697bc8fb11107ca 100644
--- a/compiler-rt/lib/builtins/floattitf.c
+++ b/compiler-rt/lib/builtins/floattitf.c
@@ -16,6 +16,10 @@
 #include "fp_lib.h"
 #include "int_lib.h"
 
+#define SRC_I128
+#define DST_QUAD
+#include "int_to_fp_impl.inc"
+
 // Returns: convert a ti_int to a fp_t, rounding toward even.
 
 // Assumption: fp_t is a IEEE 128 bit floating point type
@@ -26,53 +30,6 @@
 // mmmm mmmm mmmm
 
 #if defined(CRT_HAS_TF_MODE)
-COMPILER_RT_ABI fp_t __floattitf(ti_int a) {
-  if (a == 0)
-    return 0.0;
-  const unsigned N = sizeof(ti_int) * CHAR_BIT;
-  const ti_int s = a >> (N - 1);
-  a = (a ^ s) - s;
-  int sd = N - __clzti2(a); // number of significant digits
-  int e = sd - 1;           // exponent
-  if (sd > TF_MANT_DIG) {
-    //  start:  0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
-    //  finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
-    //                                                12345678901234567890123456
-    //  1 = msb 1 bit
-    //  P = bit LDBL_MANT_DIG-1 bits to the right of 1
-    //  Q = bit LDBL_MANT_DIG bits to the right of 1
-    //  R = "or" of all bits to the right of Q
-    switch (sd) {
-    case TF_MANT_DIG + 1:
-      a <<= 1;
-      break;
-    case TF_MANT_DIG + 2:
-      break;
-    default:
-      a = ((tu_int)a >> (sd - (TF_MANT_DIG + 2))) |
-          ((a & ((tu_int)(-1) >> ((N + TF_MANT_DIG + 2) - sd))) != 0);
-    };
-    // finish:
-    a |= (a & 4) != 0; // Or P into R
-    ++a;               // round - this step may add a significant bit
-    a >>= 2;           // dump Q and R
-    // a is now rounded to LDBL_MANT_DIG or LDBL_MANT_DIG+1 bits
-    if (a & ((tu_int)1 << TF_MANT_DIG)) {
-      a >>= 1;
-      ++e;
-    }
-    // a is now rounded to LDBL_MANT_DIG bits
-  } else {
-    a <<= (TF_MANT_DIG - sd);
-    // a is now rounded to LDBL_MANT_DIG bits
-  }
-
-  long_double_bits fb;
-  fb.u.high.all = (s & 0x8000000000000000LL)            // sign
-                  | (du_int)(e + 16383) << 48           // exponent
-                  | ((a >> 64) & 0x0000ffffffffffffLL); // significand
-  fb.u.low.all = (du_int)(a);
-  return fb.f;
-}
+COMPILER_RT_ABI fp_t __floattitf(ti_int a) { return __floatXiYf__(a); }
 
 #endif
diff --git a/compiler-rt/lib/builtins/floatundisf.c b/compiler-rt/lib/builtins/floatundisf.c
index 2a4157dc5e4b96e..d4b418efd406ff5 100644
--- a/compiler-rt/lib/builtins/floatundisf.c
+++ b/compiler-rt/lib/builtins/floatundisf.c
@@ -19,49 +19,11 @@
 
 #include "int_lib.h"
 
-COMPILER_RT_ABI float __floatundisf(du_int a) {
-  if (a == 0)
-    return 0.0F;
-  const unsigned N = sizeof(du_int) * CHAR_BIT;
-  int sd = N - __builtin_clzll(a); // number of significant digits
-  si_int e = sd - 1;               // 8 exponent
-  if (sd > FLT_MANT_DIG) {
-    //  start:  0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
-    //  finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
-    //                                                12345678901234567890123456
-    //  1 = msb 1 bit
-    //  P = bit FLT_MANT_DIG-1 bits to the right of 1
-    //  Q = bit FLT_MANT_DIG bits to the right of 1
-    //  R = "or" of all bits to the right of Q
-    switch (sd) {
-    case FLT_MANT_DIG + 1:
-      a <<= 1;
-      break;
-    case FLT_MANT_DIG + 2:
-      break;
-    default:
-      a = (a >> (sd - (FLT_MANT_DIG + 2))) |
-          ((a & ((du_int)(-1) >> ((N + FLT_MANT_DIG + 2) - sd))) != 0);
-    };
-    // finish:
-    a |= (a & 4) != 0; // Or P into R
-    ++a;               // round - this step may add a significant bit
-    a >>= 2;           // dump Q and R
-    // a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits
-    if (a & ((du_int)1 << FLT_MANT_DIG)) {
-      a >>= 1;
-      ++e;
-    }
-    // a is now rounded to FLT_MANT_DIG bits
-  } else {
-    a <<= (FLT_MANT_DIG - sd);
-    // a is now rounded to FLT_MANT_DIG bits
-  }
-  float_bits fb;
-  fb.u = ((e + 127) << 23) |       // exponent
-         ((su_int)a & 0x007FFFFF); // mantissa
-  return fb.f;
-}
+#define SRC_U64
+#define DST_SINGLE
+#include "int_to_fp_impl.inc"
+
+COMPILER_RT_ABI float __floatundisf(du_int a) { return __floatXiYf__(a); }
 
 #if defined(__ARM_EABI__)
 #if defined(COMPILER_RT_ARMHF_TARGET)
diff --git a/compiler-rt/lib/builtins/floatuntidf.c b/compiler-rt/lib/builtins/floatuntidf.c
index 4dfca8e493098a0..9abeacc30c3c3f6 100644
--- a/compiler-rt/lib/builtins/floatuntidf.c
+++ b/compiler-rt/lib/builtins/floatuntidf.c
@@ -14,6 +14,10 @@
 
 #ifdef CRT_HAS_128BIT
 
+#define SRC_U128
+#define DST_DOUBLE
+#include "int_to_fp_impl.inc"
+
 // Returns: convert a to a double, rounding toward even.
 
 // Assumption: double is a IEEE 64 bit floating point type
@@ -22,49 +26,6 @@
 // seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm
 // mmmm
 
-COMPILER_RT_ABI double __floatuntidf(tu_int a) {
-  if (a == 0)
-    return 0.0;
-  const unsigned N = sizeof(tu_int) * CHAR_BIT;
-  int sd = N - __clzti2(a); // number of significant digits
-  si_int e = sd - 1;        // exponent
-  if (sd > DBL_MANT_DIG) {
-    //  start:  0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
-    //  finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
-    //                                                12345678901234567890123456
-    //  1 = msb 1 bit
-    //  P = bit DBL_MANT_DIG-1 bits to the right of 1
-    //  Q = bit DBL_MANT_DIG bits to the right of 1
-    //  R = "or" of all bits to the right of Q
-    switch (sd) {
-    case DBL_MANT_DIG + 1:
-      a <<= 1;
-      break;
-    case DBL_MANT_DIG + 2:
-      break;
-    default:
-      a = (a >> (sd - (DBL_MANT_DIG + 2))) |
-          ((a & ((tu_int)(-1) >> ((N + DBL_MANT_DIG + 2) - sd))) != 0);
-    };
-    // finish:
-    a |= (a & 4) != 0; // Or P into R
-    ++a;               // round - this step may add a significant bit
-    a >>= 2;           // dump Q and R
-    // a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits
-    if (a & ((tu_int)1 << DBL_MANT_DIG)) {
-      a >>= 1;
-      ++e;
-    }
-    // a is now rounded to DBL_MANT_DIG bits
-  } else {
-    a <<= (DBL_MANT_DIG - sd);
-    // a is now rounded to DBL_MANT_DIG bits
-  }
-  double_bits fb;
-  fb.u.s.high = ((e + 1023) << 20) |              // exponent
-                ((su_int)(a >> 32) & 0x000FFFFF); // mantissa-high
-  fb.u.s.low = (su_int)a;                         // mantissa-low
-  return fb.f;
-}
+COMPILER_RT_ABI double __floatuntidf(tu_int a) { return __floatXiYf__(a); }
 
 #endif // CRT_HAS_128BIT
diff --git a/compiler-rt/lib/builtins/floatuntisf.c b/compiler-rt/lib/builtins/floatuntisf.c
index a53659cd1fcac40..997c1569acd67eb 100644
--- a/compiler-rt/lib/builtins/floatuntisf.c
+++ b/compiler-rt/lib/builtins/floatuntisf.c
@@ -14,6 +14,10 @@
 
 #ifdef CRT_HAS_128BIT
 
+#define SRC_U128
+#define DST_SINGLE
+#include "int_to_fp_impl.inc"
+
 // Returns: convert a to a float, rounding toward even.
 
 // Assumption: float is a IEEE 32 bit floating point type
@@ -21,48 +25,6 @@
 
 // seee eeee emmm mmmm mmmm mmmm mmmm mmmm
 
-COMPILER_RT_ABI float __floatuntisf(tu_int a) {
-  if (a == 0)
-    return 0.0F;
-  const unsigned N = sizeof(tu_int) * CHAR_BIT;
-  int sd = N - __clzti2(a); // number of significant digits
-  si_int e = sd - 1;        // exponent
-  if (sd > FLT_MANT_DIG) {
-    //  start:  0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
-    //  finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
-    //                                                12345678901234567890123456
-    //  1 = msb 1 bit
-    //  P = bit FLT_MANT_DIG-1 bits to the right of 1
-    //  Q = bit FLT_MANT_DIG bits to the right of 1
-    //  R = "or" of all bits to the right of Q
-    switch (sd) {
-    case FLT_MANT_DIG + 1:
-      a <<= 1;
-      break;
-    case FLT_MANT_DIG + 2:
-      break;
-    default:
-      a = (a >> (sd - (FLT_MANT_DIG + 2))) |
-          ((a & ((tu_int)(-1) >> ((N + FLT_MANT_DIG + 2) - sd))) != 0);
-    };
-    // finish:
-    a |= (a & 4) != 0; // Or P into R
-    ++a;               // round - this step may add a significant bit
-    a >>= 2;           // dump Q and R
-    // a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits
-    if (a & ((tu_int)1 << FLT_MANT_DIG)) {
-      a >>= 1;
-      ++e;
-    }
-    // a is now rounded to FLT_MANT_DIG bits
-  } else {
-    a <<= (FLT_MANT_DIG - sd);
-    // a is now rounded to FLT_MANT_DIG bits
-  }
-  float_bits fb;
-  fb.u = ((e + 127) << 23) |       // exponent
-         ((su_int)a & 0x007FFFFF); // mantissa
-  return fb.f;
-}
+COMPILER_RT_ABI float __floatuntisf(tu_int a) { return __floatXiYf__(a); }
 
 #endif // CRT_HAS_128BIT
diff --git a/compiler-rt/lib/builtins/floatuntitf.c b/compiler-rt/lib/builtins/floatuntitf.c
index 33a81b34eeb195b..c9639989d3c2a3a 100644
--- a/compiler-rt/lib/builtins/floatuntitf.c
+++ b/compiler-rt/lib/builtins/floatuntitf.c
@@ -16,6 +16,10 @@
 #include "fp_lib.h"
 #include "int_lib.h"
 
+#define SRC_U128
+#define DST_QUAD
+#include "int_to_fp_impl.inc"
+
 // Returns: convert a tu_int to a fp_t, rounding toward even.
 
 // Assumption: fp_t is a IEEE 128 bit floating point type
@@ -26,50 +30,6 @@
 // mmmm mmmm mmmm
 
 #if defined(CRT_HAS_TF_MODE)
-COMPILER_RT_ABI fp_t __floatuntitf(tu_int a) {
-  if (a == 0)
-    return 0.0;
-  const unsigned N = sizeof(tu_int) * CHAR_BIT;
-  int sd = N - __clzti2(a); // number of significant digits
-  int e = sd - 1;           // exponent
-  if (sd > TF_MANT_DIG) {
-    //  start:  0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
-    //  finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
-    //                                                12345678901234567890123456
-    //  1 = msb 1 bit
-    //  P = bit TF_MANT_DIG-1 bits to the right of 1
-    //  Q = bit TF_MANT_DIG bits to the right of 1
-    //  R = "or" of all bits to the right of Q
-    switch (sd) {
-    case TF_MANT_DIG + 1:
-      a <<= 1;
-      break;
-    case TF_MANT_DIG + 2:
-      break;
-    default:
-      a = (a >> (sd - (TF_MANT_DIG + 2))) |
-          ((a & ((tu_int)(-1) >> ((N + TF_MANT_DIG + 2) - sd))) != 0);
-    };
-    // finish:
-    a |= (a & 4) != 0; // Or P into R
-    ++a;               // round - this step may add a significant bit
-    a >>= 2;           // dump Q and R
-    // a is now rounded to TF_MANT_DIG or TF_MANT_DIG+1 bits
-    if (a & ((tu_int)1 << TF_MANT_DIG)) {
-      a >>= 1;
-      ++e;
-    }
-    // a is now rounded to TF_MANT_DIG bits
-  } else {
-    a <<= (TF_MANT_DIG - sd);
-    // a is now rounded to TF_MANT_DIG bits
-  }
-
-  long_double_bits fb;
-  fb.u.high.all = (du_int)(e + 16383) << 48             // exponent
-                  | ((a >> 64) & 0x0000ffffffffffffLL); // significand
-  fb.u.low.all = (du_int)(a);
-  return fb.f;
-}
+COMPILER_RT_ABI fp_t __floatuntitf(tu_int a) { return __floatXiYf__(a); }
 
 #endif
diff --git a/compiler-rt/lib/builtins/int_to_fp.h b/compiler-rt/lib/builtins/int_to_fp.h
index dbab5130fb39e61..1adce097d7a8568 100644
--- a/compiler-rt/lib/builtins/int_to_fp.h
+++ b/compiler-rt/lib/builtins/int_to_fp.h
@@ -26,16 +26,38 @@ typedef uint64_t src_t;
 typedef uint64_t usrc_t;
 static __inline int clzSrcT(usrc_t x) { return __builtin_clzll(x); }
 
+#elif defined SRC_I128
+typedef __int128_t src_t;
+typedef __uint128_t usrc_t;
+static __inline int clzSrcT(usrc_t x) { return __clzti2(x); }
+
+#elif defined SRC_U128
+typedef __uint128_t src_t;
+typedef __uint128_t usrc_t;
+static __inline int clzSrcT(usrc_t x) { return __clzti2(x); }
+
 #else
 #error Source should be a handled integer type.
 #endif
 
-#if defined DST_DOUBLE
+#if defined DST_SINGLE
+typedef float dst_t;
+typedef uint32_t dst_rep_t;
+#define DST_REP_C UINT32_C
+static const int dstSigBits = 23;
+
+#elif defined DST_DOUBLE
 typedef double dst_t;
 typedef uint64_t dst_rep_t;
 #define DST_REP_C UINT64_C
 static const int dstSigBits = 52;
 
+#elif defined DST_QUAD
+typedef long double dst_t;
+typedef __uint128_t dst_rep_t;
+#define DST_REP_C (__uint128_t)
+static const int dstSigBits = 112;
+
 #else
 #error Destination should be a handled floating point type
 #endif



More information about the llvm-commits mailing list