aboutsummaryrefslogtreecommitdiffstats
path: root/fpu
diff options
context:
space:
mode:
authorDavid 'Digit' Turner <digit@google.com>2009-09-14 14:32:27 -0700
committerDavid 'Digit' Turner <digit@google.com>2009-09-14 14:32:27 -0700
commit5d8f37ad78fc66901af50c762029a501561f3b23 (patch)
tree206790f8f21000850a98c4f9590a79e779106278 /fpu
parentcd059b15f2c7df69f4a087bd66900eb172e41d1c (diff)
downloadexternal_qemu-5d8f37ad78fc66901af50c762029a501561f3b23.zip
external_qemu-5d8f37ad78fc66901af50c762029a501561f3b23.tar.gz
external_qemu-5d8f37ad78fc66901af50c762029a501561f3b23.tar.bz2
Merge upstream QEMU 10.0.50 into the Android source tree.
This change integrates many changes from the upstream QEMU sources. Its main purpose is to enable correct ARMv6 and ARMv7 support to the Android emulator. Due to the nature of the upstream code base, this unfortunately also required changes to many other parts of the source. Note that to ensure easier integrations in the future, some source files and directories that have heavy Android-specific customization have been renamed with an -android suffix. The original files are still there for easier integration tracking, but *never* compiled. For example: net.c net-android.c qemu-char.c qemu-char-android.c slirp/ slirp-android/ etc... Tested on linux-x86, darwin-x86 and windows host machines.
Diffstat (limited to 'fpu')
-rw-r--r--fpu/softfloat-macros.h5
-rw-r--r--fpu/softfloat-native.c84
-rw-r--r--fpu/softfloat-native.h85
-rw-r--r--fpu/softfloat-specialize.h36
-rw-r--r--fpu/softfloat.c153
-rw-r--r--fpu/softfloat.h78
6 files changed, 377 insertions, 64 deletions
diff --git a/fpu/softfloat-macros.h b/fpu/softfloat-macros.h
index 2c8f18b..7838228 100644
--- a/fpu/softfloat-macros.h
+++ b/fpu/softfloat-macros.h
@@ -590,12 +590,12 @@ static bits32 estimateSqrt32( int16 aExp, bits32 a )
index = ( a>>27 ) & 15;
if ( aExp & 1 ) {
- z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ index ];
+ z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ (int)index ];
z = ( ( a / z )<<14 ) + ( z<<15 );
a >>= 1;
}
else {
- z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ index ];
+ z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ (int)index ];
z = a / z + z;
z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 );
if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 );
@@ -717,4 +717,3 @@ INLINE flag ne128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
return ( a0 != b0 ) || ( a1 != b1 );
}
-
diff --git a/fpu/softfloat-native.c b/fpu/softfloat-native.c
index e58551f..2af07a3 100644
--- a/fpu/softfloat-native.c
+++ b/fpu/softfloat-native.c
@@ -2,11 +2,15 @@
context is supported */
#include "softfloat.h"
#include <math.h>
+#if defined(HOST_SOLARIS)
+#include <fenv.h>
+#endif
void set_float_rounding_mode(int val STATUS_PARAM)
{
STATUS(float_rounding_mode) = val;
-#if defined(_BSD) && !defined(__APPLE__) || (defined(HOST_SOLARIS) && HOST_SOLARIS < 10)
+#if defined(HOST_BSD) && !defined(__APPLE__) || \
+ (defined(HOST_SOLARIS) && HOST_SOLARIS < 10)
fpsetround(val);
#elif defined(__arm__)
/* nothing to do */
@@ -22,7 +26,7 @@ void set_floatx80_rounding_precision(int val STATUS_PARAM)
}
#endif
-#if defined(_BSD) || (defined(HOST_SOLARIS) && HOST_SOLARIS < 10)
+#if defined(HOST_BSD) || (defined(HOST_SOLARIS) && HOST_SOLARIS < 10)
#define lrint(d) ((int32_t)rint(d))
#define llrint(d) ((int64_t)rint(d))
#define lrintf(f) ((int32_t)rint(f))
@@ -51,10 +55,10 @@ ldexpl(long double x, int n) {
#endif
#endif
-#if defined(__powerpc__)
+#if defined(_ARCH_PPC)
/* correct (but slow) PowerPC rint() (glibc version is incorrect) */
-double qemu_rint(double x)
+static double qemu_rint(double x)
{
double y = 4503599627370496.0;
if (fabs(x) >= y)
@@ -220,25 +224,25 @@ float32 float32_sqrt( float32 a STATUS_PARAM)
int float32_compare( float32 a, float32 b STATUS_PARAM )
{
if (a < b) {
- return -1;
+ return float_relation_less;
} else if (a == b) {
- return 0;
+ return float_relation_equal;
} else if (a > b) {
- return 1;
+ return float_relation_greater;
} else {
- return 2;
+ return float_relation_unordered;
}
}
int float32_compare_quiet( float32 a, float32 b STATUS_PARAM )
{
if (isless(a, b)) {
- return -1;
+ return float_relation_less;
} else if (a == b) {
- return 0;
+ return float_relation_equal;
} else if (isgreater(a, b)) {
- return 1;
+ return float_relation_greater;
} else {
- return 2;
+ return float_relation_unordered;
}
}
int float32_is_signaling_nan( float32 a1)
@@ -250,6 +254,15 @@ int float32_is_signaling_nan( float32 a1)
return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
}
+int float32_is_nan( float32 a1 )
+{
+ float32u u;
+ uint64_t a;
+ u.f = a1;
+ a = u.i;
+ return ( 0xFF800000 < ( a<<1 ) );
+}
+
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision conversion routines.
*----------------------------------------------------------------------------*/
@@ -382,25 +395,25 @@ float64 float64_sqrt( float64 a STATUS_PARAM)
int float64_compare( float64 a, float64 b STATUS_PARAM )
{
if (a < b) {
- return -1;
+ return float_relation_less;
} else if (a == b) {
- return 0;
+ return float_relation_equal;
} else if (a > b) {
- return 1;
+ return float_relation_greater;
} else {
- return 2;
+ return float_relation_unordered;
}
}
int float64_compare_quiet( float64 a, float64 b STATUS_PARAM )
{
if (isless(a, b)) {
- return -1;
+ return float_relation_less;
} else if (a == b) {
- return 0;
+ return float_relation_equal;
} else if (isgreater(a, b)) {
- return 1;
+ return float_relation_greater;
} else {
- return 2;
+ return float_relation_unordered;
}
}
int float64_is_signaling_nan( float64 a1)
@@ -422,7 +435,7 @@ int float64_is_nan( float64 a1 )
u.f = a1;
a = u.i;
- return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) );
+ return ( LIT64( 0xFFF0000000000000 ) < (bits64) ( a<<1 ) );
}
@@ -474,30 +487,43 @@ floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM)
int floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM )
{
if (a < b) {
- return -1;
+ return float_relation_less;
} else if (a == b) {
- return 0;
+ return float_relation_equal;
} else if (a > b) {
- return 1;
+ return float_relation_greater;
} else {
- return 2;
+ return float_relation_unordered;
}
}
int floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM )
{
if (isless(a, b)) {
- return -1;
+ return float_relation_less;
} else if (a == b) {
- return 0;
+ return float_relation_equal;
} else if (isgreater(a, b)) {
- return 1;
+ return float_relation_greater;
} else {
- return 2;
+ return float_relation_unordered;
}
}
int floatx80_is_signaling_nan( floatx80 a1)
{
floatx80u u;
+ uint64_t aLow;
+ u.f = a1;
+
+ aLow = u.i.low & ~ LIT64( 0x4000000000000000 );
+ return
+ ( ( u.i.high & 0x7FFF ) == 0x7FFF )
+ && (bits64) ( aLow<<1 )
+ && ( u.i.low == aLow );
+}
+
+int floatx80_is_nan( floatx80 a1 )
+{
+ floatx80u u;
u.f = a1;
return ( ( u.i.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( u.i.low<<1 );
}
diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h
index 379d49d..a28c769 100644
--- a/fpu/softfloat-native.h
+++ b/fpu/softfloat-native.h
@@ -1,15 +1,14 @@
/* Native implementation of soft float functions */
#include <math.h>
-#if (defined(_BSD) && !defined(__APPLE__)) || defined(HOST_SOLARIS)
+#if (defined(HOST_BSD) && !defined(__APPLE__)) || defined(HOST_SOLARIS)
#include <ieeefp.h>
#define fabsf(f) ((float)fabs(f))
#else
#include <fenv.h>
#endif
-#ifdef __OpenBSD__
-/* Get OpenBSD version number */
+#if defined(__OpenBSD__) || defined(__NetBSD__)
#include <sys/param.h>
#endif
@@ -21,7 +20,7 @@
* are defined in <iso/math_c99.h> with a compiler directive
*/
#if defined(HOST_SOLARIS) && (( HOST_SOLARIS <= 9 ) || ((HOST_SOLARIS >= 10) \
- && (__GNUC__ <= 4))) \
+ && (__GNUC__ < 4))) \
|| (defined(__OpenBSD__) && (OpenBSD < 200811))
/*
* C99 7.12.3 classification macros
@@ -35,6 +34,25 @@
#define unordered(x, y) (isnan(x) || isnan(y))
#endif
+#ifdef __NetBSD__
+#ifndef isgreater
+#define isgreater(x, y) __builtin_isgreater(x, y)
+#endif
+#ifndef isgreaterequal
+#define isgreaterequal(x, y) __builtin_isgreaterequal(x, y)
+#endif
+#ifndef isless
+#define isless(x, y) __builtin_isless(x, y)
+#endif
+#ifndef islessequal
+#define islessequal(x, y) __builtin_islessequal(x, y)
+#endif
+#ifndef isunordered
+#define isunordered(x, y) __builtin_isunordered(x, y)
+#endif
+#endif
+
+
#define isnormal(x) (fpclass(x) >= FP_NZERO)
#define isgreater(x, y) ((!unordered(x, y)) && ((x) > (y)))
#define isgreaterequal(x, y) ((!unordered(x, y)) && ((x) >= (y)))
@@ -93,7 +111,7 @@ typedef union {
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point rounding mode.
*----------------------------------------------------------------------------*/
-#if (defined(_BSD) && !defined(__APPLE__)) || defined(HOST_SOLARIS)
+#if (defined(HOST_BSD) && !defined(__APPLE__)) || defined(HOST_SOLARIS)
#if defined(__OpenBSD__)
#define FE_RM FP_RM
#define FE_RP FP_RP
@@ -122,9 +140,9 @@ enum {
#endif
typedef struct float_status {
- signed char float_rounding_mode;
+ int float_rounding_mode;
#ifdef FLOATX80
- signed char floatx80_rounding_precision;
+ int floatx80_rounding_precision;
#endif
} float_status;
@@ -228,6 +246,7 @@ INLINE int float32_unordered( float32 a, float32 b STATUS_PARAM)
int float32_compare( float32, float32 STATUS_PARAM );
int float32_compare_quiet( float32, float32 STATUS_PARAM );
int float32_is_signaling_nan( float32 );
+int float32_is_nan( float32 );
INLINE float32 float32_abs(float32 a)
{
@@ -239,6 +258,23 @@ INLINE float32 float32_chs(float32 a)
return -a;
}
+INLINE float32 float32_is_infinity(float32 a)
+{
+ return fpclassify(a) == FP_INFINITE;
+}
+
+INLINE float32 float32_is_neg(float32 a)
+{
+ float32u u;
+ u.f = a;
+ return u.i >> 31;
+}
+
+INLINE float32 float32_is_zero(float32 a)
+{
+ return fpclassify(a) == FP_ZERO;
+}
+
INLINE float32 float32_scalbn(float32 a, int n)
{
return scalbnf(a, n);
@@ -331,6 +367,23 @@ INLINE float64 float64_chs(float64 a)
return -a;
}
+INLINE float64 float64_is_infinity(float64 a)
+{
+ return fpclassify(a) == FP_INFINITE;
+}
+
+INLINE float64 float64_is_neg(float64 a)
+{
+ float64u u;
+ u.f = a;
+ return u.i >> 63;
+}
+
+INLINE float64 float64_is_zero(float64 a)
+{
+ return fpclassify(a) == FP_ZERO;
+}
+
INLINE float64 float64_scalbn(float64 a, int n)
{
return scalbn(a, n);
@@ -406,6 +459,7 @@ INLINE int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM)
int floatx80_compare( floatx80, floatx80 STATUS_PARAM );
int floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM );
int floatx80_is_signaling_nan( floatx80 );
+int floatx80_is_nan( floatx80 );
INLINE floatx80 floatx80_abs(floatx80 a)
{
@@ -417,6 +471,23 @@ INLINE floatx80 floatx80_chs(floatx80 a)
return -a;
}
+INLINE floatx80 floatx80_is_infinity(floatx80 a)
+{
+ return fpclassify(a) == FP_INFINITE;
+}
+
+INLINE floatx80 floatx80_is_neg(floatx80 a)
+{
+ floatx80u u;
+ u.f = a;
+ return u.i.high >> 15;
+}
+
+INLINE floatx80 floatx80_is_zero(floatx80 a)
+{
+ return fpclassify(a) == FP_ZERO;
+}
+
INLINE floatx80 floatx80_scalbn(floatx80 a, int n)
{
return scalbnl(a, n);
diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index 93fe06e..f607e19 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -37,12 +37,6 @@ these four paragraphs for those parts of this code that are retained.
#endif
/*----------------------------------------------------------------------------
-| Underflow tininess-detection mode, statically initialized to default value.
-| (The declaration in `softfloat.h' must match the `int8' type here.)
-*----------------------------------------------------------------------------*/
-int8 float_detect_tininess = float_tininess_after_rounding;
-
-/*----------------------------------------------------------------------------
| Raises the exceptions specified by `flags'. Floating-point traps can be
| defined here if desired. It is currently not possible for such a trap
| to substitute a result value. If traps are not implemented, this routine
@@ -67,7 +61,7 @@ typedef struct {
*----------------------------------------------------------------------------*/
#if defined(TARGET_SPARC)
#define float32_default_nan make_float32(0x7FFFFFFF)
-#elif defined(TARGET_POWERPC)
+#elif defined(TARGET_POWERPC) || defined(TARGET_ARM)
#define float32_default_nan make_float32(0x7FC00000)
#elif defined(TARGET_HPPA)
#define float32_default_nan make_float32(0x7FA00000)
@@ -150,6 +144,9 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
bits32 av, bv, res;
+ if ( STATUS(default_nan_mode) )
+ return float32_default_nan;
+
aIsNaN = float32_is_nan( a );
aIsSignalingNaN = float32_is_signaling_nan( a );
bIsNaN = float32_is_nan( b );
@@ -169,7 +166,7 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
res = bIsNaN ? bv : av;
}
else if ( aIsNaN ) {
- if ( bIsSignalingNaN | ! bIsNaN )
+ if ( bIsSignalingNaN || ! bIsNaN )
res = av;
else {
returnLargerSignificand:
@@ -192,7 +189,7 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
*----------------------------------------------------------------------------*/
#if defined(TARGET_SPARC)
#define float64_default_nan make_float64(LIT64( 0x7FFFFFFFFFFFFFFF ))
-#elif defined(TARGET_POWERPC)
+#elif defined(TARGET_POWERPC) || defined(TARGET_ARM)
#define float64_default_nan make_float64(LIT64( 0x7FF8000000000000 ))
#elif defined(TARGET_HPPA)
#define float64_default_nan make_float64(LIT64( 0x7FF4000000000000 ))
@@ -282,6 +279,9 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
bits64 av, bv, res;
+ if ( STATUS(default_nan_mode) )
+ return float64_default_nan;
+
aIsNaN = float64_is_nan( a );
aIsSignalingNaN = float64_is_signaling_nan( a );
bIsNaN = float64_is_nan( b );
@@ -301,7 +301,7 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
res = bIsNaN ? bv : av;
}
else if ( aIsNaN ) {
- if ( bIsSignalingNaN | ! bIsNaN )
+ if ( bIsSignalingNaN || ! bIsNaN )
res = av;
else {
returnLargerSignificand:
@@ -418,6 +418,12 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
{
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+ if ( STATUS(default_nan_mode) ) {
+ a.low = floatx80_default_nan_low;
+ a.high = floatx80_default_nan_high;
+ return a;
+ }
+
aIsNaN = floatx80_is_nan( a );
aIsSignalingNaN = floatx80_is_signaling_nan( a );
bIsNaN = floatx80_is_nan( b );
@@ -435,7 +441,7 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
return bIsNaN ? b : a;
}
else if ( aIsNaN ) {
- if ( bIsSignalingNaN | ! bIsNaN ) return a;
+ if ( bIsSignalingNaN || ! bIsNaN ) return a;
returnLargerSignificand:
if ( a.low < b.low ) return b;
if ( b.low < a.low ) return a;
@@ -538,6 +544,12 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM)
{
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+ if ( STATUS(default_nan_mode) ) {
+ a.low = float128_default_nan_low;
+ a.high = float128_default_nan_high;
+ return a;
+ }
+
aIsNaN = float128_is_nan( a );
aIsSignalingNaN = float128_is_signaling_nan( a );
bIsNaN = float128_is_nan( b );
@@ -555,7 +567,7 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM)
return bIsNaN ? b : a;
}
else if ( aIsNaN ) {
- if ( bIsSignalingNaN | ! bIsNaN ) return a;
+ if ( bIsSignalingNaN || ! bIsNaN ) return a;
returnLargerSignificand:
if ( lt128( a.high<<1, a.low, b.high<<1, b.low ) ) return b;
if ( lt128( b.high<<1, b.low, a.high<<1, a.low ) ) return a;
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 3ec1e0d..4d58744 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -30,6 +30,8 @@ these four paragraphs for those parts of this code that are retained.
=============================================================================*/
+/* FIXME: Flush-To-Zero only effects results. Denormal inputs should also
+ be flushed to zero. */
#include "softfloat.h"
/*----------------------------------------------------------------------------
@@ -294,6 +296,7 @@ static float32 roundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig STATUS_P
return packFloat32( zSign, 0xFF, - ( roundIncrement == 0 ));
}
if ( zExp < 0 ) {
+ if ( STATUS(flush_to_zero) ) return packFloat32( zSign, 0, 0 );
isTiny =
( STATUS(float_detect_tininess) == float_tininess_before_rounding )
|| ( zExp < -1 )
@@ -457,6 +460,7 @@ static float64 roundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig STATUS_P
return packFloat64( zSign, 0x7FF, - ( roundIncrement == 0 ));
}
if ( zExp < 0 ) {
+ if ( STATUS(flush_to_zero) ) return packFloat64( zSign, 0, 0 );
isTiny =
( STATUS(float_detect_tininess) == float_tininess_before_rounding )
|| ( zExp < -1 )
@@ -635,6 +639,7 @@ static floatx80
goto overflow;
}
if ( zExp <= 0 ) {
+ if ( STATUS(flush_to_zero) ) return packFloatx80( zSign, 0, 0 );
isTiny =
( STATUS(float_detect_tininess) == float_tininess_before_rounding )
|| ( zExp < 0 )
@@ -965,6 +970,7 @@ static float128
return packFloat128( zSign, 0x7FFF, 0, 0 );
}
if ( zExp < 0 ) {
+ if ( STATUS(flush_to_zero) ) return packFloat128( zSign, 0, 0, 0 );
isTiny =
( STATUS(float_detect_tininess) == float_tininess_before_rounding )
|| ( zExp < -1 )
@@ -1637,7 +1643,10 @@ static float32 addFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM)
if ( aSig | bSig ) return propagateFloat32NaN( a, b STATUS_VAR );
return a;
}
- if ( aExp == 0 ) return packFloat32( zSign, 0, ( aSig + bSig )>>6 );
+ if ( aExp == 0 ) {
+ if ( STATUS(flush_to_zero) ) return packFloat32( zSign, 0, 0 );
+ return packFloat32( zSign, 0, ( aSig + bSig )>>6 );
+ }
zSig = 0x40000000 + aSig + bSig;
zExp = aExp;
goto roundAndPack;
@@ -2048,6 +2057,53 @@ float32 float32_sqrt( float32 a STATUS_PARAM )
}
/*----------------------------------------------------------------------------
+| Returns the binary log of the single-precision floating-point value `a'.
+| The operation is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+float32 float32_log2( float32 a STATUS_PARAM )
+{
+ flag aSign, zSign;
+ int16 aExp;
+ bits32 aSig, zSig, i;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ aSign = extractFloat32Sign( a );
+
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return packFloat32( 1, 0xFF, 0 );
+ normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+ }
+ if ( aSign ) {
+ float_raise( float_flag_invalid STATUS_VAR);
+ return float32_default_nan;
+ }
+ if ( aExp == 0xFF ) {
+ if ( aSig ) return propagateFloat32NaN( a, float32_zero STATUS_VAR );
+ return a;
+ }
+
+ aExp -= 0x7F;
+ aSig |= 0x00800000;
+ zSign = aExp < 0;
+ zSig = aExp << 23;
+
+ for (i = 1 << 22; i > 0; i >>= 1) {
+ aSig = ( (bits64)aSig * aSig ) >> 23;
+ if ( aSig & 0x01000000 ) {
+ aSig >>= 1;
+ zSig |= i;
+ }
+ }
+
+ if ( zSign )
+ zSig = -zSig;
+
+ return normalizeRoundAndPackFloat32( zSign, 0x85, zSig STATUS_VAR );
+}
+
+/*----------------------------------------------------------------------------
| Returns 1 if the single-precision floating-point value `a' is equal to
| the corresponding value `b', and 0 otherwise. The comparison is performed
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
@@ -2595,7 +2651,10 @@ static float64 addFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM )
if ( aSig | bSig ) return propagateFloat64NaN( a, b STATUS_VAR );
return a;
}
- if ( aExp == 0 ) return packFloat64( zSign, 0, ( aSig + bSig )>>9 );
+ if ( aExp == 0 ) {
+ if ( STATUS(flush_to_zero) ) return packFloat64( zSign, 0, 0 );
+ return packFloat64( zSign, 0, ( aSig + bSig )>>9 );
+ }
zSig = LIT64( 0x4000000000000000 ) + aSig + bSig;
zExp = aExp;
goto roundAndPack;
@@ -2994,6 +3053,52 @@ float64 float64_sqrt( float64 a STATUS_PARAM )
}
/*----------------------------------------------------------------------------
+| Returns the binary log of the double-precision floating-point value `a'.
+| The operation is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+float64 float64_log2( float64 a STATUS_PARAM )
+{
+ flag aSign, zSign;
+ int16 aExp;
+ bits64 aSig, aSig0, aSig1, zSig, i;
+
+ aSig = extractFloat64Frac( a );
+ aExp = extractFloat64Exp( a );
+ aSign = extractFloat64Sign( a );
+
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return packFloat64( 1, 0x7FF, 0 );
+ normalizeFloat64Subnormal( aSig, &aExp, &aSig );
+ }
+ if ( aSign ) {
+ float_raise( float_flag_invalid STATUS_VAR);
+ return float64_default_nan;
+ }
+ if ( aExp == 0x7FF ) {
+ if ( aSig ) return propagateFloat64NaN( a, float64_zero STATUS_VAR );
+ return a;
+ }
+
+ aExp -= 0x3FF;
+ aSig |= LIT64( 0x0010000000000000 );
+ zSign = aExp < 0;
+ zSig = (bits64)aExp << 52;
+ for (i = 1LL << 51; i > 0; i >>= 1) {
+ mul64To128( aSig, aSig, &aSig0, &aSig1 );
+ aSig = ( aSig0 << 12 ) | ( aSig1 >> 52 );
+ if ( aSig & LIT64( 0x0020000000000000 ) ) {
+ aSig >>= 1;
+ zSig |= i;
+ }
+ }
+
+ if ( zSign )
+ zSig = -zSig;
+ return normalizeRoundAndPackFloat64( zSign, 0x408, zSig STATUS_VAR );
+}
+
+/*----------------------------------------------------------------------------
| Returns 1 if the double-precision floating-point value `a' is equal to the
| corresponding value `b', and 0 otherwise. The comparison is performed
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
@@ -4597,7 +4702,10 @@ static float128 addFloat128Sigs( float128 a, float128 b, flag zSign STATUS_PARAM
return a;
}
add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
- if ( aExp == 0 ) return packFloat128( zSign, 0, zSig0, zSig1 );
+ if ( aExp == 0 ) {
+ if ( STATUS(flush_to_zero) ) return packFloat128( zSign, 0, 0, 0 );
+ return packFloat128( zSign, 0, zSig0, zSig1 );
+ }
zSig2 = 0;
zSig0 |= LIT64( 0x0002000000000000 );
zExp = aExp;
@@ -4987,7 +5095,7 @@ float128 float128_rem( float128 a, float128 b STATUS_PARAM )
sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 );
} while ( 0 <= (sbits64) aSig0 );
add128(
- aSig0, aSig1, alternateASig0, alternateASig1, &sigMean0, &sigMean1 );
+ aSig0, aSig1, alternateASig0, alternateASig1, (bits64 *)&sigMean0, &sigMean1 );
if ( ( sigMean0 < 0 )
|| ( ( ( sigMean0 | sigMean1 ) == 0 ) && ( q & 1 ) ) ) {
aSig0 = alternateASig0;
@@ -5479,8 +5587,14 @@ float32 float32_scalbn( float32 a, int n STATUS_PARAM )
if ( aExp == 0xFF ) {
return a;
}
- aExp += n;
- return roundAndPackFloat32( aSign, aExp, aSig STATUS_VAR );
+ if ( aExp != 0 )
+ aSig |= 0x00800000;
+ else if ( aSig == 0 )
+ return a;
+
+ aExp += n - 1;
+ aSig <<= 7;
+ return normalizeRoundAndPackFloat32( aSign, aExp, aSig STATUS_VAR );
}
float64 float64_scalbn( float64 a, int n STATUS_PARAM )
@@ -5496,8 +5610,14 @@ float64 float64_scalbn( float64 a, int n STATUS_PARAM )
if ( aExp == 0x7FF ) {
return a;
}
- aExp += n;
- return roundAndPackFloat64( aSign, aExp, aSig STATUS_VAR );
+ if ( aExp != 0 )
+ aSig |= LIT64( 0x0010000000000000 );
+ else if ( aSig == 0 )
+ return a;
+
+ aExp += n - 1;
+ aSig <<= 10;
+ return normalizeRoundAndPackFloat64( aSign, aExp, aSig STATUS_VAR );
}
#ifdef FLOATX80
@@ -5514,9 +5634,12 @@ floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM )
if ( aExp == 0x7FF ) {
return a;
}
+ if (aExp == 0 && aSig == 0)
+ return a;
+
aExp += n;
- return roundAndPackFloatx80( STATUS(floatx80_rounding_precision),
- aSign, aExp, aSig, 0 STATUS_VAR );
+ return normalizeRoundAndPackFloatx80( STATUS(floatx80_rounding_precision),
+ aSign, aExp, aSig, 0 STATUS_VAR );
}
#endif
@@ -5534,8 +5657,14 @@ float128 float128_scalbn( float128 a, int n STATUS_PARAM )
if ( aExp == 0x7FFF ) {
return a;
}
- aExp += n;
- return roundAndPackFloat128( aSign, aExp, aSig0, aSig1, 0 STATUS_VAR );
+ if ( aExp != 0 )
+ aSig0 |= LIT64( 0x0001000000000000 );
+ else if ( aSig0 == 0 && aSig1 == 0 )
+ return a;
+
+ aExp += n - 1;
+ return normalizeRoundAndPackFloat128( aSign, aExp, aSig0, aSig1
+ STATUS_VAR );
}
#endif
diff --git a/fpu/softfloat.h b/fpu/softfloat.h
index 5f95d06..850a01f 100644
--- a/fpu/softfloat.h
+++ b/fpu/softfloat.h
@@ -50,8 +50,10 @@ these four paragraphs for those parts of this code that are retained.
typedef uint8_t flag;
typedef uint8_t uint8;
typedef int8_t int8;
+#ifndef _AIX
typedef int uint16;
typedef int int16;
+#endif
typedef unsigned int uint32;
typedef signed int int32;
typedef uint64_t uint64;
@@ -88,7 +90,7 @@ typedef int64_t sbits64;
#define FLOAT128
#else
/* native float support */
-#if (defined(__i386__) || defined(__x86_64__)) && !defined(_BSD)
+#if (defined(__i386__) || defined(__x86_64__)) && !defined(HOST_BSD)
#define FLOATX80
#endif
#endif /* !CONFIG_SOFTFLOAT */
@@ -188,10 +190,20 @@ typedef struct float_status {
#ifdef FLOATX80
signed char floatx80_rounding_precision;
#endif
+ flag flush_to_zero;
+ flag default_nan_mode;
} float_status;
void set_float_rounding_mode(int val STATUS_PARAM);
void set_float_exception_flags(int val STATUS_PARAM);
+INLINE void set_flush_to_zero(flag val STATUS_PARAM)
+{
+ STATUS(flush_to_zero) = val;
+}
+INLINE void set_default_nan_mode(flag val STATUS_PARAM)
+{
+ STATUS(default_nan_mode) = val;
+}
INLINE int get_float_exception_flags(float_status *status)
{
return STATUS(float_exception_flags);
@@ -257,6 +269,7 @@ float32 float32_mul( float32, float32 STATUS_PARAM );
float32 float32_div( float32, float32 STATUS_PARAM );
float32 float32_rem( float32, float32 STATUS_PARAM );
float32 float32_sqrt( float32 STATUS_PARAM );
+float32 float32_log2( float32 STATUS_PARAM );
int float32_eq( float32, float32 STATUS_PARAM );
int float32_le( float32, float32 STATUS_PARAM );
int float32_lt( float32, float32 STATUS_PARAM );
@@ -279,7 +292,23 @@ INLINE float32 float32_chs(float32 a)
return make_float32(float32_val(a) ^ 0x80000000);
}
+INLINE int float32_is_infinity(float32 a)
+{
+ return (float32_val(a) & 0x7fffffff) == 0x7f800000;
+}
+
+INLINE int float32_is_neg(float32 a)
+{
+ return float32_val(a) >> 31;
+}
+
+INLINE int float32_is_zero(float32 a)
+{
+ return (float32_val(a) & 0x7fffffff) == 0;
+}
+
#define float32_zero make_float32(0)
+#define float32_one make_float32(0x3f800000)
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision conversion routines.
@@ -311,6 +340,7 @@ float64 float64_mul( float64, float64 STATUS_PARAM );
float64 float64_div( float64, float64 STATUS_PARAM );
float64 float64_rem( float64, float64 STATUS_PARAM );
float64 float64_sqrt( float64 STATUS_PARAM );
+float64 float64_log2( float64 STATUS_PARAM );
int float64_eq( float64, float64 STATUS_PARAM );
int float64_le( float64, float64 STATUS_PARAM );
int float64_lt( float64, float64 STATUS_PARAM );
@@ -333,7 +363,23 @@ INLINE float64 float64_chs(float64 a)
return make_float64(float64_val(a) ^ 0x8000000000000000LL);
}
+INLINE int float64_is_infinity(float64 a)
+{
+ return (float64_val(a) & 0x7fffffffffffffffLL ) == 0x7ff0000000000000LL;
+}
+
+INLINE int float64_is_neg(float64 a)
+{
+ return float64_val(a) >> 63;
+}
+
+INLINE int float64_is_zero(float64 a)
+{
+ return (float64_val(a) & 0x7fffffffffffffffLL) == 0;
+}
+
#define float64_zero make_float64(0)
+#define float64_one make_float64(0x3ff0000000000000LL)
#ifdef FLOATX80
@@ -382,6 +428,21 @@ INLINE floatx80 floatx80_chs(floatx80 a)
return a;
}
+INLINE int floatx80_is_infinity(floatx80 a)
+{
+ return (a.high & 0x7fff) == 0x7fff && a.low == 0;
+}
+
+INLINE int floatx80_is_neg(floatx80 a)
+{
+ return a.high >> 15;
+}
+
+INLINE int floatx80_is_zero(floatx80 a)
+{
+ return (a.high & 0x7fff) == 0 && a.low == 0;
+}
+
#endif
#ifdef FLOAT128
@@ -433,6 +494,21 @@ INLINE float128 float128_chs(float128 a)
return a;
}
+INLINE int float128_is_infinity(float128 a)
+{
+ return (a.high & 0x7fffffffffffffffLL) == 0x7fff000000000000LL && a.low == 0;
+}
+
+INLINE int float128_is_neg(float128 a)
+{
+ return a.high >> 63;
+}
+
+INLINE int float128_is_zero(float128 a)
+{
+ return (a.high & 0x7fffffffffffffffLL) == 0 && a.low == 0;
+}
+
#endif
#else /* CONFIG_SOFTFLOAT */