From c27f813900a3c114562efbb8df1065e94766fc48 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 10 Feb 2009 15:43:59 -0800 Subject: auto import from //branches/cupcake/...@130745 --- fpu/softfloat-native.c | 159 ++++++++++++++++-- fpu/softfloat-native.h | 128 +++++++++++---- fpu/softfloat-specialize.h | 261 ++++++++++++++++++++--------- fpu/softfloat.c | 397 +++++++++++++++++++++++++++++++++++---------- fpu/softfloat.h | 124 +++++++++----- 5 files changed, 822 insertions(+), 247 deletions(-) (limited to 'fpu') diff --git a/fpu/softfloat-native.c b/fpu/softfloat-native.c index bbdb3d6..e58551f 100644 --- a/fpu/softfloat-native.c +++ b/fpu/softfloat-native.c @@ -30,6 +30,25 @@ void set_floatx80_rounding_precision(int val STATUS_PARAM) #define sqrtf(f) ((float)sqrt(f)) #define remainderf(fa, fb) ((float)remainder(fa, fb)) #define rintf(f) ((float)rint(f)) +#if !defined(__sparc__) && defined(HOST_SOLARIS) && HOST_SOLARIS < 10 +extern long double rintl(long double); +extern long double scalbnl(long double, int); + +long long +llrintl(long double x) { + return ((long long) rintl(x)); +} + +long +lrintl(long double x) { + return ((long) rintl(x)); +} + +long double +ldexpl(long double x, int n) { + return (scalbnl(x, n)); +} +#endif #endif #if defined(__powerpc__) @@ -40,7 +59,7 @@ double qemu_rint(double x) double y = 4503599627370496.0; if (fabs(x) >= y) return x; - if (x < 0) + if (x < 0) y = -y; y = (x + y) - y; if (y == 0.0) @@ -59,11 +78,21 @@ float32 int32_to_float32(int v STATUS_PARAM) return (float32)v; } +float32 uint32_to_float32(unsigned int v STATUS_PARAM) +{ + return (float32)v; +} + float64 int32_to_float64(int v STATUS_PARAM) { return (float64)v; } +float64 uint32_to_float64(unsigned int v STATUS_PARAM) +{ + return (float64)v; +} + #ifdef FLOATX80 floatx80 int32_to_floatx80(int v STATUS_PARAM) { @@ -74,10 +103,18 @@ float32 int64_to_float32( int64_t v STATUS_PARAM) { return (float32)v; } +float32 uint64_to_float32( uint64_t v STATUS_PARAM) +{ + return (float32)v; +} float64 int64_to_float64( int64_t v STATUS_PARAM) { return (float64)v; } +float64 uint64_to_float64( uint64_t v STATUS_PARAM) +{ + return (float64)v; +} #ifdef FLOATX80 floatx80 int64_to_floatx80( int64_t v STATUS_PARAM) { @@ -94,7 +131,7 @@ static inline int long_to_int32(long a) #else static inline int long_to_int32(long a) { - if (a != (int32_t)a) + if (a != (int32_t)a) a = 0x80000000; return a; } @@ -132,6 +169,37 @@ floatx80 float32_to_floatx80( float32 a STATUS_PARAM) } #endif +unsigned int float32_to_uint32( float32 a STATUS_PARAM) +{ + int64_t v; + unsigned int res; + + v = llrintf(a); + if (v < 0) { + res = 0; + } else if (v > 0xffffffff) { + res = 0xffffffff; + } else { + res = v; + } + return res; +} +unsigned int float32_to_uint32_round_to_zero( float32 a STATUS_PARAM) +{ + int64_t v; + unsigned int res; + + v = (int64_t)a; + if (v < 0) { + res = 0; + } else if (v > 0xffffffff) { + res = 0xffffffff; + } else { + res = v; + } + return res; +} + /*---------------------------------------------------------------------------- | Software IEC/IEEE single-precision operations. *----------------------------------------------------------------------------*/ @@ -149,7 +217,7 @@ float32 float32_sqrt( float32 a STATUS_PARAM) { return sqrtf(a); } -char float32_compare( float32 a, float32 b STATUS_PARAM ) +int float32_compare( float32 a, float32 b STATUS_PARAM ) { if (a < b) { return -1; @@ -161,7 +229,7 @@ char float32_compare( float32 a, float32 b STATUS_PARAM ) return 2; } } -char float32_compare_quiet( float32 a, float32 b STATUS_PARAM ) +int float32_compare_quiet( float32 a, float32 b STATUS_PARAM ) { if (isless(a, b)) { return -1; @@ -173,7 +241,7 @@ char float32_compare_quiet( float32 a, float32 b STATUS_PARAM ) return 2; } } -char float32_is_signaling_nan( float32 a1) +int float32_is_signaling_nan( float32 a1) { float32u u; uint32_t a; @@ -218,9 +286,67 @@ float128 float64_to_float128( float64 a STATUS_PARAM) } #endif +unsigned int float64_to_uint32( float64 a STATUS_PARAM) +{ + int64_t v; + unsigned int res; + + v = llrint(a); + if (v < 0) { + res = 0; + } else if (v > 0xffffffff) { + res = 0xffffffff; + } else { + res = v; + } + return res; +} +unsigned int float64_to_uint32_round_to_zero( float64 a STATUS_PARAM) +{ + int64_t v; + unsigned int res; + + v = (int64_t)a; + if (v < 0) { + res = 0; + } else if (v > 0xffffffff) { + res = 0xffffffff; + } else { + res = v; + } + return res; +} +uint64_t float64_to_uint64 (float64 a STATUS_PARAM) +{ + int64_t v; + + v = llrint(a + (float64)INT64_MIN); + + return v - INT64_MIN; +} +uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM) +{ + int64_t v; + + v = (int64_t)(a + (float64)INT64_MIN); + + return v - INT64_MIN; +} + /*---------------------------------------------------------------------------- | Software IEC/IEEE double-precision operations. *----------------------------------------------------------------------------*/ +#if defined(__sun__) && defined(HOST_SOLARIS) && HOST_SOLARIS < 10 +static inline float64 trunc(float64 x) +{ + return x < 0 ? -floor(-x) : floor(x); +} +#endif +float64 float64_trunc_to_int( float64 a STATUS_PARAM ) +{ + return trunc(a); +} + float64 float64_round_to_int( float64 a STATUS_PARAM ) { #if defined(__arm__) @@ -253,7 +379,7 @@ float64 float64_sqrt( float64 a STATUS_PARAM) { return sqrt(a); } -char float64_compare( float64 a, float64 b STATUS_PARAM ) +int float64_compare( float64 a, float64 b STATUS_PARAM ) { if (a < b) { return -1; @@ -265,7 +391,7 @@ char float64_compare( float64 a, float64 b STATUS_PARAM ) return 2; } } -char float64_compare_quiet( float64 a, float64 b STATUS_PARAM ) +int float64_compare_quiet( float64 a, float64 b STATUS_PARAM ) { if (isless(a, b)) { return -1; @@ -277,7 +403,7 @@ char float64_compare_quiet( float64 a, float64 b STATUS_PARAM ) return 2; } } -char float64_is_signaling_nan( float64 a1) +int float64_is_signaling_nan( float64 a1) { float64u u; uint64_t a; @@ -289,6 +415,17 @@ char float64_is_signaling_nan( float64 a1) } +int float64_is_nan( float64 a1 ) +{ + float64u u; + uint64_t a; + u.f = a1; + a = u.i; + + return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) ); + +} + #ifdef FLOATX80 /*---------------------------------------------------------------------------- @@ -334,7 +471,7 @@ floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM) { return sqrtl(a); } -char floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM ) +int floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM ) { if (a < b) { return -1; @@ -346,7 +483,7 @@ char floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM ) return 2; } } -char floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM ) +int floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM ) { if (isless(a, b)) { return -1; @@ -358,7 +495,7 @@ char floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM ) return 2; } } -char floatx80_is_signaling_nan( floatx80 a1) +int floatx80_is_signaling_nan( floatx80 a1) { floatx80u u; u.f = a1; diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h index e7c08b8..379d49d 100644 --- a/fpu/softfloat-native.h +++ b/fpu/softfloat-native.h @@ -8,6 +8,11 @@ #include #endif +#ifdef __OpenBSD__ +/* Get OpenBSD version number */ +#include +#endif + /* * Define some C99-7.12.3 classification macros and * some C99-.12.4 for Solaris systems OS less than 10, @@ -15,7 +20,9 @@ * Solaris 10 with GCC4 does not need these macros as they * are defined in with a compiler directive */ -#if defined(HOST_SOLARIS) && (( HOST_SOLARIS <= 9 ) || ( ( HOST_SOLARIS >= 10 ) && ( __GNUC__ <= 4) )) +#if defined(HOST_SOLARIS) && (( HOST_SOLARIS <= 9 ) || ((HOST_SOLARIS >= 10) \ + && (__GNUC__ <= 4))) \ + || (defined(__OpenBSD__) && (OpenBSD < 200811)) /* * C99 7.12.3 classification macros * and @@ -24,6 +31,9 @@ * ... do not work on Solaris 10 using GNU CC 3.4.x. * Try to workaround the missing / broken C99 math macros. */ +#if defined(__OpenBSD__) +#define unordered(x, y) (isnan(x) || isnan(y)) +#endif #define isnormal(x) (fpclass(x) >= FP_NZERO) #define isgreater(x, y) ((!unordered(x, y)) && ((x) > (y))) @@ -33,6 +43,29 @@ #define isunordered(x,y) unordered(x, y) #endif +#if defined(__sun__) && !defined(NEED_LIBSUNMATH) + +#ifndef isnan +# define isnan(x) \ + (sizeof (x) == sizeof (long double) ? isnan_ld (x) \ + : sizeof (x) == sizeof (double) ? isnan_d (x) \ + : isnan_f (x)) +static inline int isnan_f (float x) { return x != x; } +static inline int isnan_d (double x) { return x != x; } +static inline int isnan_ld (long double x) { return x != x; } +#endif + +#ifndef isinf +# define isinf(x) \ + (sizeof (x) == sizeof (long double) ? isinf_ld (x) \ + : sizeof (x) == sizeof (double) ? isinf_d (x) \ + : isinf_f (x)) +static inline int isinf_f (float x) { return isnan (x - x); } +static inline int isinf_d (double x) { return isnan (x - x); } +static inline int isinf_ld (long double x) { return isnan (x - x); } +#endif +#endif + typedef float float32; typedef double float64; #ifdef FLOATX80 @@ -61,6 +94,11 @@ typedef union { | Software IEC/IEEE floating-point rounding mode. *----------------------------------------------------------------------------*/ #if (defined(_BSD) && !defined(__APPLE__)) || defined(HOST_SOLARIS) +#if defined(__OpenBSD__) +#define FE_RM FP_RM +#define FE_RP FP_RP +#define FE_RZ FP_RZ +#endif enum { float_round_nearest_even = FP_RN, float_round_down = FP_RM, @@ -99,7 +137,9 @@ void set_floatx80_rounding_precision(int val STATUS_PARAM); | Software IEC/IEEE integer-to-floating-point conversion routines. *----------------------------------------------------------------------------*/ float32 int32_to_float32( int STATUS_PARAM); +float32 uint32_to_float32( unsigned int STATUS_PARAM); float64 int32_to_float64( int STATUS_PARAM); +float64 uint32_to_float64( unsigned int STATUS_PARAM); #ifdef FLOATX80 floatx80 int32_to_floatx80( int STATUS_PARAM); #endif @@ -107,7 +147,9 @@ floatx80 int32_to_floatx80( int STATUS_PARAM); float128 int32_to_float128( int STATUS_PARAM); #endif float32 int64_to_float32( int64_t STATUS_PARAM); +float32 uint64_to_float32( uint64_t STATUS_PARAM); float64 int64_to_float64( int64_t STATUS_PARAM); +float64 uint64_to_float64( uint64_t v STATUS_PARAM); #ifdef FLOATX80 floatx80 int64_to_floatx80( int64_t STATUS_PARAM); #endif @@ -120,6 +162,8 @@ float128 int64_to_float128( int64_t STATUS_PARAM); *----------------------------------------------------------------------------*/ int float32_to_int32( float32 STATUS_PARAM); int float32_to_int32_round_to_zero( float32 STATUS_PARAM); +unsigned int float32_to_uint32( float32 a STATUS_PARAM); +unsigned int float32_to_uint32_round_to_zero( float32 a STATUS_PARAM); int64_t float32_to_int64( float32 STATUS_PARAM); int64_t float32_to_int64_round_to_zero( float32 STATUS_PARAM); float64 float32_to_float64( float32 STATUS_PARAM); @@ -152,38 +196,38 @@ INLINE float32 float32_div( float32 a, float32 b STATUS_PARAM) } float32 float32_rem( float32, float32 STATUS_PARAM); float32 float32_sqrt( float32 STATUS_PARAM); -INLINE char float32_eq( float32 a, float32 b STATUS_PARAM) +INLINE int float32_eq( float32 a, float32 b STATUS_PARAM) { return a == b; } -INLINE char float32_le( float32 a, float32 b STATUS_PARAM) +INLINE int float32_le( float32 a, float32 b STATUS_PARAM) { return a <= b; } -INLINE char float32_lt( float32 a, float32 b STATUS_PARAM) +INLINE int float32_lt( float32 a, float32 b STATUS_PARAM) { return a < b; } -INLINE char float32_eq_signaling( float32 a, float32 b STATUS_PARAM) +INLINE int float32_eq_signaling( float32 a, float32 b STATUS_PARAM) { return a <= b && a >= b; } -INLINE char float32_le_quiet( float32 a, float32 b STATUS_PARAM) +INLINE int float32_le_quiet( float32 a, float32 b STATUS_PARAM) { return islessequal(a, b); } -INLINE char float32_lt_quiet( float32 a, float32 b STATUS_PARAM) +INLINE int float32_lt_quiet( float32 a, float32 b STATUS_PARAM) { return isless(a, b); } -INLINE char float32_unordered( float32 a, float32 b STATUS_PARAM) +INLINE int float32_unordered( float32 a, float32 b STATUS_PARAM) { return isunordered(a, b); } -char float32_compare( float32, float32 STATUS_PARAM ); -char float32_compare_quiet( float32, float32 STATUS_PARAM ); -char float32_is_signaling_nan( float32 ); +int float32_compare( float32, float32 STATUS_PARAM ); +int float32_compare_quiet( float32, float32 STATUS_PARAM ); +int float32_is_signaling_nan( float32 ); INLINE float32 float32_abs(float32 a) { @@ -195,13 +239,22 @@ INLINE float32 float32_chs(float32 a) return -a; } +INLINE float32 float32_scalbn(float32 a, int n) +{ + return scalbnf(a, n); +} + /*---------------------------------------------------------------------------- | Software IEC/IEEE double-precision conversion routines. *----------------------------------------------------------------------------*/ int float64_to_int32( float64 STATUS_PARAM ); int float64_to_int32_round_to_zero( float64 STATUS_PARAM ); +unsigned int float64_to_uint32( float64 STATUS_PARAM ); +unsigned int float64_to_uint32_round_to_zero( float64 STATUS_PARAM ); int64_t float64_to_int64( float64 STATUS_PARAM ); int64_t float64_to_int64_round_to_zero( float64 STATUS_PARAM ); +uint64_t float64_to_uint64( float64 STATUS_PARAM ); +uint64_t float64_to_uint64_round_to_zero( float64 STATUS_PARAM ); float32 float64_to_float32( float64 STATUS_PARAM ); #ifdef FLOATX80 floatx80 float64_to_floatx80( float64 STATUS_PARAM ); @@ -214,6 +267,7 @@ float128 float64_to_float128( float64 STATUS_PARAM ); | Software IEC/IEEE double-precision operations. *----------------------------------------------------------------------------*/ float64 float64_round_to_int( float64 STATUS_PARAM ); +float64 float64_trunc_to_int( float64 STATUS_PARAM ); INLINE float64 float64_add( float64 a, float64 b STATUS_PARAM) { return a + b; @@ -232,39 +286,40 @@ INLINE float64 float64_div( float64 a, float64 b STATUS_PARAM) } float64 float64_rem( float64, float64 STATUS_PARAM ); float64 float64_sqrt( float64 STATUS_PARAM ); -INLINE char float64_eq( float64 a, float64 b STATUS_PARAM) +INLINE int float64_eq( float64 a, float64 b STATUS_PARAM) { return a == b; } -INLINE char float64_le( float64 a, float64 b STATUS_PARAM) +INLINE int float64_le( float64 a, float64 b STATUS_PARAM) { return a <= b; } -INLINE char float64_lt( float64 a, float64 b STATUS_PARAM) +INLINE int float64_lt( float64 a, float64 b STATUS_PARAM) { return a < b; } -INLINE char float64_eq_signaling( float64 a, float64 b STATUS_PARAM) +INLINE int float64_eq_signaling( float64 a, float64 b STATUS_PARAM) { return a <= b && a >= b; } -INLINE char float64_le_quiet( float64 a, float64 b STATUS_PARAM) +INLINE int float64_le_quiet( float64 a, float64 b STATUS_PARAM) { return islessequal(a, b); } -INLINE char float64_lt_quiet( float64 a, float64 b STATUS_PARAM) +INLINE int float64_lt_quiet( float64 a, float64 b STATUS_PARAM) { return isless(a, b); } -INLINE char float64_unordered( float64 a, float64 b STATUS_PARAM) +INLINE int float64_unordered( float64 a, float64 b STATUS_PARAM) { return isunordered(a, b); } -char float64_compare( float64, float64 STATUS_PARAM ); -char float64_compare_quiet( float64, float64 STATUS_PARAM ); -char float64_is_signaling_nan( float64 ); +int float64_compare( float64, float64 STATUS_PARAM ); +int float64_compare_quiet( float64, float64 STATUS_PARAM ); +int float64_is_signaling_nan( float64 ); +int float64_is_nan( float64 ); INLINE float64 float64_abs(float64 a) { @@ -276,6 +331,11 @@ INLINE float64 float64_chs(float64 a) return -a; } +INLINE float64 float64_scalbn(float64 a, int n) +{ + return scalbn(a, n); +} + #ifdef FLOATX80 /*---------------------------------------------------------------------------- @@ -313,39 +373,39 @@ INLINE floatx80 floatx80_div( floatx80 a, floatx80 b STATUS_PARAM) } floatx80 floatx80_rem( floatx80, floatx80 STATUS_PARAM ); floatx80 floatx80_sqrt( floatx80 STATUS_PARAM ); -INLINE char floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM) +INLINE int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM) { return a == b; } -INLINE char floatx80_le( floatx80 a, floatx80 b STATUS_PARAM) +INLINE int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM) { return a <= b; } -INLINE char floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM) +INLINE int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM) { return a < b; } -INLINE char floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM) +INLINE int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM) { return a <= b && a >= b; } -INLINE char floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM) +INLINE int floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM) { return islessequal(a, b); } -INLINE char floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM) +INLINE int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM) { return isless(a, b); } -INLINE char floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM) +INLINE int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM) { return isunordered(a, b); } -char floatx80_compare( floatx80, floatx80 STATUS_PARAM ); -char floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM ); -char floatx80_is_signaling_nan( floatx80 ); +int floatx80_compare( floatx80, floatx80 STATUS_PARAM ); +int floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM ); +int floatx80_is_signaling_nan( floatx80 ); INLINE floatx80 floatx80_abs(floatx80 a) { @@ -356,4 +416,10 @@ INLINE floatx80 floatx80_chs(floatx80 a) { return -a; } + +INLINE floatx80 floatx80_scalbn(floatx80 a, int n) +{ + return scalbnl(a, n); +} + #endif diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h index d430f58..93fe06e 100644 --- a/fpu/softfloat-specialize.h +++ b/fpu/softfloat-specialize.h @@ -30,6 +30,12 @@ these four paragraphs for those parts of this code that are retained. =============================================================================*/ +#if defined(TARGET_MIPS) || defined(TARGET_HPPA) +#define SNAN_BIT_IS_ONE 1 +#else +#define SNAN_BIT_IS_ONE 0 +#endif + /*---------------------------------------------------------------------------- | Underflow tininess-detection mode, statically initialized to default value. | (The declaration in `softfloat.h' must match the `int8' type here.) @@ -45,9 +51,7 @@ int8 float_detect_tininess = float_tininess_after_rounding; void float_raise( int8 flags STATUS_PARAM ) { - STATUS(float_exception_flags) |= flags; - } /*---------------------------------------------------------------------------- @@ -61,18 +65,31 @@ typedef struct { /*---------------------------------------------------------------------------- | The pattern for a default generated single-precision NaN. *----------------------------------------------------------------------------*/ -#define float32_default_nan 0xFFC00000 +#if defined(TARGET_SPARC) +#define float32_default_nan make_float32(0x7FFFFFFF) +#elif defined(TARGET_POWERPC) +#define float32_default_nan make_float32(0x7FC00000) +#elif defined(TARGET_HPPA) +#define float32_default_nan make_float32(0x7FA00000) +#elif SNAN_BIT_IS_ONE +#define float32_default_nan make_float32(0x7FBFFFFF) +#else +#define float32_default_nan make_float32(0xFFC00000) +#endif /*---------------------------------------------------------------------------- -| Returns 1 if the single-precision floating-point value `a' is a NaN; -| otherwise returns 0. +| Returns 1 if the single-precision floating-point value `a' is a quiet +| NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -flag float32_is_nan( float32 a ) +int float32_is_nan( float32 a_ ) { - - return ( 0xFF000000 < (bits32) ( a<<1 ) ); - + uint32_t a = float32_val(a_); +#if SNAN_BIT_IS_ONE + return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); +#else + return ( 0xFF800000 <= (bits32) ( a<<1 ) ); +#endif } /*---------------------------------------------------------------------------- @@ -80,11 +97,14 @@ flag float32_is_nan( float32 a ) | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -flag float32_is_signaling_nan( float32 a ) +int float32_is_signaling_nan( float32 a_ ) { - + uint32_t a = float32_val(a_); +#if SNAN_BIT_IS_ONE + return ( 0xFF800000 <= (bits32) ( a<<1 ) ); +#else return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); - +#endif } /*---------------------------------------------------------------------------- @@ -98,11 +118,10 @@ static commonNaNT float32ToCommonNaN( float32 a STATUS_PARAM ) commonNaNT z; if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR ); - z.sign = a>>31; + z.sign = float32_val(a)>>31; z.low = 0; - z.high = ( (bits64) a )<<41; + z.high = ( (bits64) float32_val(a) )<<41; return z; - } /*---------------------------------------------------------------------------- @@ -112,9 +131,12 @@ static commonNaNT float32ToCommonNaN( float32 a STATUS_PARAM ) static float32 commonNaNToFloat32( commonNaNT a ) { - - return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 ); - + bits32 mantissa = a.high>>41; + if ( mantissa ) + return make_float32( + ( ( (bits32) a.sign )<<31 ) | 0x7F800000 | ( a.high>>41 ) ); + else + return float32_default_nan; } /*---------------------------------------------------------------------------- @@ -126,46 +148,75 @@ static float32 commonNaNToFloat32( commonNaNT a ) static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) { flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + bits32 av, bv, res; aIsNaN = float32_is_nan( a ); aIsSignalingNaN = float32_is_signaling_nan( a ); bIsNaN = float32_is_nan( b ); bIsSignalingNaN = float32_is_signaling_nan( b ); - a |= 0x00400000; - b |= 0x00400000; + av = float32_val(a); + bv = float32_val(b); +#if SNAN_BIT_IS_ONE + av &= ~0x00400000; + bv &= ~0x00400000; +#else + av |= 0x00400000; + bv |= 0x00400000; +#endif if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); if ( aIsSignalingNaN ) { if ( bIsSignalingNaN ) goto returnLargerSignificand; - return bIsNaN ? b : a; + res = bIsNaN ? bv : av; } else if ( aIsNaN ) { - if ( bIsSignalingNaN | ! bIsNaN ) return a; + if ( bIsSignalingNaN | ! bIsNaN ) + res = av; + else { returnLargerSignificand: - if ( (bits32) ( a<<1 ) < (bits32) ( b<<1 ) ) return b; - if ( (bits32) ( b<<1 ) < (bits32) ( a<<1 ) ) return a; - return ( a < b ) ? a : b; + if ( (bits32) ( av<<1 ) < (bits32) ( bv<<1 ) ) + res = bv; + else if ( (bits32) ( bv<<1 ) < (bits32) ( av<<1 ) ) + res = av; + else + res = ( av < bv ) ? av : bv; + } } else { - return b; + res = bv; } - + return make_float32(res); } /*---------------------------------------------------------------------------- | The pattern for a default generated double-precision NaN. *----------------------------------------------------------------------------*/ -#define float64_default_nan LIT64( 0xFFF8000000000000 ) +#if defined(TARGET_SPARC) +#define float64_default_nan make_float64(LIT64( 0x7FFFFFFFFFFFFFFF )) +#elif defined(TARGET_POWERPC) +#define float64_default_nan make_float64(LIT64( 0x7FF8000000000000 )) +#elif defined(TARGET_HPPA) +#define float64_default_nan make_float64(LIT64( 0x7FF4000000000000 )) +#elif SNAN_BIT_IS_ONE +#define float64_default_nan make_float64(LIT64( 0x7FF7FFFFFFFFFFFF )) +#else +#define float64_default_nan make_float64(LIT64( 0xFFF8000000000000 )) +#endif /*---------------------------------------------------------------------------- -| Returns 1 if the double-precision floating-point value `a' is a NaN; -| otherwise returns 0. +| Returns 1 if the double-precision floating-point value `a' is a quiet +| NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -flag float64_is_nan( float64 a ) +int float64_is_nan( float64 a_ ) { - - return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) ); - + bits64 a = float64_val(a_); +#if SNAN_BIT_IS_ONE + return + ( ( ( a>>51 ) & 0xFFF ) == 0xFFE ) + && ( a & LIT64( 0x0007FFFFFFFFFFFF ) ); +#else + return ( LIT64( 0xFFF0000000000000 ) <= (bits64) ( a<<1 ) ); +#endif } /*---------------------------------------------------------------------------- @@ -173,13 +224,16 @@ flag float64_is_nan( float64 a ) | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -flag float64_is_signaling_nan( float64 a ) +int float64_is_signaling_nan( float64 a_ ) { - + bits64 a = float64_val(a_); +#if SNAN_BIT_IS_ONE + return ( LIT64( 0xFFF0000000000000 ) <= (bits64) ( a<<1 ) ); +#else return ( ( ( a>>51 ) & 0xFFF ) == 0xFFE ) && ( a & LIT64( 0x0007FFFFFFFFFFFF ) ); - +#endif } /*---------------------------------------------------------------------------- @@ -193,11 +247,10 @@ static commonNaNT float64ToCommonNaN( float64 a STATUS_PARAM) commonNaNT z; if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR); - z.sign = a>>63; + z.sign = float64_val(a)>>63; z.low = 0; - z.high = a<<12; + z.high = float64_val(a)<<12; return z; - } /*---------------------------------------------------------------------------- @@ -207,12 +260,15 @@ static commonNaNT float64ToCommonNaN( float64 a STATUS_PARAM) static float64 commonNaNToFloat64( commonNaNT a ) { - - return - ( ( (bits64) a.sign )<<63 ) - | LIT64( 0x7FF8000000000000 ) - | ( a.high>>12 ); - + bits64 mantissa = a.high>>12; + + if ( mantissa ) + return make_float64( + ( ( (bits64) a.sign )<<63 ) + | LIT64( 0x7FF0000000000000 ) + | ( a.high>>12 )); + else + return float64_default_nan; } /*---------------------------------------------------------------------------- @@ -224,29 +280,43 @@ static float64 commonNaNToFloat64( commonNaNT a ) static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM) { flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + bits64 av, bv, res; aIsNaN = float64_is_nan( a ); aIsSignalingNaN = float64_is_signaling_nan( a ); bIsNaN = float64_is_nan( b ); bIsSignalingNaN = float64_is_signaling_nan( b ); - a |= LIT64( 0x0008000000000000 ); - b |= LIT64( 0x0008000000000000 ); + av = float64_val(a); + bv = float64_val(b); +#if SNAN_BIT_IS_ONE + av &= ~LIT64( 0x0008000000000000 ); + bv &= ~LIT64( 0x0008000000000000 ); +#else + av |= LIT64( 0x0008000000000000 ); + bv |= LIT64( 0x0008000000000000 ); +#endif if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); if ( aIsSignalingNaN ) { if ( bIsSignalingNaN ) goto returnLargerSignificand; - return bIsNaN ? b : a; + res = bIsNaN ? bv : av; } else if ( aIsNaN ) { - if ( bIsSignalingNaN | ! bIsNaN ) return a; + if ( bIsSignalingNaN | ! bIsNaN ) + res = av; + else { returnLargerSignificand: - if ( (bits64) ( a<<1 ) < (bits64) ( b<<1 ) ) return b; - if ( (bits64) ( b<<1 ) < (bits64) ( a<<1 ) ) return a; - return ( a < b ) ? a : b; + if ( (bits64) ( av<<1 ) < (bits64) ( bv<<1 ) ) + res = bv; + else if ( (bits64) ( bv<<1 ) < (bits64) ( av<<1 ) ) + res = av; + else + res = ( av < bv ) ? av : bv; + } } else { - return b; + res = bv; } - + return make_float64(res); } #ifdef FLOATX80 @@ -256,19 +326,32 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM) | `high' and `low' values hold the most- and least-significant bits, | respectively. *----------------------------------------------------------------------------*/ +#if SNAN_BIT_IS_ONE +#define floatx80_default_nan_high 0x7FFF +#define floatx80_default_nan_low LIT64( 0xBFFFFFFFFFFFFFFF ) +#else #define floatx80_default_nan_high 0xFFFF #define floatx80_default_nan_low LIT64( 0xC000000000000000 ) +#endif /*---------------------------------------------------------------------------- | Returns 1 if the extended double-precision floating-point value `a' is a -| NaN; otherwise returns 0. +| quiet NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -flag floatx80_is_nan( floatx80 a ) +int floatx80_is_nan( floatx80 a ) { +#if SNAN_BIT_IS_ONE + bits64 aLow; + aLow = a.low & ~ LIT64( 0x4000000000000000 ); + return + ( ( a.high & 0x7FFF ) == 0x7FFF ) + && (bits64) ( aLow<<1 ) + && ( a.low == aLow ); +#else return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 ); - +#endif } /*---------------------------------------------------------------------------- @@ -276,8 +359,11 @@ flag floatx80_is_nan( floatx80 a ) | signaling NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -flag floatx80_is_signaling_nan( floatx80 a ) +int floatx80_is_signaling_nan( floatx80 a ) { +#if SNAN_BIT_IS_ONE + return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 ); +#else bits64 aLow; aLow = a.low & ~ LIT64( 0x4000000000000000 ); @@ -285,7 +371,7 @@ flag floatx80_is_signaling_nan( floatx80 a ) ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( aLow<<1 ) && ( a.low == aLow ); - +#endif } /*---------------------------------------------------------------------------- @@ -301,9 +387,8 @@ static commonNaNT floatx80ToCommonNaN( floatx80 a STATUS_PARAM) if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR); z.sign = a.high>>15; z.low = 0; - z.high = a.low<<1; + z.high = a.low; return z; - } /*---------------------------------------------------------------------------- @@ -315,10 +400,12 @@ static floatx80 commonNaNToFloatx80( commonNaNT a ) { floatx80 z; - z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 ); + if (a.high) + z.low = a.high; + else + z.low = floatx80_default_nan_low; z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF; return z; - } /*---------------------------------------------------------------------------- @@ -335,8 +422,13 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM) aIsSignalingNaN = floatx80_is_signaling_nan( a ); bIsNaN = floatx80_is_nan( b ); bIsSignalingNaN = floatx80_is_signaling_nan( b ); +#if SNAN_BIT_IS_ONE + a.low &= ~LIT64( 0xC000000000000000 ); + b.low &= ~LIT64( 0xC000000000000000 ); +#else a.low |= LIT64( 0xC000000000000000 ); b.low |= LIT64( 0xC000000000000000 ); +#endif if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); if ( aIsSignalingNaN ) { if ( bIsSignalingNaN ) goto returnLargerSignificand; @@ -352,7 +444,6 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM) else { return b; } - } #endif @@ -363,21 +454,30 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM) | The pattern for a default generated quadruple-precision NaN. The `high' and | `low' values hold the most- and least-significant bits, respectively. *----------------------------------------------------------------------------*/ +#if SNAN_BIT_IS_ONE +#define float128_default_nan_high LIT64( 0x7FFF7FFFFFFFFFFF ) +#define float128_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF ) +#else #define float128_default_nan_high LIT64( 0xFFFF800000000000 ) #define float128_default_nan_low LIT64( 0x0000000000000000 ) +#endif /*---------------------------------------------------------------------------- -| Returns 1 if the quadruple-precision floating-point value `a' is a NaN; -| otherwise returns 0. +| Returns 1 if the quadruple-precision floating-point value `a' is a quiet +| NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -flag float128_is_nan( float128 a ) +int float128_is_nan( float128 a ) { - +#if SNAN_BIT_IS_ONE + return + ( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE ) + && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) ); +#else return ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) ) && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) ); - +#endif } /*---------------------------------------------------------------------------- @@ -385,13 +485,17 @@ flag float128_is_nan( float128 a ) | signaling NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -flag float128_is_signaling_nan( float128 a ) +int float128_is_signaling_nan( float128 a ) { - +#if SNAN_BIT_IS_ONE + return + ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) ) + && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) ); +#else return ( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE ) && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) ); - +#endif } /*---------------------------------------------------------------------------- @@ -408,7 +512,6 @@ static commonNaNT float128ToCommonNaN( float128 a STATUS_PARAM) z.sign = a.high>>63; shortShift128Left( a.high, a.low, 16, &z.high, &z.low ); return z; - } /*---------------------------------------------------------------------------- @@ -421,9 +524,8 @@ static float128 commonNaNToFloat128( commonNaNT a ) float128 z; shift128Right( a.high, a.low, 16, &z.high, &z.low ); - z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF800000000000 ); + z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF000000000000 ); return z; - } /*---------------------------------------------------------------------------- @@ -440,8 +542,13 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM) aIsSignalingNaN = float128_is_signaling_nan( a ); bIsNaN = float128_is_nan( b ); bIsSignalingNaN = float128_is_signaling_nan( b ); +#if SNAN_BIT_IS_ONE + a.high &= ~LIT64( 0x0000800000000000 ); + b.high &= ~LIT64( 0x0000800000000000 ); +#else a.high |= LIT64( 0x0000800000000000 ); b.high |= LIT64( 0x0000800000000000 ); +#endif if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); if ( aIsSignalingNaN ) { if ( bIsSignalingNaN ) goto returnLargerSignificand; @@ -457,8 +564,6 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM) else { return b; } - } #endif - diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 75511c9..3ec1e0d 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -175,7 +175,7 @@ static int64 roundAndPackInt64( flag zSign, bits64 absZ0, bits64 absZ1 STATUS_PA INLINE bits32 extractFloat32Frac( float32 a ) { - return a & 0x007FFFFF; + return float32_val(a) & 0x007FFFFF; } @@ -186,7 +186,7 @@ INLINE bits32 extractFloat32Frac( float32 a ) INLINE int16 extractFloat32Exp( float32 a ) { - return ( a>>23 ) & 0xFF; + return ( float32_val(a)>>23 ) & 0xFF; } @@ -197,7 +197,7 @@ INLINE int16 extractFloat32Exp( float32 a ) INLINE flag extractFloat32Sign( float32 a ) { - return a>>31; + return float32_val(a)>>31; } @@ -233,7 +233,8 @@ static void INLINE float32 packFloat32( flag zSign, int16 zExp, bits32 zSig ) { - return ( ( (bits32) zSign )<<31 ) + ( ( (bits32) zExp )<<23 ) + zSig; + return make_float32( + ( ( (bits32) zSign )<<31 ) + ( ( (bits32) zExp )<<23 ) + zSig); } @@ -290,7 +291,7 @@ static float32 roundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig STATUS_P && ( (sbits32) ( zSig + roundIncrement ) < 0 ) ) ) { float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR); - return packFloat32( zSign, 0xFF, 0 ) - ( roundIncrement == 0 ); + return packFloat32( zSign, 0xFF, - ( roundIncrement == 0 )); } if ( zExp < 0 ) { isTiny = @@ -337,7 +338,7 @@ static float32 INLINE bits64 extractFloat64Frac( float64 a ) { - return a & LIT64( 0x000FFFFFFFFFFFFF ); + return float64_val(a) & LIT64( 0x000FFFFFFFFFFFFF ); } @@ -348,7 +349,7 @@ INLINE bits64 extractFloat64Frac( float64 a ) INLINE int16 extractFloat64Exp( float64 a ) { - return ( a>>52 ) & 0x7FF; + return ( float64_val(a)>>52 ) & 0x7FF; } @@ -359,7 +360,7 @@ INLINE int16 extractFloat64Exp( float64 a ) INLINE flag extractFloat64Sign( float64 a ) { - return a>>63; + return float64_val(a)>>63; } @@ -395,7 +396,8 @@ static void INLINE float64 packFloat64( flag zSign, int16 zExp, bits64 zSig ) { - return ( ( (bits64) zSign )<<63 ) + ( ( (bits64) zExp )<<52 ) + zSig; + return make_float64( + ( ( (bits64) zSign )<<63 ) + ( ( (bits64) zExp )<<52 ) + zSig); } @@ -452,7 +454,7 @@ static float64 roundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig STATUS_P && ( (sbits64) ( zSig + roundIncrement ) < 0 ) ) ) { float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR); - return packFloat64( zSign, 0x7FF, 0 ) - ( roundIncrement == 0 ); + return packFloat64( zSign, 0x7FF, - ( roundIncrement == 0 )); } if ( zExp < 0 ) { isTiny = @@ -1050,7 +1052,7 @@ float32 int32_to_float32( int32 a STATUS_PARAM ) { flag zSign; - if ( a == 0 ) return 0; + if ( a == 0 ) return float32_zero; if ( a == (sbits32) 0x80000000 ) return packFloat32( 1, 0x9E, 0 ); zSign = ( a < 0 ); return normalizeRoundAndPackFloat32( zSign, 0x9C, zSign ? - a : a STATUS_VAR ); @@ -1070,7 +1072,7 @@ float64 int32_to_float64( int32 a STATUS_PARAM ) int8 shiftCount; bits64 zSig; - if ( a == 0 ) return 0; + if ( a == 0 ) return float64_zero; zSign = ( a < 0 ); absA = zSign ? - a : a; shiftCount = countLeadingZeros32( absA ) + 21; @@ -1144,7 +1146,7 @@ float32 int64_to_float32( int64 a STATUS_PARAM ) uint64 absA; int8 shiftCount; - if ( a == 0 ) return 0; + if ( a == 0 ) return float32_zero; zSign = ( a < 0 ); absA = zSign ? - a : a; shiftCount = countLeadingZeros64( absA ) - 40; @@ -1164,6 +1166,27 @@ float32 int64_to_float32( int64 a STATUS_PARAM ) } +float32 uint64_to_float32( uint64 a STATUS_PARAM ) +{ + int8 shiftCount; + + if ( a == 0 ) return float32_zero; + shiftCount = countLeadingZeros64( a ) - 40; + if ( 0 <= shiftCount ) { + return packFloat32( 1 > 0, 0x95 - shiftCount, a< 0, 0x9C - shiftCount, a STATUS_VAR ); + } +} + /*---------------------------------------------------------------------------- | Returns the result of converting the 64-bit two's complement integer `a' | to the double-precision floating-point format. The conversion is performed @@ -1174,7 +1197,7 @@ float64 int64_to_float64( int64 a STATUS_PARAM ) { flag zSign; - if ( a == 0 ) return 0; + if ( a == 0 ) return float64_zero; if ( a == (sbits64) LIT64( 0x8000000000000000 ) ) { return packFloat64( 1, 0x43E, 0 ); } @@ -1183,6 +1206,13 @@ float64 int64_to_float64( int64 a STATUS_PARAM ) } +float64 uint64_to_float64( uint64 a STATUS_PARAM ) +{ + if ( a == 0 ) return float64_zero; + return normalizeRoundAndPackFloat64( 0, 0x43C, a STATUS_VAR ); + +} + #ifdef FLOATX80 /*---------------------------------------------------------------------------- @@ -1297,7 +1327,7 @@ int32 float32_to_int32_round_to_zero( float32 a STATUS_PARAM ) aSign = extractFloat32Sign( a ); shiftCount = aExp - 0x9E; if ( 0 <= shiftCount ) { - if ( a != 0xCF000000 ) { + if ( float32_val(a) != 0xCF000000 ) { float_raise( float_flag_invalid STATUS_VAR); if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) return 0x7FFFFFFF; } @@ -1376,7 +1406,7 @@ int64 float32_to_int64_round_to_zero( float32 a STATUS_PARAM ) aSign = extractFloat32Sign( a ); shiftCount = aExp - 0xBE; if ( 0 <= shiftCount ) { - if ( a != 0xDF000000 ) { + if ( float32_val(a) != 0xDF000000 ) { float_raise( float_flag_invalid STATUS_VAR); if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) { return LIT64( 0x7FFFFFFFFFFFFFFF ); @@ -1507,7 +1537,7 @@ float32 float32_round_to_int( float32 a STATUS_PARAM) int16 aExp; bits32 lastBitMask, roundBitsMask; int8 roundingMode; - float32 z; + bits32 z; aExp = extractFloat32Exp( a ); if ( 0x96 <= aExp ) { @@ -1517,7 +1547,7 @@ float32 float32_round_to_int( float32 a STATUS_PARAM) return a; } if ( aExp <= 0x7E ) { - if ( (bits32) ( a<<1 ) == 0 ) return a; + if ( (bits32) ( float32_val(a)<<1 ) == 0 ) return a; STATUS(float_exception_flags) |= float_flag_inexact; aSign = extractFloat32Sign( a ); switch ( STATUS(float_rounding_mode) ) { @@ -1527,29 +1557,29 @@ float32 float32_round_to_int( float32 a STATUS_PARAM) } break; case float_round_down: - return aSign ? 0xBF800000 : 0; + return make_float32(aSign ? 0xBF800000 : 0); case float_round_up: - return aSign ? 0x80000000 : 0x3F800000; + return make_float32(aSign ? 0x80000000 : 0x3F800000); } return packFloat32( aSign, 0, 0 ); } lastBitMask = 1; lastBitMask <<= 0x96 - aExp; roundBitsMask = lastBitMask - 1; - z = a; + z = float32_val(a); roundingMode = STATUS(float_rounding_mode); if ( roundingMode == float_round_nearest_even ) { z += lastBitMask>>1; if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask; } else if ( roundingMode != float_round_to_zero ) { - if ( extractFloat32Sign( z ) ^ ( roundingMode == float_round_up ) ) { + if ( extractFloat32Sign( make_float32(z) ) ^ ( roundingMode == float_round_up ) ) { z += roundBitsMask; } } z &= ~ roundBitsMask; - if ( z != a ) STATUS(float_exception_flags) |= float_flag_inexact; - return z; + if ( z != float32_val(a) ) STATUS(float_exception_flags) |= float_flag_inexact; + return make_float32(z); } @@ -1980,7 +2010,7 @@ float32 float32_sqrt( float32 a STATUS_PARAM ) aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); if ( aExp == 0xFF ) { - if ( aSig ) return propagateFloat32NaN( a, 0 STATUS_VAR ); + if ( aSig ) return propagateFloat32NaN( a, float32_zero STATUS_VAR ); if ( ! aSign ) return a; float_raise( float_flag_invalid STATUS_VAR); return float32_default_nan; @@ -1991,7 +2021,7 @@ float32 float32_sqrt( float32 a STATUS_PARAM ) return float32_default_nan; } if ( aExp == 0 ) { - if ( aSig == 0 ) return 0; + if ( aSig == 0 ) return float32_zero; normalizeFloat32Subnormal( aSig, &aExp, &aSig ); } zExp = ( ( aExp - 0x7F )>>1 ) + 0x7E; @@ -2023,7 +2053,7 @@ float32 float32_sqrt( float32 a STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float32_eq( float32 a, float32 b STATUS_PARAM ) +int float32_eq( float32 a, float32 b STATUS_PARAM ) { if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) @@ -2034,7 +2064,8 @@ flag float32_eq( float32 a, float32 b STATUS_PARAM ) } return 0; } - return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 ); + return ( float32_val(a) == float32_val(b) ) || + ( (bits32) ( ( float32_val(a) | float32_val(b) )<<1 ) == 0 ); } @@ -2045,9 +2076,10 @@ flag float32_eq( float32 a, float32 b STATUS_PARAM ) | Arithmetic. *----------------------------------------------------------------------------*/ -flag float32_le( float32 a, float32 b STATUS_PARAM ) +int float32_le( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign; + bits32 av, bv; if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) @@ -2057,8 +2089,10 @@ flag float32_le( float32 a, float32 b STATUS_PARAM ) } aSign = extractFloat32Sign( a ); bSign = extractFloat32Sign( b ); - if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 ); - return ( a == b ) || ( aSign ^ ( a < b ) ); + av = float32_val(a); + bv = float32_val(b); + if ( aSign != bSign ) return aSign || ( (bits32) ( ( av | bv )<<1 ) == 0 ); + return ( av == bv ) || ( aSign ^ ( av < bv ) ); } @@ -2068,9 +2102,10 @@ flag float32_le( float32 a, float32 b STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float32_lt( float32 a, float32 b STATUS_PARAM ) +int float32_lt( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign; + bits32 av, bv; if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) @@ -2080,8 +2115,10 @@ flag float32_lt( float32 a, float32 b STATUS_PARAM ) } aSign = extractFloat32Sign( a ); bSign = extractFloat32Sign( b ); - if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 ); - return ( a != b ) && ( aSign ^ ( a < b ) ); + av = float32_val(a); + bv = float32_val(b); + if ( aSign != bSign ) return aSign && ( (bits32) ( ( av | bv )<<1 ) != 0 ); + return ( av != bv ) && ( aSign ^ ( av < bv ) ); } @@ -2092,8 +2129,9 @@ flag float32_lt( float32 a, float32 b STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float32_eq_signaling( float32 a, float32 b STATUS_PARAM ) +int float32_eq_signaling( float32 a, float32 b STATUS_PARAM ) { + bits32 av, bv; if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) @@ -2101,7 +2139,9 @@ flag float32_eq_signaling( float32 a, float32 b STATUS_PARAM ) float_raise( float_flag_invalid STATUS_VAR); return 0; } - return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 ); + av = float32_val(a); + bv = float32_val(b); + return ( av == bv ) || ( (bits32) ( ( av | bv )<<1 ) == 0 ); } @@ -2112,9 +2152,10 @@ flag float32_eq_signaling( float32 a, float32 b STATUS_PARAM ) | IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float32_le_quiet( float32 a, float32 b STATUS_PARAM ) +int float32_le_quiet( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign; + bits32 av, bv; if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) @@ -2126,8 +2167,10 @@ flag float32_le_quiet( float32 a, float32 b STATUS_PARAM ) } aSign = extractFloat32Sign( a ); bSign = extractFloat32Sign( b ); - if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 ); - return ( a == b ) || ( aSign ^ ( a < b ) ); + av = float32_val(a); + bv = float32_val(b); + if ( aSign != bSign ) return aSign || ( (bits32) ( ( av | bv )<<1 ) == 0 ); + return ( av == bv ) || ( aSign ^ ( av < bv ) ); } @@ -2138,9 +2181,10 @@ flag float32_le_quiet( float32 a, float32 b STATUS_PARAM ) | Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float32_lt_quiet( float32 a, float32 b STATUS_PARAM ) +int float32_lt_quiet( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign; + bits32 av, bv; if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) @@ -2152,8 +2196,10 @@ flag float32_lt_quiet( float32 a, float32 b STATUS_PARAM ) } aSign = extractFloat32Sign( a ); bSign = extractFloat32Sign( b ); - if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 ); - return ( a != b ) && ( aSign ^ ( a < b ) ); + av = float32_val(a); + bv = float32_val(b); + if ( aSign != bSign ) return aSign && ( (bits32) ( ( av | bv )<<1 ) != 0 ); + return ( av != bv ) && ( aSign ^ ( av < bv ) ); } @@ -2296,7 +2342,7 @@ int64 float64_to_int64_round_to_zero( float64 a STATUS_PARAM ) shiftCount = aExp - 0x433; if ( 0 <= shiftCount ) { if ( 0x43E <= aExp ) { - if ( a != LIT64( 0xC3E0000000000000 ) ) { + if ( float64_val(a) != LIT64( 0xC3E0000000000000 ) ) { float_raise( float_flag_invalid STATUS_VAR); if ( ! aSign || ( ( aExp == 0x7FF ) @@ -2436,7 +2482,7 @@ float64 float64_round_to_int( float64 a STATUS_PARAM ) int16 aExp; bits64 lastBitMask, roundBitsMask; int8 roundingMode; - float64 z; + bits64 z; aExp = extractFloat64Exp( a ); if ( 0x433 <= aExp ) { @@ -2446,7 +2492,7 @@ float64 float64_round_to_int( float64 a STATUS_PARAM ) return a; } if ( aExp < 0x3FF ) { - if ( (bits64) ( a<<1 ) == 0 ) return a; + if ( (bits64) ( float64_val(a)<<1 ) == 0 ) return a; STATUS(float_exception_flags) |= float_flag_inexact; aSign = extractFloat64Sign( a ); switch ( STATUS(float_rounding_mode) ) { @@ -2456,33 +2502,45 @@ float64 float64_round_to_int( float64 a STATUS_PARAM ) } break; case float_round_down: - return aSign ? LIT64( 0xBFF0000000000000 ) : 0; + return make_float64(aSign ? LIT64( 0xBFF0000000000000 ) : 0); case float_round_up: - return - aSign ? LIT64( 0x8000000000000000 ) : LIT64( 0x3FF0000000000000 ); + return make_float64( + aSign ? LIT64( 0x8000000000000000 ) : LIT64( 0x3FF0000000000000 )); } return packFloat64( aSign, 0, 0 ); } lastBitMask = 1; lastBitMask <<= 0x433 - aExp; roundBitsMask = lastBitMask - 1; - z = a; + z = float64_val(a); roundingMode = STATUS(float_rounding_mode); if ( roundingMode == float_round_nearest_even ) { z += lastBitMask>>1; if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask; } else if ( roundingMode != float_round_to_zero ) { - if ( extractFloat64Sign( z ) ^ ( roundingMode == float_round_up ) ) { + if ( extractFloat64Sign( make_float64(z) ) ^ ( roundingMode == float_round_up ) ) { z += roundBitsMask; } } z &= ~ roundBitsMask; - if ( z != a ) STATUS(float_exception_flags) |= float_flag_inexact; - return z; + if ( z != float64_val(a) ) + STATUS(float_exception_flags) |= float_flag_inexact; + return make_float64(z); } +float64 float64_trunc_to_int( float64 a STATUS_PARAM) +{ + int oldmode; + float64 res; + oldmode = STATUS(float_rounding_mode); + STATUS(float_rounding_mode) = float_round_to_zero; + res = float64_round_to_int(a STATUS_VAR); + STATUS(float_rounding_mode) = oldmode; + return res; +} + /*---------------------------------------------------------------------------- | Returns the result of adding the absolute values of the double-precision | floating-point values `a' and `b'. If `zSign' is 1, the sum is negated @@ -2912,7 +2970,7 @@ float64 float64_sqrt( float64 a STATUS_PARAM ) return float64_default_nan; } if ( aExp == 0 ) { - if ( aSig == 0 ) return 0; + if ( aSig == 0 ) return float64_zero; normalizeFloat64Subnormal( aSig, &aExp, &aSig ); } zExp = ( ( aExp - 0x3FF )>>1 ) + 0x3FE; @@ -2941,8 +2999,9 @@ float64 float64_sqrt( float64 a STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float64_eq( float64 a, float64 b STATUS_PARAM ) +int float64_eq( float64 a, float64 b STATUS_PARAM ) { + bits64 av, bv; if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) @@ -2952,7 +3011,9 @@ flag float64_eq( float64 a, float64 b STATUS_PARAM ) } return 0; } - return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 ); + av = float64_val(a); + bv = float64_val(b); + return ( av == bv ) || ( (bits64) ( ( av | bv )<<1 ) == 0 ); } @@ -2963,9 +3024,10 @@ flag float64_eq( float64 a, float64 b STATUS_PARAM ) | Arithmetic. *----------------------------------------------------------------------------*/ -flag float64_le( float64 a, float64 b STATUS_PARAM ) +int float64_le( float64 a, float64 b STATUS_PARAM ) { flag aSign, bSign; + bits64 av, bv; if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) @@ -2975,8 +3037,10 @@ flag float64_le( float64 a, float64 b STATUS_PARAM ) } aSign = extractFloat64Sign( a ); bSign = extractFloat64Sign( b ); - if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 ); - return ( a == b ) || ( aSign ^ ( a < b ) ); + av = float64_val(a); + bv = float64_val(b); + if ( aSign != bSign ) return aSign || ( (bits64) ( ( av | bv )<<1 ) == 0 ); + return ( av == bv ) || ( aSign ^ ( av < bv ) ); } @@ -2986,9 +3050,10 @@ flag float64_le( float64 a, float64 b STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float64_lt( float64 a, float64 b STATUS_PARAM ) +int float64_lt( float64 a, float64 b STATUS_PARAM ) { flag aSign, bSign; + bits64 av, bv; if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) @@ -2998,8 +3063,10 @@ flag float64_lt( float64 a, float64 b STATUS_PARAM ) } aSign = extractFloat64Sign( a ); bSign = extractFloat64Sign( b ); - if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 ); - return ( a != b ) && ( aSign ^ ( a < b ) ); + av = float64_val(a); + bv = float64_val(b); + if ( aSign != bSign ) return aSign && ( (bits64) ( ( av | bv )<<1 ) != 0 ); + return ( av != bv ) && ( aSign ^ ( av < bv ) ); } @@ -3010,8 +3077,9 @@ flag float64_lt( float64 a, float64 b STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float64_eq_signaling( float64 a, float64 b STATUS_PARAM ) +int float64_eq_signaling( float64 a, float64 b STATUS_PARAM ) { + bits64 av, bv; if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) @@ -3019,7 +3087,9 @@ flag float64_eq_signaling( float64 a, float64 b STATUS_PARAM ) float_raise( float_flag_invalid STATUS_VAR); return 0; } - return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 ); + av = float64_val(a); + bv = float64_val(b); + return ( av == bv ) || ( (bits64) ( ( av | bv )<<1 ) == 0 ); } @@ -3030,9 +3100,10 @@ flag float64_eq_signaling( float64 a, float64 b STATUS_PARAM ) | IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float64_le_quiet( float64 a, float64 b STATUS_PARAM ) +int float64_le_quiet( float64 a, float64 b STATUS_PARAM ) { flag aSign, bSign; + bits64 av, bv; if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) @@ -3044,8 +3115,10 @@ flag float64_le_quiet( float64 a, float64 b STATUS_PARAM ) } aSign = extractFloat64Sign( a ); bSign = extractFloat64Sign( b ); - if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 ); - return ( a == b ) || ( aSign ^ ( a < b ) ); + av = float64_val(a); + bv = float64_val(b); + if ( aSign != bSign ) return aSign || ( (bits64) ( ( av | bv )<<1 ) == 0 ); + return ( av == bv ) || ( aSign ^ ( av < bv ) ); } @@ -3056,9 +3129,10 @@ flag float64_le_quiet( float64 a, float64 b STATUS_PARAM ) | Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float64_lt_quiet( float64 a, float64 b STATUS_PARAM ) +int float64_lt_quiet( float64 a, float64 b STATUS_PARAM ) { flag aSign, bSign; + bits64 av, bv; if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) @@ -3070,8 +3144,10 @@ flag float64_lt_quiet( float64 a, float64 b STATUS_PARAM ) } aSign = extractFloat64Sign( a ); bSign = extractFloat64Sign( b ); - if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 ); - return ( a != b ) && ( aSign ^ ( a < b ) ); + av = float64_val(a); + bv = float64_val(b); + if ( aSign != bSign ) return aSign && ( (bits64) ( ( av | bv )<<1 ) != 0 ); + return ( av != bv ) && ( aSign ^ ( av < bv ) ); } @@ -3879,7 +3955,7 @@ floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM ) | Arithmetic. *----------------------------------------------------------------------------*/ -flag floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM ) +int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM ) { if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) @@ -3909,7 +3985,7 @@ flag floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM ) | Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag floatx80_le( floatx80 a, floatx80 b STATUS_PARAM ) +int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM ) { flag aSign, bSign; @@ -3942,7 +4018,7 @@ flag floatx80_le( floatx80 a, floatx80 b STATUS_PARAM ) | Arithmetic. *----------------------------------------------------------------------------*/ -flag floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM ) +int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM ) { flag aSign, bSign; @@ -3975,7 +4051,7 @@ flag floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM ) +int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM ) { if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) @@ -4002,7 +4078,7 @@ flag floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM ) | to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM ) +int floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM ) { flag aSign, bSign; @@ -4038,7 +4114,7 @@ flag floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM ) | IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM ) +int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM ) { flag aSign, bSign; @@ -4911,7 +4987,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, (bits64*)&sigMean0, &sigMean1 ); + aSig0, aSig1, alternateASig0, alternateASig1, &sigMean0, &sigMean1 ); if ( ( sigMean0 < 0 ) || ( ( ( sigMean0 | sigMean1 ) == 0 ) && ( q & 1 ) ) ) { aSig0 = alternateASig0; @@ -4999,7 +5075,7 @@ float128 float128_sqrt( float128 a STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float128_eq( float128 a, float128 b STATUS_PARAM ) +int float128_eq( float128 a, float128 b STATUS_PARAM ) { if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) @@ -5029,7 +5105,7 @@ flag float128_eq( float128 a, float128 b STATUS_PARAM ) | Arithmetic. *----------------------------------------------------------------------------*/ -flag float128_le( float128 a, float128 b STATUS_PARAM ) +int float128_le( float128 a, float128 b STATUS_PARAM ) { flag aSign, bSign; @@ -5061,7 +5137,7 @@ flag float128_le( float128 a, float128 b STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float128_lt( float128 a, float128 b STATUS_PARAM ) +int float128_lt( float128 a, float128 b STATUS_PARAM ) { flag aSign, bSign; @@ -5094,7 +5170,7 @@ flag float128_lt( float128 a, float128 b STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float128_eq_signaling( float128 a, float128 b STATUS_PARAM ) +int float128_eq_signaling( float128 a, float128 b STATUS_PARAM ) { if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) @@ -5121,7 +5197,7 @@ flag float128_eq_signaling( float128 a, float128 b STATUS_PARAM ) | IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float128_le_quiet( float128 a, float128 b STATUS_PARAM ) +int float128_le_quiet( float128 a, float128 b STATUS_PARAM ) { flag aSign, bSign; @@ -5157,7 +5233,7 @@ flag float128_le_quiet( float128 a, float128 b STATUS_PARAM ) | Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float128_lt_quiet( float128 a, float128 b STATUS_PARAM ) +int float128_lt_quiet( float128 a, float128 b STATUS_PARAM ) { flag aSign, bSign; @@ -5271,11 +5347,35 @@ unsigned int float64_to_uint32_round_to_zero( float64 a STATUS_PARAM ) return res; } +/* FIXME: This looks broken. */ +uint64_t float64_to_uint64 (float64 a STATUS_PARAM) +{ + int64_t v; + + v = float64_val(int64_to_float64(INT64_MIN STATUS_VAR)); + v += float64_val(a); + v = float64_to_int64(make_float64(v) STATUS_VAR); + + return v - INT64_MIN; +} + +uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM) +{ + int64_t v; + + v = float64_val(int64_to_float64(INT64_MIN STATUS_VAR)); + v += float64_val(a); + v = float64_to_int64_round_to_zero(make_float64(v) STATUS_VAR); + + return v - INT64_MIN; +} + #define COMPARE(s, nan_exp) \ -INLINE char float ## s ## _compare_internal( float ## s a, float ## s b, \ +INLINE int float ## s ## _compare_internal( float ## s a, float ## s b, \ int is_quiet STATUS_PARAM ) \ { \ flag aSign, bSign; \ + bits ## s av, bv; \ \ if (( ( extractFloat ## s ## Exp( a ) == nan_exp ) && \ extractFloat ## s ## Frac( a ) ) || \ @@ -5290,31 +5390,152 @@ INLINE char float ## s ## _compare_internal( float ## s a, float ## s b, \ } \ aSign = extractFloat ## s ## Sign( a ); \ bSign = extractFloat ## s ## Sign( b ); \ + av = float ## s ## _val(a); \ + bv = float ## s ## _val(b); \ if ( aSign != bSign ) { \ - if ( (bits ## s) ( ( a | b )<<1 ) == 0 ) { \ + if ( (bits ## s) ( ( av | bv )<<1 ) == 0 ) { \ /* zero case */ \ return float_relation_equal; \ } else { \ return 1 - (2 * aSign); \ } \ } else { \ - if (a == b) { \ + if (av == bv) { \ return float_relation_equal; \ } else { \ - return 1 - 2 * (aSign ^ ( a < b )); \ + return 1 - 2 * (aSign ^ ( av < bv )); \ } \ } \ } \ \ -char float ## s ## _compare( float ## s a, float ## s b STATUS_PARAM ) \ +int float ## s ## _compare( float ## s a, float ## s b STATUS_PARAM ) \ { \ return float ## s ## _compare_internal(a, b, 0 STATUS_VAR); \ } \ \ -char float ## s ## _compare_quiet( float ## s a, float ## s b STATUS_PARAM ) \ +int float ## s ## _compare_quiet( float ## s a, float ## s b STATUS_PARAM ) \ { \ return float ## s ## _compare_internal(a, b, 1 STATUS_VAR); \ } COMPARE(32, 0xff) COMPARE(64, 0x7ff) + +INLINE int float128_compare_internal( float128 a, float128 b, + int is_quiet STATUS_PARAM ) +{ + flag aSign, bSign; + + if (( ( extractFloat128Exp( a ) == 0x7fff ) && + ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) || + ( ( extractFloat128Exp( b ) == 0x7fff ) && + ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )) { + if (!is_quiet || + float128_is_signaling_nan( a ) || + float128_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return float_relation_unordered; + } + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign != bSign ) { + if ( ( ( ( a.high | b.high )<<1 ) | a.low | b.low ) == 0 ) { + /* zero case */ + return float_relation_equal; + } else { + return 1 - (2 * aSign); + } + } else { + if (a.low == b.low && a.high == b.high) { + return float_relation_equal; + } else { + return 1 - 2 * (aSign ^ ( lt128( a.high, a.low, b.high, b.low ) )); + } + } +} + +int float128_compare( float128 a, float128 b STATUS_PARAM ) +{ + return float128_compare_internal(a, b, 0 STATUS_VAR); +} + +int float128_compare_quiet( float128 a, float128 b STATUS_PARAM ) +{ + return float128_compare_internal(a, b, 1 STATUS_VAR); +} + +/* Multiply A by 2 raised to the power N. */ +float32 float32_scalbn( float32 a, int n STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits32 aSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + + if ( aExp == 0xFF ) { + return a; + } + aExp += n; + return roundAndPackFloat32( aSign, aExp, aSig STATUS_VAR ); +} + +float64 float64_scalbn( float64 a, int n STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits64 aSig; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + + if ( aExp == 0x7FF ) { + return a; + } + aExp += n; + return roundAndPackFloat64( aSign, aExp, aSig STATUS_VAR ); +} + +#ifdef FLOATX80 +floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits64 aSig; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + + if ( aExp == 0x7FF ) { + return a; + } + aExp += n; + return roundAndPackFloatx80( STATUS(floatx80_rounding_precision), + aSign, aExp, aSig, 0 STATUS_VAR ); +} +#endif + +#ifdef FLOAT128 +float128 float128_scalbn( float128 a, int n STATUS_PARAM ) +{ + flag aSign; + int32 aExp; + bits64 aSig0, aSig1; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + if ( aExp == 0x7FFF ) { + return a; + } + aExp += n; + return roundAndPackFloat128( aSign, aExp, aSig0, aSig1, 0 STATUS_VAR ); + +} +#endif diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 44c29f1..5f95d06 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -32,6 +32,10 @@ these four paragraphs for those parts of this code that are retained. #ifndef SOFTFLOAT_H #define SOFTFLOAT_H +#if defined(HOST_SOLARIS) && defined(NEEDS_LIBSUNMATH) +#include +#endif + #include #include "config.h" @@ -43,11 +47,11 @@ these four paragraphs for those parts of this code that are retained. | implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed | to the same as `int'. *----------------------------------------------------------------------------*/ -typedef char flag; +typedef uint8_t flag; typedef uint8_t uint8; typedef int8_t int8; -typedef uint16_t uint16; -typedef int16_t int16; +typedef int uint16; +typedef int int16; typedef unsigned int uint32; typedef signed int int32; typedef uint64_t uint64; @@ -107,8 +111,31 @@ enum { /*---------------------------------------------------------------------------- | Software IEC/IEEE floating-point types. *----------------------------------------------------------------------------*/ +/* Use structures for soft-float types. This prevents accidentally mixing + them with native int/float types. A sufficiently clever compiler and + sane ABI should be able to see though these structs. However + x86/gcc 3.x seems to struggle a bit, so leave them disabled by default. */ +//#define USE_SOFTFLOAT_STRUCT_TYPES +#ifdef USE_SOFTFLOAT_STRUCT_TYPES +typedef struct { + uint32_t v; +} float32; +/* The cast ensures an error if the wrong type is passed. */ +#define float32_val(x) (((float32)(x)).v) +#define make_float32(x) __extension__ ({ float32 f32_val = {x}; f32_val; }) +typedef struct { + uint64_t v; +} float64; +#define float64_val(x) (((float64)(x)).v) +#define make_float64(x) __extension__ ({ float64 f64_val = {x}; f64_val; }) +#else typedef uint32_t float32; typedef uint64_t float64; +#define float32_val(x) (x) +#define float64_val(x) (x) +#define make_float32(x) (x) +#define make_float64(x) (x) +#endif #ifdef FLOATX80 typedef struct { uint64_t low; @@ -193,7 +220,9 @@ floatx80 int32_to_floatx80( int STATUS_PARAM ); float128 int32_to_float128( int STATUS_PARAM ); #endif float32 int64_to_float32( int64_t STATUS_PARAM ); +float32 uint64_to_float32( uint64_t STATUS_PARAM ); float64 int64_to_float64( int64_t STATUS_PARAM ); +float64 uint64_to_float64( uint64_t STATUS_PARAM ); #ifdef FLOATX80 floatx80 int64_to_floatx80( int64_t STATUS_PARAM ); #endif @@ -228,26 +257,30 @@ 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 ); -char float32_eq( float32, float32 STATUS_PARAM ); -char float32_le( float32, float32 STATUS_PARAM ); -char float32_lt( float32, float32 STATUS_PARAM ); -char float32_eq_signaling( float32, float32 STATUS_PARAM ); -char float32_le_quiet( float32, float32 STATUS_PARAM ); -char float32_lt_quiet( float32, float32 STATUS_PARAM ); -char float32_compare( float32, float32 STATUS_PARAM ); -char float32_compare_quiet( float32, float32 STATUS_PARAM ); -char float32_is_signaling_nan( float32 ); +int float32_eq( float32, float32 STATUS_PARAM ); +int float32_le( float32, float32 STATUS_PARAM ); +int float32_lt( float32, float32 STATUS_PARAM ); +int float32_eq_signaling( float32, float32 STATUS_PARAM ); +int float32_le_quiet( float32, float32 STATUS_PARAM ); +int float32_lt_quiet( float32, float32 STATUS_PARAM ); +int float32_compare( float32, float32 STATUS_PARAM ); +int float32_compare_quiet( float32, float32 STATUS_PARAM ); +int float32_is_nan( float32 ); +int float32_is_signaling_nan( float32 ); +float32 float32_scalbn( float32, int STATUS_PARAM ); INLINE float32 float32_abs(float32 a) { - return a & 0x7fffffff; + return make_float32(float32_val(a) & 0x7fffffff); } INLINE float32 float32_chs(float32 a) { - return a ^ 0x80000000; + return make_float32(float32_val(a) ^ 0x80000000); } +#define float32_zero make_float32(0) + /*---------------------------------------------------------------------------- | Software IEC/IEEE double-precision conversion routines. *----------------------------------------------------------------------------*/ @@ -257,6 +290,8 @@ unsigned int float64_to_uint32( float64 STATUS_PARAM ); unsigned int float64_to_uint32_round_to_zero( float64 STATUS_PARAM ); int64_t float64_to_int64( float64 STATUS_PARAM ); int64_t float64_to_int64_round_to_zero( float64 STATUS_PARAM ); +uint64_t float64_to_uint64 (float64 a STATUS_PARAM); +uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM); float32 float64_to_float32( float64 STATUS_PARAM ); #ifdef FLOATX80 floatx80 float64_to_floatx80( float64 STATUS_PARAM ); @@ -269,32 +304,37 @@ float128 float64_to_float128( float64 STATUS_PARAM ); | Software IEC/IEEE double-precision operations. *----------------------------------------------------------------------------*/ float64 float64_round_to_int( float64 STATUS_PARAM ); +float64 float64_trunc_to_int( float64 STATUS_PARAM ); float64 float64_add( float64, float64 STATUS_PARAM ); float64 float64_sub( float64, float64 STATUS_PARAM ); 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 ); -char float64_eq( float64, float64 STATUS_PARAM ); -char float64_le( float64, float64 STATUS_PARAM ); -char float64_lt( float64, float64 STATUS_PARAM ); -char float64_eq_signaling( float64, float64 STATUS_PARAM ); -char float64_le_quiet( float64, float64 STATUS_PARAM ); -char float64_lt_quiet( float64, float64 STATUS_PARAM ); -char float64_compare( float64, float64 STATUS_PARAM ); -char float64_compare_quiet( float64, float64 STATUS_PARAM ); -char float64_is_signaling_nan( float64 ); +int float64_eq( float64, float64 STATUS_PARAM ); +int float64_le( float64, float64 STATUS_PARAM ); +int float64_lt( float64, float64 STATUS_PARAM ); +int float64_eq_signaling( float64, float64 STATUS_PARAM ); +int float64_le_quiet( float64, float64 STATUS_PARAM ); +int float64_lt_quiet( float64, float64 STATUS_PARAM ); +int float64_compare( float64, float64 STATUS_PARAM ); +int float64_compare_quiet( float64, float64 STATUS_PARAM ); +int float64_is_nan( float64 a ); +int float64_is_signaling_nan( float64 ); +float64 float64_scalbn( float64, int STATUS_PARAM ); INLINE float64 float64_abs(float64 a) { - return a & 0x7fffffffffffffffLL; + return make_float64(float64_val(a) & 0x7fffffffffffffffLL); } INLINE float64 float64_chs(float64 a) { - return a ^ 0x8000000000000000LL; + return make_float64(float64_val(a) ^ 0x8000000000000000LL); } +#define float64_zero make_float64(0) + #ifdef FLOATX80 /*---------------------------------------------------------------------------- @@ -320,13 +360,15 @@ floatx80 floatx80_mul( floatx80, floatx80 STATUS_PARAM ); floatx80 floatx80_div( floatx80, floatx80 STATUS_PARAM ); floatx80 floatx80_rem( floatx80, floatx80 STATUS_PARAM ); floatx80 floatx80_sqrt( floatx80 STATUS_PARAM ); -char floatx80_eq( floatx80, floatx80 STATUS_PARAM ); -char floatx80_le( floatx80, floatx80 STATUS_PARAM ); -char floatx80_lt( floatx80, floatx80 STATUS_PARAM ); -char floatx80_eq_signaling( floatx80, floatx80 STATUS_PARAM ); -char floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM ); -char floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM ); -char floatx80_is_signaling_nan( floatx80 ); +int floatx80_eq( floatx80, floatx80 STATUS_PARAM ); +int floatx80_le( floatx80, floatx80 STATUS_PARAM ); +int floatx80_lt( floatx80, floatx80 STATUS_PARAM ); +int floatx80_eq_signaling( floatx80, floatx80 STATUS_PARAM ); +int floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM ); +int floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM ); +int floatx80_is_nan( floatx80 ); +int floatx80_is_signaling_nan( floatx80 ); +floatx80 floatx80_scalbn( floatx80, int STATUS_PARAM ); INLINE floatx80 floatx80_abs(floatx80 a) { @@ -367,13 +409,17 @@ float128 float128_mul( float128, float128 STATUS_PARAM ); float128 float128_div( float128, float128 STATUS_PARAM ); float128 float128_rem( float128, float128 STATUS_PARAM ); float128 float128_sqrt( float128 STATUS_PARAM ); -char float128_eq( float128, float128 STATUS_PARAM ); -char float128_le( float128, float128 STATUS_PARAM ); -char float128_lt( float128, float128 STATUS_PARAM ); -char float128_eq_signaling( float128, float128 STATUS_PARAM ); -char float128_le_quiet( float128, float128 STATUS_PARAM ); -char float128_lt_quiet( float128, float128 STATUS_PARAM ); -char float128_is_signaling_nan( float128 ); +int float128_eq( float128, float128 STATUS_PARAM ); +int float128_le( float128, float128 STATUS_PARAM ); +int float128_lt( float128, float128 STATUS_PARAM ); +int float128_eq_signaling( float128, float128 STATUS_PARAM ); +int float128_le_quiet( float128, float128 STATUS_PARAM ); +int float128_lt_quiet( float128, float128 STATUS_PARAM ); +int float128_compare( float128, float128 STATUS_PARAM ); +int float128_compare_quiet( float128, float128 STATUS_PARAM ); +int float128_is_nan( float128 ); +int float128_is_signaling_nan( float128 ); +float128 float128_scalbn( float128, int STATUS_PARAM ); INLINE float128 float128_abs(float128 a) { -- cgit v1.1