Bug 531915 - part 3 - add back needed rounding helpers and emulate freebsd internal double types ?tjr r=arai

Differential Revision: https://phabricator.services.mozilla.com/D119423
This commit is contained in:
sanketh 2021-08-12 09:59:02 +00:00
Родитель 474a039e5c
Коммит 8dc9e8a52f
3 изменённых файлов: 114 добавлений и 54 удалений

Просмотреть файл

@ -1,46 +1,15 @@
diff --git a/modules/fdlibm/src/math_private.h b/modules/fdlibm/src/math_private.h
--- a/modules/fdlibm/src/math_private.h
+++ b/modules/fdlibm/src/math_private.h
@@ -586,126 +586,16 @@ CMPLXL(long double x, long double y)
REALPART(z) = x;
IMAGPART(z) = y;
return (z.f);
@@ -617,95 +617,32 @@ rnint(double x)
* magic number would need to be variable. Assuming that the
* rounding precision is always the default is too fragile. This
* and many other complications will move when the default is
* changed to FP_PE.
*/
return ((double)(x + 0x1.8p52) - 0x1.8p52);
}
#endif
#endif /* _COMPLEX_H */
-/*
- * The rnint() family rounds to the nearest integer for a restricted range
- * range of args (up to about 2**MANT_DIG). We assume that the current
- * rounding mode is FE_TONEAREST so that this can be done efficiently.
- * Extra precision causes more problems in practice, and we only centralize
- * this here to reduce those problems, and have not solved the efficiency
- * problems. The exp2() family uses a more delicate version of this that
- * requires extracting bits from the intermediate value, so it is not
- * centralized here and should copy any solution of the efficiency problems.
- */
-
-static inline double
-rnint(__double_t x)
-{
- /*
- * This casts to double to kill any extra precision. This depends
- * on the cast being applied to a double_t to avoid compiler bugs
- * (this is a cleaner version of STRICT_ASSIGN()). This is
- * inefficient if there actually is extra precision, but is hard
- * to improve on. We use double_t in the API to minimise conversions
- * for just calling here. Note that we cannot easily change the
- * magic number to the one that works directly with double_t, since
- * the rounding precision is variable at runtime on x86 so the
- * magic number would need to be variable. Assuming that the
- * rounding precision is always the default is too fragile. This
- * and many other complications will move when the default is
- * changed to FP_PE.
- */
- return ((double)(x + 0x1.8p52) - 0x1.8p52);
-}
-
-static inline float
-rnintf(__float_t x)
-{
@ -71,22 +40,22 @@ diff --git a/modules/fdlibm/src/math_private.h b/modules/fdlibm/src/math_private
-}
-#endif /* LDBL_MANT_DIG */
-
-/*
- * irint() and i64rint() give the same result as casting to their integer
- * return type provided their arg is a floating point integer. They can
- * sometimes be more efficient because no rounding is required.
- */
-#if (defined(amd64) || defined(__i386__)) && defined(__GNUCLIKE_ASM)
-#define irint(x) \
- (sizeof(x) == sizeof(float) && \
- sizeof(__float_t) == sizeof(long double) ? irintf(x) : \
- sizeof(x) == sizeof(double) && \
- sizeof(__double_t) == sizeof(long double) ? irintd(x) : \
- sizeof(x) == sizeof(long double) ? irintl(x) : (int)(x))
-#else
-#define irint(x) ((int)(x))
-#endif
-
/*
* irint() and i64rint() give the same result as casting to their integer
* return type provided their arg is a floating point integer. They can
* sometimes be more efficient because no rounding is required.
*/
#if (defined(amd64) || defined(__i386__)) && defined(__GNUCLIKE_ASM)
#define irint(x) \
(sizeof(x) == sizeof(float) && \
sizeof(__float_t) == sizeof(long double) ? irintf(x) : \
sizeof(x) == sizeof(double) && \
sizeof(__double_t) == sizeof(long double) ? irintd(x) : \
sizeof(x) == sizeof(long double) ? irintl(x) : (int)(x))
#else
#define irint(x) ((int)(x))
#endif
-#define i64rint(x) ((int64_t)(x)) /* only needed for ld128 so not opt. */
-
-#if defined(__i386__) && defined(__GNUCLIKE_ASM)

