Refactor float to integer conversion to share the same code.
authorJoerg Sonnenberger <joerg@bec.de>
Wed, 11 Mar 2015 21:13:56 +0000 (21:13 +0000)
committerJoerg Sonnenberger <joerg@bec.de>
Wed, 11 Mar 2015 21:13:56 +0000 (21:13 +0000)
80bit Intel/PPC long double is excluded due to lacking support
for the abstraction. Consistently provide saturation logic.
Extend to long double on 128bit IEEE extended platforms.

Initial patch with test cases from GuanHong Liu.
Reviewed by Steve Canon.

Differential Revision: http://reviews.llvm.org/D2804

llvm-svn: 231965

27 files changed:
compiler-rt/lib/builtins/fixdfdi.c
compiler-rt/lib/builtins/fixdfsi.c
compiler-rt/lib/builtins/fixdfti.c
compiler-rt/lib/builtins/fixsfdi.c
compiler-rt/lib/builtins/fixsfsi.c
compiler-rt/lib/builtins/fixsfti.c
compiler-rt/lib/builtins/fixtfdi.c [new file with mode: 0644]
compiler-rt/lib/builtins/fixtfsi.c [new file with mode: 0644]
compiler-rt/lib/builtins/fixtfti.c [new file with mode: 0644]
compiler-rt/lib/builtins/fixunsdfdi.c
compiler-rt/lib/builtins/fixunsdfsi.c
compiler-rt/lib/builtins/fixunsdfti.c
compiler-rt/lib/builtins/fixunssfdi.c
compiler-rt/lib/builtins/fixunssfsi.c
compiler-rt/lib/builtins/fixunssfti.c
compiler-rt/lib/builtins/fixunstfdi.c [new file with mode: 0644]
compiler-rt/lib/builtins/fixunstfsi.c [new file with mode: 0644]
compiler-rt/lib/builtins/fixunstfti.c [new file with mode: 0644]
compiler-rt/lib/builtins/fixunsxfdi.c
compiler-rt/lib/builtins/fixunsxfsi.c
compiler-rt/lib/builtins/fixunsxfti.c
compiler-rt/lib/builtins/fixxfdi.c
compiler-rt/lib/builtins/fixxfti.c
compiler-rt/lib/builtins/fp_fixint_impl.inc [new file with mode: 0644]
compiler-rt/lib/builtins/fp_fixuint_impl.inc [new file with mode: 0644]
compiler-rt/test/builtins/Unit/fixtfsi_test.c [new file with mode: 0644]
compiler-rt/test/builtins/Unit/fixunstfsi_test.c [new file with mode: 0644]

index 86f9f6c..67b124a 100644 (file)
@@ -6,40 +6,17 @@
  * Source Licenses. See LICENSE.TXT for details.
  *
  * ===----------------------------------------------------------------------===
- *
- * This file implements __fixdfdi for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
  */
 
-#include "int_lib.h"
-
-/* Returns: convert a to a signed long long, rounding toward zero. */
-
-/* Assumption: double is a IEEE 64 bit floating point type 
- *            su_int is a 32 bit integral type
- *            value in double is representable in di_int (no range checking performed)
- */
-
-/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
-
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
 ARM_EABI_FNALIAS(d2lz, fixdfdi)
 
+typedef di_int fixint_t;
+typedef du_int fixuint_t;
+#include "fp_fixint_impl.inc"
+
 COMPILER_RT_ABI di_int
