Statistics
| Branch: | Revision:

root / fpu / softfloat-native.c @ 14d483ec

History | View | Annotate | Download (11.4 kB)

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(HOST_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(HOST_BSD) && !defined(__APPLE__) ||         \
13
    (defined(HOST_SOLARIS) && HOST_SOLARIS < 10)
14
    fpsetround(val);
15
#elif defined(__arm__)
16
    /* nothing to do */
17
#else
18
    fesetround(val);
19
#endif
20
}
21

    
22
#ifdef FLOATX80
23
void set_floatx80_rounding_precision(int val STATUS_PARAM)
24
{
25
    STATUS(floatx80_rounding_precision) = val;
26
}
27
#endif
28

    
29
#if defined(HOST_BSD) || (defined(HOST_SOLARIS) && HOST_SOLARIS < 10)
30
#define lrint(d)                ((int32_t)rint(d))
31
#define llrint(d)                ((int64_t)rint(d))
32
#define lrintf(f)                ((int32_t)rint(f))
33
#define llrintf(f)                ((int64_t)rint(f))
34
#define sqrtf(f)                ((float)sqrt(f))
35
#define remainderf(fa, fb)        ((float)remainder(fa, fb))
36
#define rintf(f)                ((float)rint(f))
37
#if !defined(__sparc__) && defined(HOST_SOLARIS) && HOST_SOLARIS < 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__) && defined(HOST_SOLARIS) && HOST_SOLARIS < 10
353
static inline float64 trunc(float64 x)
354
{
355
    return x < 0 ? -floor(-x) : floor(x);
356
}
357
#endif
358
float64 float64_trunc_to_int( float64 a STATUS_PARAM )
359
{
360
    return trunc(a);
361
}
362

    
363
float64 float64_round_to_int( float64 a STATUS_PARAM )
364
{
365
#if defined(__arm__)
366
    switch(STATUS(float_rounding_mode)) {
367
    default:
368
    case float_round_nearest_even:
369
        asm("rndd %0, %1" : "=f" (a) : "f"(a));
370
        break;
371
    case float_round_down:
372
        asm("rnddm %0, %1" : "=f" (a) : "f"(a));
373
        break;
374
    case float_round_up:
375
        asm("rnddp %0, %1" : "=f" (a) : "f"(a));
376
        break;
377
    case float_round_to_zero:
378
        asm("rnddz %0, %1" : "=f" (a) : "f"(a));
379
        break;
380
    }
381
#else
382
    return rint(a);
383
#endif
384
}
385

    
386
float64 float64_rem( float64 a, float64 b STATUS_PARAM)
387
{
388
    return remainder(a, b);
389
}
390

    
391
float64 float64_sqrt( float64 a STATUS_PARAM)
392
{
393
    return sqrt(a);
394
}
395
int float64_compare( float64 a, float64 b STATUS_PARAM )
396
{
397
    if (a < b) {
398
        return float_relation_less;
399
    } else if (a == b) {
400
        return float_relation_equal;
401
    } else if (a > b) {
402
        return float_relation_greater;
403
    } else {
404
        return float_relation_unordered;
405
    }
406
}
407
int float64_compare_quiet( float64 a, float64 b STATUS_PARAM )
408
{
409
    if (isless(a, b)) {
410
        return float_relation_less;
411
    } else if (a == b) {
412
        return float_relation_equal;
413
    } else if (isgreater(a, b)) {
414
        return float_relation_greater;
415
    } else {
416
        return float_relation_unordered;
417
    }
418
}
419
int float64_is_signaling_nan( float64 a1)
420
{
421
    float64u u;
422
    uint64_t a;
423
    u.f = a1;
424
    a = u.i;
425
    return
426
           ( ( ( a>>51 ) & 0xFFF ) == 0xFFE )
427
        && ( a & LIT64( 0x0007FFFFFFFFFFFF ) );
428

    
429
}
430

    
431
int float64_is_nan( float64 a1 )
432
{
433
    float64u u;
434
    uint64_t a;
435
    u.f = a1;
436
    a = u.i;
437

    
438
    return ( LIT64( 0xFFF0000000000000 ) < (bits64) ( a<<1 ) );
439

    
440
}
441

    
442
#ifdef FLOATX80
443

    
444
/*----------------------------------------------------------------------------
445
| Software IEC/IEEE extended double-precision conversion routines.
446
*----------------------------------------------------------------------------*/
447
int floatx80_to_int32( floatx80 a STATUS_PARAM)
448
{
449
    return long_to_int32(lrintl(a));
450
}
451
int floatx80_to_int32_round_to_zero( floatx80 a STATUS_PARAM)
452
{
453
    return (int)a;
454
}
455
int64_t floatx80_to_int64( floatx80 a STATUS_PARAM)
456
{
457
    return llrintl(a);
458
}
459
int64_t floatx80_to_int64_round_to_zero( floatx80 a STATUS_PARAM)
460
{
461
    return (int64_t)a;
462
}
463
float32 floatx80_to_float32( floatx80 a STATUS_PARAM)
464
{
465
    return a;
466
}
467
float64 floatx80_to_float64( floatx80 a STATUS_PARAM)
468
{
469
    return a;
470
}
471

    
472
/*----------------------------------------------------------------------------
473
| Software IEC/IEEE extended double-precision operations.
474
*----------------------------------------------------------------------------*/
475
floatx80 floatx80_round_to_int( floatx80 a STATUS_PARAM)
476
{
477
    return rintl(a);
478
}
479
floatx80 floatx80_rem( floatx80 a, floatx80 b STATUS_PARAM)
480
{
481
    return remainderl(a, b);
482
}
483
floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM)
484
{
485
    return sqrtl(a);
486
}
487
int floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM )
488
{
489
    if (a < b) {
490
        return float_relation_less;
491
    } else if (a == b) {
492
        return float_relation_equal;
493
    } else if (a > b) {
494
        return float_relation_greater;
495
    } else {
496
        return float_relation_unordered;
497
    }
498
}
499
int floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM )
500
{
501
    if (isless(a, b)) {
502
        return float_relation_less;
503
    } else if (a == b) {
504
        return float_relation_equal;
505
    } else if (isgreater(a, b)) {
506
        return float_relation_greater;
507
    } else {
508
        return float_relation_unordered;
509
    }
510
}
511
int floatx80_is_signaling_nan( floatx80 a1)
512
{
513
    floatx80u u;
514
    uint64_t aLow;
515
    u.f = a1;
516

    
517
    aLow = u.i.low & ~ LIT64( 0x4000000000000000 );
518
    return
519
           ( ( u.i.high & 0x7FFF ) == 0x7FFF )
520
        && (bits64) ( aLow<<1 )
521
        && ( u.i.low == aLow );
522
}
523

    
524
int floatx80_is_nan( floatx80 a1 )
525
{
526
    floatx80u u;
527
    u.f = a1;
528
    return ( ( u.i.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( u.i.low<<1 );
529
}
530

    
531
#endif