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_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 /*----------------------------------------------------------------------------
    267 | Software IEC/IEEE double-precision conversion routines.
    268 *----------------------------------------------------------------------------*/
    269 int float64_to_int32( float64 a STATUS_PARAM)
    270 {
    271     return long_to_int32(lrint(a));
    272 }
    273 int float64_to_int32_round_to_zero( float64 a STATUS_PARAM)
    274 {
    275     return (int)a;
    276 }
    277 int64_t float64_to_int64( float64 a STATUS_PARAM)
    278 {
    279     return llrint(a);
    280 }
    281 int64_t float64_to_int64_round_to_zero( float64 a STATUS_PARAM)
    282 {
    283     return (int64_t)a;
    284 }
    285 float32 float64_to_float32( float64 a STATUS_PARAM)
    286 {
    287     return a;
    288 }
    289 #ifdef FLOATX80
    290 floatx80 float64_to_floatx80( float64 a STATUS_PARAM)
    291 {
    292     return a;
    293 }
    294 #endif
    295 #ifdef FLOAT128
    296 float128 float64_to_float128( float64 a STATUS_PARAM)
    297 {
    298     return a;
    299 }
    300 #endif
    301 
    302 unsigned int float64_to_uint32( float64 a STATUS_PARAM)
    303 {
    304     int64_t v;
    305     unsigned int res;
    306 
    307     v = llrint(a);
    308     if (v < 0) {
    309         res = 0;
    310     } else if (v > 0xffffffff) {
    311         res = 0xffffffff;
    312     } else {
    313         res = v;
    314     }
    315     return res;
    316 }
    317 unsigned int float64_to_uint32_round_to_zero( float64 a STATUS_PARAM)
    318 {
    319     int64_t v;
    320     unsigned int res;
    321 
    322     v = (int64_t)a;
    323     if (v < 0) {
    324         res = 0;
    325     } else if (v > 0xffffffff) {
    326         res = 0xffffffff;
    327     } else {
    328         res = v;
    329     }
    330     return res;
    331 }
    332 uint64_t float64_to_uint64 (float64 a STATUS_PARAM)
    333 {
    334     int64_t v;
    335 
    336     v = llrint(a + (float64)INT64_MIN);
    337 
    338     return v - INT64_MIN;
    339 }
    340 uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM)
    341 {
    342     int64_t v;
    343 
    344     v = (int64_t)(a + (float64)INT64_MIN);
    345 
    346     return v - INT64_MIN;
    347 }
    348 
    349 /*----------------------------------------------------------------------------
    350 | Software IEC/IEEE double-precision operations.
    351 *----------------------------------------------------------------------------*/
    352 #if defined(__sun__) && \
    353     (defined(CONFIG_SOLARIS) && CONFIG_SOLARIS_VERSION < 10)
    354 static inline float64 trunc(float64 x)
    355 {
    356     return x < 0 ? -floor(-x) : floor(x);
    357 }
    358 #endif
    359 float64 float64_trunc_to_int( float64 a STATUS_PARAM )
    360 {
    361     return trunc(a);
    362 }
    363 
    364 float64 float64_round_to_int( float64 a STATUS_PARAM )
    365 {
    366     return rint(a);
    367 }
    368 
    369 float64 float64_rem( float64 a, float64 b STATUS_PARAM)
    370 {
    371     return remainder(a, b);
    372 }
    373 
    374 float64 float64_sqrt( float64 a STATUS_PARAM)
    375 {
    376     return sqrt(a);
    377 }
    378 int float64_compare( float64 a, float64 b STATUS_PARAM )
    379 {
    380     if (a < b) {
    381         return float_relation_less;
    382     } else if (a == b) {
    383         return float_relation_equal;
    384     } else if (a > b) {
    385         return float_relation_greater;
    386     } else {
    387         return float_relation_unordered;
    388     }
    389 }
    390 int float64_compare_quiet( float64 a, float64 b STATUS_PARAM )
    391 {
    392     if (isless(a, b)) {
    393         return float_relation_less;
    394     } else if (a == b) {
    395         return float_relation_equal;
    396     } else if (isgreater(a, b)) {
    397         return float_relation_greater;
    398     } else {
    399         return float_relation_unordered;
    400     }
    401 }
    402 int float64_is_signaling_nan( float64 a1)
    403 {
    404     float64u u;
    405     uint64_t a;
    406     u.f = a1;
    407     a = u.i;
    408     return
    409            ( ( ( a>>51 ) & 0xFFF ) == 0xFFE )
    410         && ( a & LIT64( 0x0007FFFFFFFFFFFF ) );
    411 
    412 }
    413 
    414 int float64_is_nan( float64 a1 )
    415 {
    416     float64u u;
    417     uint64_t a;
    418     u.f = a1;
    419     a = u.i;
    420 
    421     return ( LIT64( 0xFFF0000000000000 ) < (bits64) ( a<<1 ) );
    422 
    423 }
    424 
    425 #ifdef FLOATX80
    426 
    427 /*----------------------------------------------------------------------------
    428 | Software IEC/IEEE extended double-precision conversion routines.
    429 *----------------------------------------------------------------------------*/
    430 int floatx80_to_int32( floatx80 a STATUS_PARAM)
    431 {
    432     return long_to_int32(lrintl(a));
    433 }
    434 int floatx80_to_int32_round_to_zero( floatx80 a STATUS_PARAM)
    435 {
    436     return (int)a;
    437 }
    438 int64_t floatx80_to_int64( floatx80 a STATUS_PARAM)
    439 {
    440     return llrintl(a);
    441 }
    442 int64_t floatx80_to_int64_round_to_zero( floatx80 a STATUS_PARAM)
    443 {
    444     return (int64_t)a;
    445 }
    446 float32 floatx80_to_float32( floatx80 a STATUS_PARAM)
    447 {
    448     return a;
    449 }
    450 float64 floatx80_to_float64( floatx80 a STATUS_PARAM)
    451 {
    452     return a;
    453 }
    454 
    455 /*----------------------------------------------------------------------------
    456 | Software IEC/IEEE extended double-precision operations.
    457 *----------------------------------------------------------------------------*/
    458 floatx80 floatx80_round_to_int( floatx80 a STATUS_PARAM)
    459 {
    460     return rintl(a);
    461 }
    462 floatx80 floatx80_rem( floatx80 a, floatx80 b STATUS_PARAM)
    463 {
    464     return remainderl(a, b);
    465 }
    466 floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM)
    467 {
    468     return sqrtl(a);
    469 }
    470 int floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM )
    471 {
    472     if (a < b) {
    473         return float_relation_less;
    474     } else if (a == b) {
    475         return float_relation_equal;
    476     } else if (a > b) {
    477         return float_relation_greater;
    478     } else {
    479         return float_relation_unordered;
    480     }
    481 }
    482 int floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM )
    483 {
    484     if (isless(a, b)) {
    485         return float_relation_less;
    486     } else if (a == b) {
    487         return float_relation_equal;
    488     } else if (isgreater(a, b)) {
    489         return float_relation_greater;
    490     } else {
    491         return float_relation_unordered;
    492     }
    493 }
    494 int floatx80_is_signaling_nan( floatx80 a1)
    495 {
    496     floatx80u u;
    497     uint64_t aLow;
    498     u.f = a1;
    499 
    500     aLow = u.i.low & ~ LIT64( 0x4000000000000000 );
    501     return
    502            ( ( u.i.high & 0x7FFF ) == 0x7FFF )
    503         && (bits64) ( aLow<<1 )
    504         && ( u.i.low == aLow );
    505 }
    506 
    507 int floatx80_is_nan( floatx80 a1 )
    508 {
    509     floatx80u u;
    510     u.f = a1;
    511     return ( ( u.i.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( u.i.low<<1 );
    512 }
    513 
    514 #endif
    515