-__fixdfdi(double a)
-{
-    double_bits fb;
-    fb.f = a;
-    int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023;
-    if (e < 0)
-        return 0;
-    di_int s = (si_int)(fb.u.s.high & 0x80000000) >> 31;
-    dwords r;
-    r.s.high = (fb.u.s.high & 0x000FFFFF) | 0x00100000;
-    r.s.low = fb.u.s.low;
-    if (e > 52)
-        r.all <<= (e - 52);
-    else
-        r.all >>= (52 - e);
-    return (r.all ^ s) - s;
-} 
+__fixdfdi(fp_t a) {
+    return __fixint(a);
+}
index 88b2ff5..704e65b 100644 (file)
@@ -1,50 +1,22 @@
-//===-- lib/fixdfsi.c - Double-precision -> integer conversion ----*- C -*-===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements double-precision to integer conversion for the
-// compiler-rt library.  No range checking is performed; the behavior of this
-// conversion is undefined for out of range values in the C standard.
-//
-//===----------------------------------------------------------------------===//
+/* ===-- fixdfsi.c - Implement __fixdfsi -----------------------------------===
+ *
+ *                     The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
 
 #define DOUBLE_PRECISION
 #include "fp_lib.h"
-
-#include "int_lib.h"
+typedef si_int fixint_t;
+typedef su_int fixuint_t;
+#include "fp_fixint_impl.inc"
 
 ARM_EABI_FNALIAS(d2iz, fixdfsi)
 
-COMPILER_RT_ABI int
+COMPILER_RT_ABI si_int
 __fixdfsi(fp_t a) {
-    
-    // Break a into sign, exponent, significand
-    const rep_t aRep = toRep(a);
-    const rep_t aAbs = aRep & absMask;
-    const int sign = aRep & signBit ? -1 : 1;
-    const int exponent = (aAbs >> significandBits) - exponentBias;
-    const rep_t significand = (aAbs & significandMask) | implicitBit;
-    
-    // If 0 < exponent < significandBits, right shift to get the result.
-    if ((unsigned int)exponent < significandBits) {
-        return sign * (significand >> (significandBits - exponent));
-    }
-    
-    // If exponent is negative, the result is zero.
-    else if (exponent < 0) {
-        return 0;
-    }
-    
-    // If significandBits < exponent, left shift to get the result.  This shift
-    // may end up being larger than the type width, which incurs undefined
-    // behavior, but the conversion itself is undefined in that case, so
-    // whatever the compiler decides to do is fine.
-    else {
-        return sign * (significand << (exponent - significandBits));
-    }
+    return __fixint(a);
 }
index 2c27f4b..aaf225e 100644 (file)
@@ -6,40 +6,21 @@
  * Source Licenses. See LICENSE.TXT for details.
  *
  * ===----------------------------------------------------------------------===
- *
- * This file implements __fixdfti for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
  */
 
 #include "int_lib.h"
 
 #ifdef CRT_HAS_128BIT
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
 
-/* Returns: convert a to a signed long long, rounding toward zero. */
-
-/* Assumption: double is a IEEE 64 bit floating point type 
- *             su_int is a 32 bit integral type
- *             value in double is representable in ti_int (no range checking performed)
- */
-
-/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
+typedef ti_int fixint_t;
+typedef tu_int fixuint_t;
+#include "fp_fixint_impl.inc"
 
 COMPILER_RT_ABI ti_int