Просмотреть файл

@ -0,0 +1,32 @@
diff --git a/modules/fdlibm/src/math_private.h b/modules/fdlibm/src/math_private.h
--- a/modules/fdlibm/src/math_private.h
+++ b/modules/fdlibm/src/math_private.h
@@ -21,16 +21,28 @@
#include <stdint.h>
#include <sys/types.h>
#include "fdlibm.h"
#include "mozilla/EndianUtils.h"
/*
+ * Emulate FreeBSD internal double types.
+ * Adapted from https://github.com/freebsd/freebsd-src/search?q=__double_t
+ */
+
+#if defined(__i386__)
+typedef long double __double_t;
+#else
+typedef double __double_t;
+#endif
+typedef __double_t double_t;
+
+/*
* The original fdlibm code used statements like:
* n0 = ((*(int*)&one)>>29)^1; * index of high word *
* ix0 = *(n0+(int*)&x); * high word of x *
* ix1 = *((1-n0)+(int*)&x); * low word of x *
* to dig two 32 bit words out of the 64 bit IEEE floating point
* value. That is non-ANSI, and, moreover, the gcc instruction
* scheduler gets it wrong. We instead use the following macros.
* Unlike the original code, we determine the endianness at compile

Просмотреть файл

@ -25,6 +25,18 @@
#include "mozilla/EndianUtils.h"
/*
* Emulate FreeBSD internal double types.
* Adapted from https://github.com/freebsd/freebsd-src/search?q=__double_t
*/
#if defined(__i386__)
typedef long double __double_t;
#else
typedef double __double_t;
#endif
typedef __double_t double_t;
/*
* The original fdlibm code used statements like:
* n0 = ((*(int*)&one)>>29)^1; * index of high word *
@ -591,6 +603,53 @@ CMPLXL(long double x, long double y)
#endif /* _COMPLEX_H */
/*
* The rnint() family rounds to the nearest integer for a restricted range
* range of args (up to about 2**MANT_DIG). We assume that the current
* rounding mode is FE_TONEAREST so that this can be done efficiently.
* Extra precision causes more problems in practice, and we only centralize
* this here to reduce those problems, and have not solved the efficiency
* problems. The exp2() family uses a more delicate version of this that
* requires extracting bits from the intermediate value, so it is not
* centralized here and should copy any solution of the efficiency problems.
*/
static inline double
rnint(__double_t x)
{
/*
* This casts to double to kill any extra precision. This depends
* on the cast being applied to a double_t to avoid compiler bugs
* (this is a cleaner version of STRICT_ASSIGN()). This is
* inefficient if there actually is extra precision, but is hard
* to improve on. We use double_t in the API to minimise conversions
* for just calling here. Note that we cannot easily change the
* magic number to the one that works directly with double_t, since
* the rounding precision is variable at runtime on x86 so the
* magic number would need to be variable. Assuming that the
* rounding precision is always the default is too fragile. This
* and many other complications will move when the default is
* changed to FP_PE.
*/
return ((double)(x + 0x1.8p52) - 0x1.8p52);
}
/*
* irint() and i64rint() give the same result as casting to their integer
* return type provided their arg is a floating point integer. They can
* sometimes be more efficient because no rounding is required.
*/
#if (defined(amd64) || defined(__i386__)) && defined(__GNUCLIKE_ASM)
#define irint(x) \
(sizeof(x) == sizeof(float) && \
sizeof(__float_t) == sizeof(long double) ? irintf(x) : \
sizeof(x) == sizeof(double) && \
sizeof(__double_t) == sizeof(long double) ? irintd(x) : \
sizeof(x) == sizeof(long double) ? irintl(x) : (int)(x))
#else
#define irint(x) ((int)(x))
#endif
#ifdef DEBUG
#if defined(__amd64__) || defined(__i386__)
#define breakpoint() asm("int $3")