Home | History | Annotate | Download | only in fpu
      1 /* Native implementation of soft float functions. Only a single status
      2    context is supported */
      3 #include "softfloat.h"
      4 #include <math.h>
      5 #if defined(CONFIG_SOLARIS)
      6 #include <fenv.h>
      7 #endif
      8 
      9 void set_float_rounding_mode(int val STATUS_PARAM)
     10 {
     11     STATUS(float_rounding_mode) = val;
     12 #if (defined(CONFIG_BSD) && !defined(__APPLE__) && !defined(__GLIBC__)) || \
     13     (defined(CONFIG_SOLARIS) && CONFIG_SOLARIS_VERSION < 10)
     14     fpsetround(val);
     15 #else
     16     fesetround(val);
     17 #endif
     18 }
     19 
     20 #ifdef FLOATX80
     21 void set_floatx80_rounding_precision(int val STATUS_PARAM)
     22 {
     23     STATUS(floatx80_rounding_precision) = val;
     24 }
     25 #endif
     26 
     27 #if defined(CONFIG_BSD) || \
     28     (defined(CONFIG_SOLARIS) && CONFIG_SOLARIS_VERSION < 10)
     29 #define lrint(d)		((int32_t)rint(d))
     30 #define llrint(d)		((int64_t)rint(d))
     31 #define lrintf(f)		((int32_t)rint(f))
     32 #define llrintf(f)		((int64_t)rint(f))
     33 #define sqrtf(f)		((float)sqrt(f))
     34 #define remainderf(fa, fb)	((float)remainder(fa, fb))
     35 #define rintf(f)		((float)rint(f))
     36 #if !defined(__sparc__) && \
     37     (defined(CONFIG_SOLARIS) && CONFIG_SOLARIS_VERSION < 10)
     38 extern long double rintl(long double);
     39 extern long double scalbnl(long double, int);
     40 
     41 long long
     42 llrintl(long double x) {
     43 	return ((long long) rintl(x));
     44 }
     45 
     46 long
     47 lrintl(long double x) {
     48 	return ((long) rintl(x));
     49 }
     50 
     51 long double
     52 ldexpl(long double x, int n) {
     53 	return (scalbnl(x, n));
     54 }
     55 #endif
     56 #endif
     57 
     58 #if defined(_ARCH_PPC)
     59 
     60 /* correct (but slow) PowerPC rint() (glibc version is incorrect) */
     61 static double qemu_rint(double x)
     62 {
     63     double y = 4503599627370496.0;
     64     if (fabs(x) >= y)
     65         return x;
     66     if (x < 0)
     67         y = -y;
     68     y = (x + y) - y;
     69     if (y == 0.0)
     70         y = copysign(y, x);
     71     return y;
     72 }
     73 
     74 #define rint qemu_rint
     75 #endif
     76 
     77 /*----------------------------------------------------------------------------
     78 | Software IEC/IEEE integer-to-floating-point conversion routines.
     79 *----------------------------------------------------------------------------*/
     80 float32 int32_to_float32(int v STATUS_PARAM)
     81 {
     82     return (float32)v;
     83 }
     84 
     85 float32 uint32_to_float32(unsigned int v STATUS_PARAM)
     86 {
     87     return (float32)v;
     88 }
     89 
     90 float64 int32_to_float64(int v STATUS_PARAM)
     91 {
     92     return (float64)v;
     93 }
     94 
     95 float64 uint32_to_float64(unsigned int v STATUS_PARAM)
     96 {
     97     return (float64)v;
     98 }
     99 
    100 #ifdef FLOATX80
    101 floatx80 int32_to_floatx80(int v STATUS_PARAM)
    102 {
    103     return (floatx80)v;
    104 }
    105 #endif
    106 float32 int64_to_float32( int64_t v STATUS_PARAM)
    107 {
    108     return (float32)v;
    109 }
    110 float32 uint64_to_float32( uint64_t v STATUS_PARAM)
    111 {
    112     return (float32)v;
    113 }
    114 float64 int64_to_float64( int64_t v STATUS_PARAM)
    115 {
    116     return (float64)v;
    117 }
    118 float64 uint64_to_float64( uint64_t v STATUS_PARAM)
    119 {
    120     return (float64)v;
    121 }
    122 #ifdef FLOATX80
    123 floatx80 int64_to_floatx80( int64_t v STATUS_PARAM)
    124 {
    125     return (floatx80)v;
    126 }
    127 #endif
    128 
    129 /* XXX: this code implements the x86 behaviour, not the IEEE one.  */
    130 #if HOST_LONG_BITS == 32
    131 static inline int long_to_int32(long a)
    132 {
    133     return a;
    134 }
    135 #else
    136 static inline int long_to_int32(long a)
    137 {
    138     if (a != (int32_t)a)
    139         a = 0x80000000;
    140     return a;
    141 }
    142 #endif
    143 
    144 /*----------------------------------------------------------------------------
    145 | Software IEC/IEEE single-precision conversion routines.
    146 *----------------------------------------------------------------------------*/
    147 int float32_to_int32( float32 a STATUS_PARAM)
    148 {
    149     return long_to_int32(lrintf(a));
    150 }
    151 int float32_to_int32_round_to_zero( float32 a STATUS_PARAM)
    152 {
    153     return (int)a;
    154 }
    155 int64_t float32_to_int64( float32 a STATUS_PARAM)
    156 {
    157     return llrintf(a);
    158 }
    159 
    160 int64_t float32_to_int64_round_to_zero( float32 a STATUS_PARAM)
    161 {
    162     return (int64_t)a;
    163 }
    164 
    165 float64 float32_to_float64( float32 a STATUS_PARAM)
    166 {
    167     return a;
    168 }
    169 #ifdef FLOATX80
    170 floatx80 float32_to_floatx80( float32 a STATUS_PARAM)
    171 {
    172     return a;
    173 }
    174 #endif
    175 
    176 unsigned int float32_to_uint32( float32 a STATUS_PARAM)
    177 {
    178     int64_t v;
    179     unsigned int res;
    180 
    181     v = llrintf(a);
    182     if (v < 0) {
    183         res = 0;
    184     } else if (v > 0xffffffff) {
    185         res = 0xffffffff;
    186     } else {
    187         res = v;
    188     }
    189     return res;
    190 }
    191 unsigned int float32_to_uint32_round_to_zero( float32 a STATUS_PARAM)
    192 {
    193     int64_t v;
    194     unsigned int res;
    195 
    196     v = (int64_t)a;
    197     if (v < 0) {
    198         res = 0;
    199     } else if (v > 0xffffffff) {
    200         res = 0xffffffff;
    201     } else {
    202         res = v;
    203     }
    204     return res;
    205 }
    206 
    207 /*----------------------------------------------------------------------------
    208 | Software IEC/IEEE single-precision operations.
    209 *----------------------------------------------------------------------------*/
    210 float32 float32_round_to_int( float32 a STATUS_PARAM)
    211 {
    212     return rintf(a);
    213 }
    214 
    215 float32 float32_rem( float32 a, float32 b STATUS_PARAM)
    216 {
    217     return remainderf(a, b);
    218 }
    219 
    220 float32 float32_sqrt( float32 a STATUS_PARAM)
    221 {
    222     return sqrtf(a);
    223 }
    224 int float32_compare( float32 a, float32 b STATUS_PARAM )
    225 {
    226     if (a < b) {
    227         return float_relation_less;
    228     } else if (a == b) {
    229         return float_relation_equal;
    230     } else if (a > b) {
    231         return float_relation_greater;
    232     } else {
    233         return float_relation_unordered;
    234     }
    235 }
    236 int float32_compare_quiet( float32 a, float32 b STATUS_PARAM )
    237 {
    238     if (isless(a, b)) {
    239         return float_relation_less;
    240     } else if (a == b) {
    241         return float_relation_equal;
    242     } else if (isgreater(a, b)) {
    243         return float_relation_greater;
    244     } else {
    245         return float_relation_unordered;
    246     }
    247 }
    248 int float32_is_signaling_nan( float32 a1)
    249 {
    250     float32u u;
    251     uint32_t a;
    252     u.f = a1;
    253     a = u.i;
    254     return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
    255 }
    256 
    257 int float32_is_quiet_nan( float32 a1 )
    258 {
    259     float32u u;
    260     uint64_t a;
    261     u.f = a1;
    262     a = u.i;
    263     return ( 0xFF800000 < ( a<<1 ) );
    264 }
    265 
    266 int float32_is_any_nan( float32 a1 )
    267 {
    268     float32u u;
    269     uint32_t a;
    270     u.f = a1;
    271     a = u.i;
    272     return (a & ~(1 << 31)) > 0x7f800000U;
    273 }
    274 
    275 /*----------------------------------------------------------------------------
    276 | Software IEC/IEEE double-precision conversion routines.
    277 *----------------------------------------------------------------------------*/
    278 int float64_to_int32( float64 a STATUS_PARAM)
    279 {
    280     return long_to_int32(lrint(a));
    281 }
    282 int float64_to_int32_round_to_zero( float64 a STATUS_PARAM)
    283 {
    284     return (int)a;
    285 }
    286 int64_t float64_to_int64( float64 a STATUS_PARAM)
    287 {
    288     return llrint(a);
    289 }
    290 int64_t float64_to_int64_round_to_zero( float64 a STATUS_PARAM)
    291 {
    292     return (int64_t)a;
    293 }
    294 float32 float64_to_float32( float64 a STATUS_PARAM)
    295 {
    296     return a;
    297 }
    298 #ifdef FLOATX80
    299 floatx80 float64_to_floatx80( float64 a STATUS_PARAM)
    300 {
    301     return a;
    302 }
    303 #endif
    304 #ifdef FLOAT128
    305 float128 float64_to_float128( float64 a STATUS_PARAM)
    306 {
    307     return a;
    308 }
    309 #endif
    310 
    311 unsigned int float64_to_uint32( float64 a STATUS_PARAM)
    312 {
    313     int64_t v;
    314     unsigned int res;
    315 
    316     v = llrint(a);
    317     if (v < 0) {
    318         res = 0;
    319     } else if (v > 0xffffffff) {
    320         res = 0xffffffff;
    321     } else {
    322         res = v;
    323     }
    324     return res;
    325 }
    326 unsigned int float64_to_uint32_round_to_zero( float64 a STATUS_PARAM)
    327 {
    328     int64_t v;
    329     unsigned int res;
    330 
    331     v = (int64_t)a;
    332     if (v < 0) {
    333         res = 0;
    334     } else if (v > 0xffffffff) {
    335         res = 0xffffffff;
    336     } else {
    337         res = v;
    338     }
    339     return res;
    340 }
    341 uint64_t float64_to_uint64 (float64 a STATUS_PARAM)
    342 {
    343     int64_t v;
    344 
    345     v = llrint(a + (float64)INT64_MIN);
    346 
    347     return v - INT64_MIN;
    348 }
    349 uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM)
    350 {
    351     int64_t v;
    352 
    353     v = (int64_t)(a + (float64)INT64_MIN);
    354 
    355     return v - INT64_MIN;
    356 }
    357 
    358 /*----------------------------------------------------------------------------
    359 | Software IEC/IEEE double-precision operations.
    360 *----------------------------------------------------------------------------*/
    361 #if defined(__sun__) && \
    362     (defined(CONFIG_SOLARIS) && CONFIG_SOLARIS_VERSION < 10)
    363 static inline float64 trunc(float64 x)
    364 {
    365     return x < 0 ? -floor(-x) : floor(x);
    366 }
    367 #endif
    368 float64 float64_trunc_to_int( float64 a STATUS_PARAM )
    369 {
    370     return trunc(a);
    371 }
    372 
    373 float64 float64_round_to_int( float64 a STATUS_PARAM )
    374 {
    375     return rint(a);
    376 }
    377 
    378 float64 float64_rem( float64 a, float64 b STATUS_PARAM)
    379 {
    380     return remainder(a, b);
    381 }
    382 
    383 float64 float64_sqrt( float64 a STATUS_PARAM)
    384 {
    385     return sqrt(a);
    386 }
    387 int float64_compare( float64 a, float64 b STATUS_PARAM )
    388 {
    389     if (a < b) {
    390         return float_relation_less;
    391     } else if (a == b) {
    392         return float_relation_equal;
    393     } else if (a > b) {
    394         return float_relation_greater;
    395     } else {
    396         return float_relation_unordered;
    397     }
    398 }
    399 int float64_compare_quiet( float64 a, float64 b STATUS_PARAM )
    400 {
    401     if (isless(a, b)) {
    402         return float_relation_less;
    403     } else if (a == b) {
    404         return float_relation_equal;
    405     } else if (isgreater(a, b)) {
    406         return float_relation_greater;
    407     } else {
    408         return float_relation_unordered;
    409     }
    410 }
    411 int float64_is_signaling_nan( float64 a1)
    412 {
    413     float64u u;
    414     uint64_t a;
    415     u.f = a1;
    416     a = u.i;
    417     return
    418            ( ( ( a>>51 ) & 0xFFF ) == 0xFFE )
    419         && ( a & LIT64( 0x0007FFFFFFFFFFFF ) );
    420 
    421 }
    422 
    423 int float64_is_quiet_nan( float64 a1 )
    424 {
    425     float64u u;
    426     uint64_t a;
    427     u.f = a1;
    428     a = u.i;
    429 
    430     return ( LIT64( 0xFFF0000000000000 ) < (uint64_t) ( a<<1 ) );
    431 
    432 }
    433 
    434 int float64_is_any_nan( float64 a1 )
    435 {
    436     float64u u;
    437     uint64_t a;
    438     u.f = a1;
    439     a = u.i;
    440 
    441     return (a & ~(1ULL << 63)) > LIT64 (0x7FF0000000000000 );
    442 }
    443 
    444 #ifdef FLOATX80
    445 
    446 /*----------------------------------------------------------------------------
    447 | Software IEC/IEEE extended double-precision conversion routines.
    448 *----------------------------------------------------------------------------*/
    449 int floatx80_to_int32( floatx80 a STATUS_PARAM)
    450 {
    451     return long_to_int32(lrintl(a));
    452 }
    453 int floatx80_to_int32_round_to_zero( floatx80 a STATUS_PARAM)
    454 {
    455     return (int)a;
    456 }
    457 int64_t floatx80_to_int64( floatx80 a STATUS_PARAM)
    458 {
    459     return llrintl(a);
    460 }
    461 int64_t floatx80_to_int64_round_to_zero( floatx80 a STATUS_PARAM)
    462 {
    463     return (int64_t)a;
    464 }
    465 float32 floatx80_to_float32( floatx80 a STATUS_PARAM)
    466 {
    467     return a;
    468 }
    469 float64 floatx80_to_float64( floatx80 a STATUS_PARAM)
    470 {
    471     return a;
    472 }
    473 
    474 /*----------------------------------------------------------------------------
    475 | Software IEC/IEEE extended double-precision operations.
    476 *----------------------------------------------------------------------------*/
    477 floatx80 floatx80_round_to_int( floatx80 a STATUS_PARAM)
    478 {
    479     return rintl(a);
    480 }
    481 floatx80 floatx80_rem( floatx80 a, floatx80 b STATUS_PARAM)
    482 {
    483     return remainderl(a, b);
    484 }
    485 floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM)
    486 {
    487     return sqrtl(a);
    488 }
    489 int floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM )
    490 {
    491     if (a < b) {
    492         return float_relation_less;
    493     } else if (a == b) {
    494         return float_relation_equal;
    495     } else if (a > b) {
    496         return float_relation_greater;
    497     } else {
    498         return float_relation_unordered;
    499     }
    500 }
    501 int floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM )
    502 {
    503     if (isless(a, b)) {
    504         return float_relation_less;
    505     } else if (a == b) {
    506         return float_relation_equal;
    507     } else if (isgreater(a, b)) {
    508         return float_relation_greater;
    509     } else {
    510         return float_relation_unordered;
    511     }
    512 }
    513 int floatx80_is_signaling_nan( floatx80 a1)
    514 {
    515     floatx80u u;
    516     uint64_t aLow;
    517     u.f = a1;
    518 
    519     aLow = u.i.low & ~ LIT64( 0x4000000000000000 );
    520     return
    521            ( ( u.i.high & 0x7FFF ) == 0x7FFF )
    522         && (uint64_t) ( aLow<<1 )
    523         && ( u.i.low == aLow );
    524 }
    525 
    526 int floatx80_is_quiet_nan( floatx80 a1 )
    527 {
    528     floatx80u u;
    529     u.f = a1;
    530     return ( ( u.i.high & 0x7FFF ) == 0x7FFF ) && (uint64_t) ( u.i.low<<1 );
    531 }
    532 
    533 int floatx80_is_any_nan( floatx80 a1 )
    534 {
    535     floatx80u u;
    536     u.f = a1;
    537     return ((u.i.high & 0x7FFF) == 0x7FFF) && ( u.i.low<<1 );
    538 }
    539 
    540 #endif
    541