-__fixdfti(double a)
-{
-    double_bits fb;
-    fb.f = a;
-    int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023;
-    if (e < 0)
-        return 0;
-    ti_int s = (si_int)(fb.u.s.high & 0x80000000) >> 31;
-    ti_int r = 0x0010000000000000uLL | (0x000FFFFFFFFFFFFFuLL & fb.u.all);
-    if (e > 52)
-        r <<= (e - 52);
-    else
-        r >>= (52 - e);
-    return (r ^ s) - s;
+__fixdfti(fp_t a) {
+    return __fixint(a);
 }
 
 #endif /* CRT_HAS_128BIT */
index 4f6cfdd..835ff85 100644 (file)
@@ -1,43 +1,23 @@
 /* ===-- fixsfdi.c - Implement __fixsfdi -----------------------------------===
  *
- *                    The LLVM Compiler Infrastructure
+ *                     The LLVM Compiler Infrastructure
  *
  * This file is dual licensed under the MIT and the University of Illinois Open
  * Source Licenses. See LICENSE.TXT for details.
  *
  * ===----------------------------------------------------------------------===
- *
- * This file implements __fixsfdi for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-/* Returns: convert a to a signed long long, rounding toward zero. */
-
-/* Assumption: float is a IEEE 32 bit floating point type 
- *             su_int is a 32 bit integral type
- *             value in float is representable in di_int (no range checking performed)
  */
 
-/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
+#define SINGLE_PRECISION
+#include "fp_lib.h"
 
 ARM_EABI_FNALIAS(f2lz, fixsfdi)
 
+typedef di_int fixint_t;
+typedef du_int fixuint_t;
+#include "fp_fixint_impl.inc"
+
 COMPILER_RT_ABI di_int
-__fixsfdi(float a)
-{
-    float_bits fb;
-    fb.f = a;
-    int e = ((fb.u & 0x7F800000) >> 23) - 127;
-    if (e < 0)
-        return 0;
-    di_int s = (si_int)(fb.u & 0x80000000) >> 31;
-    di_int r = (fb.u & 0x007FFFFF) | 0x00800000;
-    if (e > 23)
-        r <<= (e - 23);
-    else
-        r >>= (23 - e);
-    return (r ^ s) - s;
+__fixsfdi(fp_t a) {
+    return __fixint(a);
 }
index e3cc42d..f045536 100644 (file)
@@ -1,47 +1,22 @@
-//===-- lib/fixsfsi.c - Single-precision -> integer conversion ----*- C -*-===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements single-precision to integer conversion for the
-// compiler-rt library.  No range checking is performed; the behavior of this
-// conversion is undefined for out of range values in the C standard.
-//
-//===----------------------------------------------------------------------===//
+/* ===-- fixsfsi.c - Implement __fixsfsi -----------------------------------===
+ *
+ *                     The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
 
 #define SINGLE_PRECISION
 #include "fp_lib.h"
+typedef si_int fixint_t;
+typedef su_int fixuint_t;
+#include "fp_fixint_impl.inc"
 
 ARM_EABI_FNALIAS(f2iz, fixsfsi)
 
-COMPILER_RT_ABI int
+COMPILER_RT_ABI si_int
 __fixsfsi(fp_t a) {
-    // Break a into sign, exponent, significand
-    const rep_t aRep = toRep(a);
-    const rep_t aAbs = aRep & absMask;
-    const int sign = aRep & signBit ? -1 : 1;
-    const int exponent = (aAbs >> significandBits) - exponentBias;
-    const rep_t significand = (aAbs & significandMask) | implicitBit;
-    
-    // If 0 < exponent < significandBits, right shift to get the result.
-    if ((unsigned int)exponent < significandBits) {
-        return sign * (significand >> (significandBits - exponent));
-    }
-    
-    // If exponent is negative, the result is zero.
-    else if (exponent < 0) {
-        return 0;
-    }
-    
-    // If significandBits < exponent, left shift to get the result.  This shift
-    // may end up being larger than the type width, which incurs undefined
-    // behavior, but the conversion itself is undefined in that case, so
-    // whatever the compiler decides to do is fine.
-    else {
-        return sign * (significand << (exponent - significandBits));
-    }
+    return __fixint(a);
 }
index 6a1a1c6..3a159b3 100644 (file)
@@ -6,40 +6,21 @@
  * Source Licenses. See LICENSE.TXT for details.
  *
  * ===----------------------------------------------------------------------===
- *
- * This file implements __fixsfti for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
  */
 
 #include "int_lib.h"
 
 #ifdef CRT_HAS_128BIT
+#define SINGLE_PRECISION
+#include "fp_lib.h"
 
-/* Returns: convert a to a signed long long, rounding toward zero. */
-
-/* Assumption: float is a IEEE 32 bit floating point type 
- *             su_int is a 32 bit integral type
- *             value in float is representable in ti_int (no range checking performed)
- */
-
-/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
+typedef ti_int fixint_t;
+typedef tu_int fixuint_t;
+#include "fp_fixint_impl.inc"
 
 COMPILER_RT_ABI ti_int
-__fixsfti(float a)
-{
-    float_bits fb;
-    fb.f = a;
-    int e = ((fb.u & 0x7F800000) >> 23) - 127;
-    if (e < 0)
-        return 0;
-    ti_int s = (si_int)(fb.u & 0x80000000) >> 31;
-    ti_int r = (fb.u & 0x007FFFFF) | 0x00800000;
-    if (e > 23)
-        r <<= (e - 23);
-    else
-        r >>= (23 - e);
-    return (r ^ s) - s;
+__fixsfti(fp_t a) {
+    return __fixint(a);
 }
 
 #endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/fixtfdi.c b/compiler-rt/lib/builtins/fixtfdi.c
new file mode 100644 (file)
index 0000000..dd3ec00
--- /dev/null
@@ -0,0 +1,23 @@
+/* ===-- fixtfdi.c - Implement __fixtfdi -----------------------------------===
+ *
+ *                     The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+typedef di_int fixint_t;
+typedef du_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
+COMPILER_RT_ABI di_int
+__fixtfdi(fp_t a) {
+    return __fixint(a);
+}
+#endif
diff --git a/compiler-rt/lib/builtins/fixtfsi.c b/compiler-rt/lib/builtins/fixtfsi.c
new file mode 100644 (file)
index 0000000..91b9630
--- /dev/null
@@ -0,0 +1,23 @@
+/* ===-- fixtfsi.c - Implement __fixtfsi -----------------------------------===
+ *
+ *                     The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+typedef si_int fixint_t;
+typedef su_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
+COMPILER_RT_ABI si_int
+__fixtfsi(fp_t a) {
+    return __fixint(a);
+}
+#endif
diff --git a/compiler-rt/lib/builtins/fixtfti.c b/compiler-rt/lib/builtins/fixtfti.c
new file mode 100644 (file)
index 0000000..41a5638
--- /dev/null
@@ -0,0 +1,23 @@
+/* ===-- fixtfti.c - Implement __fixtfti -----------------------------------===
+ *
+ *                     The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+typedef ti_int fixint_t;
+typedef tu_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
+COMPILER_RT_ABI ti_int
+__fixtfti(fp_t a) {
+    return __fixint(a);
+}
+#endif
index 9e63713..f4f689e 100644 (file)
@@ -6,42 +6,16 @@
  * Source Licenses. See LICENSE.TXT for details.
  *
  * ===----------------------------------------------------------------------===
- *
- * This file implements __fixunsdfdi for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-/* Returns: convert a to a unsigned long long, rounding toward zero.
- *          Negative values all become zero.
- */
-
-/* Assumption: double is a IEEE 64 bit floating point type 
- *             du_int is a 64 bit integral type
- *             value in double is representable in du_int or is negative 
- *                 (no range checking performed)
  */
 
-/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+typedef du_int fixuint_t;
+#include "fp_fixuint_impl.inc"
 
 ARM_EABI_FNALIAS(d2ulz, fixunsdfdi)
 
 COMPILER_RT_ABI du_int
-__fixunsdfdi(double a)
-{
-    double_bits fb;
-    fb.f = a;
-    int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023;
-    if (e < 0 || (fb.u.s.high & 0x80000000))
-        return 0;
-    udwords r;
-    r.s.high = (fb.u.s.high & 0x000FFFFF) | 0x00100000;
-    r.s.low = fb.u.s.low;
-    if (e > 52)
-        r.all <<= (e - 52);
-    else
-        r.all >>= (52 - e);
-    return r.all;
+__fixunsdfdi(fp_t a) {
+    return __fixuint(a);
 }
index c6a3c75..232d342 100644 (file)
@@ -6,39 +6,16 @@
  * Source Licenses. See LICENSE.TXT for details.
  *
  * ===----------------------------------------------------------------------===
- *
- * This file implements __fixunsdfsi for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-/* Returns: convert a to a unsigned int, rounding toward zero.
- *          Negative values all become zero.
- */
-
-/* Assumption: double is a IEEE 64 bit floating point type 
- *             su_int is a 32 bit integral type
- *             value in double is representable in su_int or is negative 
- *                 (no range checking performed)
  */
 
-/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+typedef su_int fixuint_t;
+#include "fp_fixuint_impl.inc"
 
 ARM_EABI_FNALIAS(d2uiz, fixunsdfsi)
 
 COMPILER_RT_ABI su_int
-__fixunsdfsi(double a)
-{
-    double_bits fb;
-    fb.f = a;
-    int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023;
-    if (e < 0 || (fb.u.s.high & 0x80000000))
-        return 0;
-    return (
-                0x80000000u                      |
-                ((fb.u.s.high & 0x000FFFFF) << 11) |
-                (fb.u.s.low >> 21)
-           ) >> (31 - e);
+__fixunsdfsi(fp_t a) {
+    return __fixuint(a);
 }
index cc6c84f..c3d7df9 100644 (file)
@@ -6,42 +6,18 @@
  * Source Licenses. See LICENSE.TXT for details.
  *
  * ===----------------------------------------------------------------------===
- *
- * This file implements __fixunsdfti for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
  */
 
 #include "int_lib.h"
 
 #ifdef CRT_HAS_128BIT
-
-/* Returns: convert a to a unsigned long long, rounding toward zero.
- *          Negative values all become zero.
- */
-
-/* Assumption: double is a IEEE 64 bit floating point type 
- *             tu_int is a 64 bit integral type
- *             value in double is representable in tu_int or is negative 
- *                 (no range checking performed)
- */
-
-/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+typedef tu_int fixuint_t;
+#include "fp_fixuint_impl.inc"
 
 COMPILER_RT_ABI tu_int
-__fixunsdfti(double a)
-{
-    double_bits fb;
-    fb.f = a;
-    int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023;
-    if (e < 0 || (fb.u.s.high & 0x80000000))
-        return 0;
-    tu_int r = 0x0010000000000000uLL | (fb.u.all & 0x000FFFFFFFFFFFFFuLL);
-    if (e > 52)
-        r <<= (e - 52);
-    else
-        r >>= (52 - e);
-    return r;
+__fixunsdftti(fp_t a) {
+    return __fixuint(a);
 }
-
 #endif /* CRT_HAS_128BIT */
index 69d5952..cd21cfd 100644 (file)
@@ -6,39 +6,16 @@
  * Source Licenses. See LICENSE.TXT for details.
  *
  * ===----------------------------------------------------------------------===
- *
- * This file implements __fixunssfdi for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-/* Returns: convert a to a unsigned long long, rounding toward zero.
- *          Negative values all become zero.
- */
-
-/* Assumption: float is a IEEE 32 bit floating point type 
- *             du_int is a 64 bit integral type
- *             value in float is representable in du_int or is negative 
- *                 (no range checking performed)
  */
 
-/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
+#define SINGLE_PRECISION
+#include "fp_lib.h"
+typedef du_int fixuint_t;
+#include "fp_fixuint_impl.inc"
 
 ARM_EABI_FNALIAS(f2ulz, fixunssfdi)
 
 COMPILER_RT_ABI du_int
-__fixunssfdi(float a)
-{
-    float_bits fb;
-    fb.f = a;
-    int e = ((fb.u & 0x7F800000) >> 23) - 127;
-    if (e < 0 || (fb.u & 0x80000000))
-        return 0;
-    du_int r = (fb.u & 0x007FFFFF) | 0x00800000;
-    if (e > 23)
-        r <<= (e - 23);
-    else
-        r >>= (23 - e);
-    return r;
+__fixunssfdi(fp_t a) {
+    return __fixuint(a);
 }
index e034139..cc2b05b 100644 (file)
  * ===----------------------------------------------------------------------===
  */
 
-#include "int_lib.h"
-
-/* Returns: convert a to a unsigned int, rounding toward zero.
- *          Negative values all become zero.
- */
-
-/* Assumption: float is a IEEE 32 bit floating point type 
- *             su_int is a 32 bit integral type
- *             value in float is representable in su_int or is negative 
- *                 (no range checking performed)
- */
-
-/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
+#define SINGLE_PRECISION
+#include "fp_lib.h"
+typedef su_int fixuint_t;
+#include "fp_fixuint_impl.inc"
 
 ARM_EABI_FNALIAS(f2uiz, fixunssfsi)
 
 COMPILER_RT_ABI su_int
-__fixunssfsi(float a)
-{
-    float_bits fb;
-    fb.f = a;
-    int e = ((fb.u & 0x7F800000) >> 23) - 127;
-    if (e < 0 || (fb.u & 0x80000000))
-        return 0;
-    su_int r = (fb.u & 0x007FFFFF) | 0x00800000;
-    if (e > 23)
-        r <<= (e - 23);
-    else
-        r >>= (23 - e);
-    return r;
+__fixunssfsi(fp_t a) {
+    return __fixuint(a);
 }
index 4da9e24..9593153 100644 (file)
  * ===----------------------------------------------------------------------===
  */
 
-#include "int_lib.h"
-
-#ifdef CRT_HAS_128BIT
-
-/* Returns: convert a to a unsigned long long, rounding toward zero.
- *          Negative values all become zero.
- */
-
-/* Assumption: float is a IEEE 32 bit floating point type 
- *             tu_int is a 64 bit integral type
- *             value in float is representable in tu_int or is negative 
- *                 (no range checking performed)
- */
-
-/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
+#if defined(CRT_HAS_128BIT)
+typedef tu_int fixuint_t;
+#include "fp_fixuint_impl.inc"
 
 COMPILER_RT_ABI tu_int
-__fixunssfti(float a)
-{
-    float_bits fb;
-    fb.f = a;
-    int e = ((fb.u & 0x7F800000) >> 23) - 127;
-    if (e < 0 || (fb.u & 0x80000000))
-        return 0;
-    tu_int r = (fb.u & 0x007FFFFF) | 0x00800000;
-    if (e > 23)
-        r <<= (e - 23);
-    else
-        r >>= (23 - e);
-    return r;
+__fixunssfti(fp_t a) {
+    return __fixuint(a);
 }
-
-#endif /* CRT_HAS_128BIT */
+#endif
diff --git a/compiler-rt/lib/builtins/fixunstfdi.c b/compiler-rt/lib/builtins/fixunstfdi.c
new file mode 100644 (file)
index 0000000..b2995f6
--- /dev/null
@@ -0,0 +1,22 @@
+/* ===-- fixunstfdi.c - Implement __fixunstfdi -----------------------------===
+ *
+ *                     The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+typedef du_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
+COMPILER_RT_ABI du_int
+__fixunstfdi(fp_t a) {
+    return __fixuint(a);
+}
+#endif
diff --git a/compiler-rt/lib/builtins/fixunstfsi.c b/compiler-rt/lib/builtins/fixunstfsi.c
new file mode 100644 (file)
index 0000000..b5d3f6a
--- /dev/null
@@ -0,0 +1,22 @@
+/* ===-- fixunstfsi.c - Implement __fixunstfsi -----------------------------===
+ *
+ *                     The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+typedef su_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
+COMPILER_RT_ABI su_int
+__fixunstfsi(fp_t a) {
+    return __fixuint(a);
+}
+#endif
diff --git a/compiler-rt/lib/builtins/fixunstfti.c b/compiler-rt/lib/builtins/fixunstfti.c
new file mode 100644 (file)
index 0000000..22ff9df
--- /dev/null
@@ -0,0 +1,22 @@
+/* ===-- fixunstfsi.c - Implement __fixunstfsi -----------------------------===
+ *
+ *                     The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+typedef tu_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
+COMPILER_RT_ABI tu_int
+__fixunstfti(fp_t a) {
+    return __fixuint(a);
+}
+#endif
index 7224d46..075304e 100644 (file)
@@ -38,6 +38,8 @@ __fixunsxfdi(long double a)
     int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
     if (e < 0 || (fb.u.high.s.low & 0x00008000))
         return 0;
+    if ((unsigned)e > sizeof(du_int) * CHAR_BIT)
+        return ~(du_int)0;
     return fb.u.low.all >> (63 - e);
 }
 
index df0a18e..c3c70f7 100644 (file)
@@ -23,7 +23,6 @@
 /* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
  *             su_int is a 32 bit integral type
  *             value in long double is representable in su_int or is negative 
- *                 (no range checking performed)
  */
 
 /* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
@@ -38,6 +37,8 @@ __fixunsxfsi(long double a)
     int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
     if (e < 0 || (fb.u.high.s.low & 0x00008000))
         return 0;
+    if ((unsigned)e > sizeof(su_int) * CHAR_BIT)
+        return ~(su_int)0;
     return fb.u.low.s.high >> (31 - e);
 }
 
index 42e5073..fb39d00 100644 (file)
@@ -21,9 +21,8 @@
  */
 
 /* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
- *             tu_int is a 64 bit integral type
+ *             tu_int is a 128 bit integral type
  *             value in long double is representable in tu_int or is negative 
- *                 (no range checking performed)
  */
 
 /* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
@@ -38,6 +37,8 @@ __fixunsxfti(long double a)
     int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
     if (e < 0 || (fb.u.high.s.low & 0x00008000))
         return 0;
+    if ((unsigned)e > sizeof(tu_int) * CHAR_BIT)
+        return ~(tu_int)0;
     tu_int r = fb.u.low.all;
     if (e > 63)
         r <<= (e - 63);
index afc79d8..011787f 100644 (file)
@@ -19,7 +19,7 @@
 /* Returns: convert a to a signed long long, rounding toward zero. */
 
 /* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
- *             su_int is a 32 bit integral type
+ *             di_int is a 64 bit integral type
  *             value in long double is representable in di_int (no range checking performed)
  */
 
 COMPILER_RT_ABI di_int
 __fixxfdi(long double a)
 {
+    const di_int di_max = (di_int)((~(du_int)0) / 2);
+    const di_int di_min = -di_max - 1;
     long_double_bits fb;
     fb.f = a;
     int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
     if (e < 0)
         return 0;
+    if ((unsigned)e >= sizeof(di_int) * CHAR_BIT)
+        return a > 0 ? di_max : di_min;
     di_int s = -(si_int)((fb.u.high.s.low & 0x00008000) >> 15);
     di_int r = fb.u.low.all;
     r = (du_int)r >> (63 - e);
index 3d0a279..968a4f0 100644 (file)
@@ -19,8 +19,8 @@
 /* Returns: convert a to a signed long long, rounding toward zero. */
 
 /* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
- *             su_int is a 32 bit integral type
- *             value in long double is representable in ti_int (no range checking performed)
+ *             ti_int is a 128 bit integral type
+ *             value in long double is representable in ti_int
  */
 
 /* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
@@ -30,6 +30,8 @@
 COMPILER_RT_ABI ti_int
 __fixxfti(long double a)
 {
+    const ti_int ti_max = (ti_int)((~(tu_int)0) / 2);
+    const ti_int ti_min = -ti_max - 1;
     long_double_bits fb;
     fb.f = a;
     int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
@@ -37,6 +39,8 @@ __fixxfti(long double a)
         return 0;
     ti_int s = -(si_int)((fb.u.high.s.low & 0x00008000) >> 15);
     ti_int r = fb.u.low.all;
+    if ((unsigned)e >= sizeof(ti_int) * CHAR_BIT)
+        return a > 0 ? ti_max : ti_min;
     if (e > 63)
         r <<= (e - 63);
     else
diff --git a/compiler-rt/lib/builtins/fp_fixint_impl.inc b/compiler-rt/lib/builtins/fp_fixint_impl.inc
new file mode 100644 (file)
index 0000000..035e87c
--- /dev/null
@@ -0,0 +1,41 @@
+//===-- lib/fixdfsi.c - Double-precision -> integer conversion ----*- C -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements float to integer conversion for the
+// compiler-rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "fp_lib.h"
+
+static inline fixint_t __fixint(fp_t a) {
+    const fixint_t fixint_max = (fixint_t)((~(fixuint_t)0) / 2);
+    const fixint_t fixint_min = -fixint_max - 1;
+    // Break a into sign, exponent, significand
+    const rep_t aRep = toRep(a);
+    const rep_t aAbs = aRep & absMask;
+    const fixint_t sign = aRep & signBit ? -1 : 1;
+    const int exponent = (aAbs >> significandBits) - exponentBias;
+    const rep_t significand = (aAbs & significandMask) | implicitBit;
+
+    // If exponent is negative, the result is zero.
+    if (exponent < 0)
+        return 0;
+
+    // If the value is too large for the integer type, saturate.
+    if ((unsigned)exponent >= sizeof(fixint_t) * CHAR_BIT)
+        return sign == 1 ? fixint_max : fixint_min;
+
+    // If 0 <= exponent < significandBits, right shift to get the result.
+    // Otherwise, shift left.
+    if (exponent < significandBits)
+        return sign * (significand >> (significandBits - exponent));
+    else
+        return sign * ((fixint_t)significand << (exponent - significandBits));
+}
diff --git a/compiler-rt/lib/builtins/fp_fixuint_impl.inc b/compiler-rt/lib/builtins/fp_fixuint_impl.inc
new file mode 100644 (file)
index 0000000..5fefab0
--- /dev/null
@@ -0,0 +1,39 @@
+//===-- lib/fixdfsi.c - Double-precision -> integer conversion ----*- C -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements float to unsigned integer conversion for the
+// compiler-rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "fp_lib.h"
+
+static inline fixuint_t __fixuint(fp_t a) {
+    // Break a into sign, exponent, significand
+    const rep_t aRep = toRep(a);
+    const rep_t aAbs = aRep & absMask;
+    const int sign = aRep & signBit ? -1 : 1;
+    const int exponent = (aAbs >> significandBits) - exponentBias;
+    const rep_t significand = (aAbs & significandMask) | implicitBit;
+
+    // If either the value or the exponent is negative, the result is zero.
+    if (sign == -1 || exponent < 0)
+        return 0;
+
+    // If the value is too large for the integer type, saturate.
+    if ((unsigned)exponent > sizeof(fixuint_t) * CHAR_BIT)
+        return ~(fixuint_t)0;
+
+    // If 0 <= exponent < significandBits, right shift to get the result.
+    // Otherwise, shift left.
+    if (exponent < significandBits)
+        return significand >> (significandBits - exponent);
+    else
+        return (fixuint_t)significand << (exponent - significandBits);
+}
diff --git a/compiler-rt/test/builtins/Unit/fixtfsi_test.c b/compiler-rt/test/builtins/Unit/fixtfsi_test.c
new file mode 100644 (file)
index 0000000..45ad0d2
--- /dev/null
@@ -0,0 +1,65 @@
+//===--------------- fixtfsi_test.c - Test __fixtfsi ----------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file tests __fixtfsi for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+#if __LDBL_MANT_DIG__ == 113
+
+#include "fp_test.h"
+
+int __fixtfsi(long double a);
+
+int test__fixtfsi(long double a, int expected)
+{
+    int x = __fixtfsi(a);
+    int ret = (x != expected);
+
+    if (ret){
+        printf("error in test__fixtfsi(%.20Lf) = %d, "
+               "expected %d\n", a, x, expected);
+    }
+    return ret;
+}
+
+char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0};
+
+#endif
+
+int main()
+{
+#if __LDBL_MANT_DIG__ == 113
+    if (test__fixtfsi(makeInf128(), 0x7fffffff))
+        return 1;
+    if (test__fixtfsi(0, 0x0))
+        return 1;
+    if (test__fixtfsi(0x1.23456789abcdefp+5, 0x24))
+        return 1;
+    if (test__fixtfsi(0x1.23456789abcdefp-3, 0x0))
+        return 1;
+    if (test__fixtfsi(0x1.23456789abcdefp+20, 0x123456))
+        return 1;
+    if (test__fixtfsi(0x1.23456789abcdefp+40, 0x7fffffff))
+        return 1;
+    if (test__fixtfsi(0x1.23456789abcdefp+256, 0x7fffffff))
+        return 1;
+    if (test__fixtfsi(-0x1.23456789abcdefp+20, 0xffedcbaa))
+        return 1;
+    if (test__fixtfsi(-0x1.23456789abcdefp+40, 0x80000001))
+        return 1;
+
+#else
+    printf("skipped\n");
+
+#endif
+    return 0;
+}
diff --git a/compiler-rt/test/builtins/Unit/fixunstfsi_test.c b/compiler-rt/test/builtins/Unit/fixunstfsi_test.c
new file mode 100644 (file)
index 0000000..4bf8fde
--- /dev/null
@@ -0,0 +1,64 @@
+//===--------------- fixunstfsi_test.c - Test __fixunstfsi ----------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file tests __fixunstfsi for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+#if __LDBL_MANT_DIG__ == 113
+
+#include "fp_test.h"
+
+unsigned int __fixunstfsi(long double a);
+
+int test__fixunstfsi(long double a, unsigned int expected)
+{
+    unsigned int x = __fixunstfsi(a);
+    int ret = (x != expected);
+
+    if (ret)
+    {
+        printf("error in test__fixunstfsi(%.20Lf) = %u, "
+               "expected %u\n", a, x, expected);
+    }
+    return ret;
+}
+
+char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0};
+
+#endif
+
+int main()
+{
+#if __LDBL_MANT_DIG__ == 113
+    if (test__fixunstfsi(makeInf128(), UINT32_C(0xffffffff)))
+        return 1;
+    if (test__fixunstfsi(0, UINT32_C(0x0)))
+        return 1;
+    if (test__fixunstfsi(0x1.23456789abcdefp+5, UINT32_C(0x24)))
+        return 1;
+    if (test__fixunstfsi(0x1.23456789abcdefp-3, UINT32_C(0x0)))
+        return 1;
+    if (test__fixunstfsi(0x1.23456789abcdefp+20, UINT32_C(0x123456)))
+        return 1;
+    if (test__fixunstfsi(0x1.23456789abcdefp+40, UINT32_C(0xffffffff)))
+        return 1;
+    if (test__fixunstfsi(0x1.23456789abcdefp+256, UINT32_C(0xffffffff)))
+        return 1;
+    if (test__fixunstfsi(-0x1.23456789abcdefp+3, UINT32_C(0x0)))
+        return 1;
+
+#else
+    printf("skipped\n");
+
+#endif
+    return 0;
+}