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