OSDN Git Service

325306a5460d88626bd066bf69884d8d552c7915
[pf3gnuchains/gcc-fork.git] / gcc / config / dfp-bit.c
1 /* This is a software decimal floating point library.
2    Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
3
4 This file is part of GCC.
5
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2, or (at your option) any later
9 version.
10
11 In addition to the permissions in the GNU General Public License, the
12 Free Software Foundation gives you unlimited permission to link the
13 compiled version of this file into combinations with other programs,
14 and to distribute those combinations without any restriction coming
15 from the use of this file.  (The General Public License restrictions
16 do apply in other respects; for example, they cover modification of
17 the file, and distribution when not linked into a combine
18 executable.)
19
20 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
21 WARRANTY; without even the implied warranty of MERCHANTABILITY or
22 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
23 for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with GCC; see the file COPYING.  If not, write to the Free
27 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
28 02110-1301, USA.  */
29
30 /* This implements IEEE 754R decimal floating point arithmetic, but
31    does not provide a mechanism for setting the rounding mode, or for
32    generating or handling exceptions.  Conversions between decimal
33    floating point types and other types depend on C library functions.
34
35    Contributed by Ben Elliston  <bje@au.ibm.com>.  */
36
37 /* The intended way to use this file is to make two copies, add `#define '
38    to one copy, then compile both copies and add them to libgcc.a.  */
39
40 /* FIXME: This implementation doesn't support TFmode conversions.  */
41 #if !(defined (L_sd_to_tf) || defined (L_dd_to_tf) \
42       || defined (L_td_to_tf) || defined (L_tf_to_sd) \
43       || defined (L_tf_to_dd) || defined (L_tf_to_td))
44
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <limits.h>
49
50 #include "config/dfp-bit.h"
51
52 /* Forward declarations.  */
53 #if WIDTH == 32 || WIDTH_TO == 32
54 void __host_to_ieee_32 (_Decimal32 in, decimal32 *out);
55 void __ieee_to_host_32 (decimal32 in, _Decimal32 *out);
56 #endif
57 #if WIDTH == 64 || WIDTH_TO == 64
58 void __host_to_ieee_64 (_Decimal64 in, decimal64 *out);
59 void __ieee_to_host_64 (decimal64 in, _Decimal64 *out);
60 #endif
61 #if WIDTH == 128 || WIDTH_TO == 128
62 void __host_to_ieee_128 (_Decimal128 in, decimal128 *out);
63 void __ieee_to_host_128 (decimal128 in, _Decimal128 *out);
64 #endif
65
66 /* A pointer to a unary decNumber operation.  */
67 typedef decNumber* (*dfp_unary_func)
68      (decNumber *, decNumber *, decContext *);
69
70 /* A pointer to a binary decNumber operation.  */
71 typedef decNumber* (*dfp_binary_func)
72      (decNumber *, const decNumber *, const decNumber *, decContext *);
73
74 extern uint32_t __dec_byte_swap (uint32_t);
75 \f
76 /* Unary operations.  */
77
78 static inline DFP_C_TYPE
79 dfp_unary_op (dfp_unary_func op, DFP_C_TYPE arg)
80 {
81   DFP_C_TYPE result;
82   decContext context;
83   decNumber arg1, res;
84   IEEE_TYPE a, encoded_result;
85
86   HOST_TO_IEEE (arg, &a);
87
88   decContextDefault (&context, CONTEXT_INIT);
89   DFP_INIT_ROUNDMODE (context.round);
90
91   TO_INTERNAL (&a, &arg1);
92
93   /* Perform the operation.  */
94   op (&res, &arg1, &context);
95
96   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
97     {
98       /* decNumber exception flags we care about here.  */
99       int ieee_flags;
100       int dec_flags = DEC_IEEE_854_Division_by_zero | DEC_IEEE_854_Inexact
101                       | DEC_IEEE_854_Invalid_operation | DEC_IEEE_854_Overflow
102                       | DEC_IEEE_854_Underflow;
103       dec_flags &= context.status;
104       ieee_flags = DFP_IEEE_FLAGS (dec_flags);
105       if (ieee_flags != 0)
106         DFP_HANDLE_EXCEPTIONS (ieee_flags);
107     }
108
109   TO_ENCODED (&encoded_result, &res, &context);
110   IEEE_TO_HOST (encoded_result, &result);
111   return result;
112 }
113
114 /* Binary operations.  */
115
116 static inline DFP_C_TYPE
117 dfp_binary_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
118 {
119   DFP_C_TYPE result;
120   decContext context;
121   decNumber arg1, arg2, res;
122   IEEE_TYPE a, b, encoded_result;
123
124   HOST_TO_IEEE (arg_a, &a);
125   HOST_TO_IEEE (arg_b, &b);
126
127   decContextDefault (&context, CONTEXT_INIT);
128   DFP_INIT_ROUNDMODE (context.round);
129
130   TO_INTERNAL (&a, &arg1);
131   TO_INTERNAL (&b, &arg2);
132
133   /* Perform the operation.  */
134   op (&res, &arg1, &arg2, &context);
135
136   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
137     {
138       /* decNumber exception flags we care about here.  */
139       int ieee_flags;
140       int dec_flags = DEC_IEEE_854_Division_by_zero | DEC_IEEE_854_Inexact
141                       | DEC_IEEE_854_Invalid_operation | DEC_IEEE_854_Overflow
142                       | DEC_IEEE_854_Underflow;
143       dec_flags &= context.status;
144       ieee_flags = DFP_IEEE_FLAGS (dec_flags);
145       if (ieee_flags != 0)
146         DFP_HANDLE_EXCEPTIONS (ieee_flags);
147     }
148
149   TO_ENCODED (&encoded_result, &res, &context);
150   IEEE_TO_HOST (encoded_result, &result);
151   return result;
152 }
153
154 /* Comparison operations.  */
155
156 static inline int
157 dfp_compare_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
158 {
159   IEEE_TYPE a, b;
160   decContext context;
161   decNumber arg1, arg2, res;
162   int result;
163
164   HOST_TO_IEEE (arg_a, &a);
165   HOST_TO_IEEE (arg_b, &b);
166
167   decContextDefault (&context, CONTEXT_INIT);
168   DFP_INIT_ROUNDMODE (context.round);
169
170   TO_INTERNAL (&a, &arg1);
171   TO_INTERNAL (&b, &arg2);
172
173   /* Perform the comparison.  */
174   op (&res, &arg1, &arg2, &context);
175
176   if (decNumberIsNegative (&res))
177     result = -1;
178   else if (decNumberIsZero (&res))
179     result = 0;
180   else if (decNumberIsNaN (&res))
181     result = -2;
182   else
183     result = 1;
184
185   return result;
186 }
187
188 \f
189 #if defined(L_conv_sd)
190 void
191 __host_to_ieee_32 (_Decimal32 in, decimal32 *out)
192 {
193   uint32_t t;
194
195   if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
196     {
197       memcpy (&t, &in, 4);
198       t = __dec_byte_swap (t);
199       memcpy (out, &t, 4);
200     }
201   else
202     memcpy (out, &in, 4);
203 }
204
205 void
206 __ieee_to_host_32 (decimal32 in, _Decimal32 *out)
207 {
208   uint32_t t;
209
210   if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
211     {
212       memcpy (&t, &in, 4);
213       t = __dec_byte_swap (t);
214       memcpy (out, &t, 4);
215     }
216   else
217     memcpy (out, &in, 4);
218 }
219 #endif /* L_conv_sd */
220
221 #if defined(L_conv_dd)
222 static void
223 __swap64 (char *src, char *dst)
224 {
225   uint32_t t1, t2;
226
227   if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN) 
228     {
229       memcpy (&t1, src, 4);
230       memcpy (&t2, src + 4, 4);
231       t1 = __dec_byte_swap (t1);
232       t2 = __dec_byte_swap (t2);
233       memcpy (dst, &t2, 4);
234       memcpy (dst + 4, &t1, 4);
235     }
236   else
237     memcpy (dst, src, 8);
238 }
239
240 void
241 __host_to_ieee_64 (_Decimal64 in, decimal64 *out)
242 {
243   __swap64 ((char *) &in, (char *) out);
244 }
245
246 void
247 __ieee_to_host_64 (decimal64 in, _Decimal64 *out)
248 {
249   __swap64 ((char *) &in, (char *) out);
250 }
251 #endif /* L_conv_dd */
252
253 #if defined(L_conv_td)
254 static void
255 __swap128 (char *src, char *dst)
256 {
257   uint32_t t1, t2, t3, t4;
258
259   if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
260     {
261       memcpy (&t1, src, 4);
262       memcpy (&t2, src + 4, 4);
263       memcpy (&t3, src + 8, 4);
264       memcpy (&t4, src + 12, 4);
265       t1 = __dec_byte_swap (t1);
266       t2 = __dec_byte_swap (t2);
267       t3 = __dec_byte_swap (t3);
268       t4 = __dec_byte_swap (t4);
269       memcpy (dst, &t4, 4);
270       memcpy (dst + 4, &t3, 4);
271       memcpy (dst + 8, &t2, 4);
272       memcpy (dst + 12, &t1, 4);
273     }
274   else
275     memcpy (dst, src, 16);
276 }
277
278 void
279 __host_to_ieee_128 (_Decimal128 in, decimal128 *out)
280 {
281   __swap128 ((char *) &in, (char *) out);
282 }
283
284 void
285 __ieee_to_host_128 (decimal128 in, _Decimal128 *out)
286 {
287   __swap128 ((char *) &in, (char *) out);
288 }
289 #endif /* L_conv_td */
290
291 #if defined(L_addsub_sd) || defined(L_addsub_dd) || defined(L_addsub_td)
292 DFP_C_TYPE
293 DFP_ADD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
294 {
295   return dfp_binary_op (decNumberAdd, arg_a, arg_b);
296 }
297
298 DFP_C_TYPE
299 DFP_SUB (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
300 {
301   return dfp_binary_op (decNumberSubtract, arg_a, arg_b);
302 }
303 #endif /* L_addsub */
304
305 #if defined(L_mul_sd) || defined(L_mul_dd) || defined(L_mul_td)
306 DFP_C_TYPE
307 DFP_MULTIPLY (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
308 {
309   return dfp_binary_op (decNumberMultiply, arg_a, arg_b);
310 }
311 #endif /* L_mul */
312
313 #if defined(L_div_sd) || defined(L_div_dd) || defined(L_div_td)
314 DFP_C_TYPE
315 DFP_DIVIDE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
316 {
317   return dfp_binary_op (decNumberDivide, arg_a, arg_b);
318 }
319 #endif /* L_div */
320
321 #if defined (L_eq_sd) || defined (L_eq_dd) || defined (L_eq_td)
322 CMPtype
323 DFP_EQ (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
324 {
325   int stat;
326   stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
327   /* For EQ return zero for true, nonzero for false.  */
328   return stat != 0;
329 }
330 #endif /* L_eq */
331
332 #if defined (L_ne_sd) || defined (L_ne_dd) || defined (L_ne_td)
333 CMPtype
334 DFP_NE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
335 {
336   int stat;
337   stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
338   /* For NE return zero for true, nonzero for false.  */
339   if (__builtin_expect (stat == -2, 0))  /* An operand is NaN.  */
340     return 1;
341   return stat != 0;
342 }
343 #endif /* L_ne */
344
345 #if defined (L_lt_sd) || defined (L_lt_dd) || defined (L_lt_td)
346 CMPtype
347 DFP_LT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
348 {
349   int stat;
350   stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
351   /* For LT return -1 (<0) for true, 1 for false.  */
352   return (stat == -1) ? -1 : 1;
353 }
354 #endif /* L_lt */
355
356 #if defined (L_gt_sd) || defined (L_gt_dd) || defined (L_gt_td)
357 CMPtype
358 DFP_GT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
359 {
360   int stat;
361   stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
362   /* For GT return 1 (>0) for true, -1 for false.  */
363   return (stat == 1) ? 1 : -1;
364 }
365 #endif
366
367 #if defined (L_le_sd) || defined (L_le_dd) || defined (L_le_td)
368 CMPtype
369 DFP_LE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
370 {
371   int stat;
372   stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
373   /* For LE return 0 (<= 0) for true, 1 for false.  */
374   if (__builtin_expect (stat == -2, 0))  /* An operand is NaN.  */
375     return 1;
376   return stat == 1;
377 }
378 #endif /* L_le */
379
380 #if defined (L_ge_sd) || defined (L_ge_dd) || defined (L_ge_td)
381 CMPtype
382 DFP_GE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
383 {
384   int stat;
385   stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
386   /* For GE return 1 (>=0) for true, -1 for false.  */
387   if (__builtin_expect (stat == -2, 0))  /* An operand is NaN.  */
388     return -1;
389   return (stat != -1) ? 1 : -1;
390 }
391 #endif /* L_ge */
392
393 #define BUFMAX 128
394
395 #if defined (L_sd_to_dd) || defined (L_sd_to_td) || defined (L_dd_to_sd) \
396  || defined (L_dd_to_td) || defined (L_td_to_sd) || defined (L_td_to_dd)
397 DFP_C_TYPE_TO
398 DFP_TO_DFP (DFP_C_TYPE f_from)
399 {
400   DFP_C_TYPE_TO f_to;
401   IEEE_TYPE s_from;
402   IEEE_TYPE_TO s_to;
403   decNumber d;
404   decContext context;
405
406   decContextDefault (&context, CONTEXT_INIT);
407   DFP_INIT_ROUNDMODE (context.round);
408
409   HOST_TO_IEEE (f_from, &s_from);
410   TO_INTERNAL (&s_from, &d);
411   TO_ENCODED_TO (&s_to, &d, &context);
412
413   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
414     {
415       /* decNumber exception flags we care about here.  */
416       int ieee_flags;
417       int dec_flags = DEC_IEEE_854_Inexact | DEC_IEEE_854_Invalid_operation
418                       | DEC_IEEE_854_Overflow;
419       dec_flags &= context.status;
420       ieee_flags = DFP_IEEE_FLAGS (dec_flags);
421       if (ieee_flags != 0)
422         DFP_HANDLE_EXCEPTIONS (ieee_flags);
423     }
424
425   IEEE_TO_HOST_TO (s_to, &f_to);
426   return f_to;
427 }
428 #endif
429
430 #if defined (L_sd_to_si) || defined (L_dd_to_si) || defined (L_td_to_si) \
431   || defined (L_sd_to_di) || defined (L_dd_to_di) || defined (L_td_to_di) \
432   || defined (L_sd_to_usi) || defined (L_dd_to_usi) || defined (L_td_to_usi) \
433   || defined (L_sd_to_udi) || defined (L_dd_to_udi) || defined (L_td_to_udi)
434 INT_TYPE
435 DFP_TO_INT (DFP_C_TYPE x)
436 {
437   /* decNumber's decimal* types have the same format as C's _Decimal*
438      types, but they have different calling conventions.  */
439
440   /* TODO: Decimal float to integer conversions should raise FE_INVALID
441      if the result value does not fit into the result type.  */
442
443   IEEE_TYPE s;
444   char buf[BUFMAX];
445   char *pos;
446   decNumber qval, n1, n2;
447   decContext context;
448
449   /* Use a large context to avoid losing precision.  */
450   decContextDefault (&context, DEC_INIT_DECIMAL128);
451   /* Need non-default rounding mode here.  */
452   context.round = DEC_ROUND_DOWN;
453
454   HOST_TO_IEEE (x, &s);
455   TO_INTERNAL (&s, &n1);
456   /* Rescale if the exponent is less than zero.  */
457   decNumberToIntegralValue (&n2, &n1, &context);
458   /* Get a value to use for the quantize call.  */
459   decNumberFromString (&qval, (char *) "1.", &context);
460   /* Force the exponent to zero.  */
461   decNumberQuantize (&n1, &n2, &qval, &context);
462   /* Get a string, which at this point will not include an exponent.  */
463   decNumberToString (&n1, buf);
464   /* Ignore the fractional part.  */
465   pos = strchr (buf, '.');
466   if (pos)
467     *pos = 0;
468   /* Use a C library function to convert to the integral type.  */
469   return STR_TO_INT (buf, NULL, 10);
470 }
471 #endif
472
473 #if defined (L_si_to_sd) || defined (L_si_to_dd) || defined (L_si_to_td) \
474   || defined (L_di_to_sd) || defined (L_di_to_dd) || defined (L_di_to_td) \
475   || defined (L_usi_to_sd) || defined (L_usi_to_dd) || defined (L_usi_to_td) \
476   || defined (L_udi_to_sd) || defined (L_udi_to_dd) || defined (L_udi_to_td)
477 DFP_C_TYPE
478 INT_TO_DFP (INT_TYPE i)
479 {
480   DFP_C_TYPE f;
481   IEEE_TYPE s;
482   char buf[BUFMAX];
483   decContext context;
484
485   decContextDefault (&context, CONTEXT_INIT);
486   DFP_INIT_ROUNDMODE (context.round);
487
488   /* Use a C library function to get a floating point string.  */
489   sprintf (buf, INT_FMT ".0", CAST_FOR_FMT(i));
490   /* Convert from the floating point string to a decimal* type.  */
491   FROM_STRING (&s, buf, &context);
492   IEEE_TO_HOST (s, &f);
493
494   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
495     {
496       /* decNumber exception flags we care about here.  */
497       int ieee_flags;
498       int dec_flags = DEC_IEEE_854_Inexact | DEC_IEEE_854_Invalid_operation
499                       | DEC_IEEE_854_Overflow;
500       dec_flags &= context.status;
501       ieee_flags = DFP_IEEE_FLAGS (dec_flags);
502       if (ieee_flags != 0)
503         DFP_HANDLE_EXCEPTIONS (ieee_flags);
504     }
505
506   return f;
507 }
508 #endif
509
510 #if defined (L_sd_to_sf) || defined (L_dd_to_sf) || defined (L_td_to_sf) \
511  || defined (L_sd_to_df) || defined (L_dd_to_df) || defined (L_td_to_df) \
512  || ((defined (L_sd_to_xf) || defined (L_dd_to_xf) || defined (L_td_to_xf)) \
513      && LIBGCC2_HAS_XF_MODE)
514 BFP_TYPE
515 DFP_TO_BFP (DFP_C_TYPE f)
516 {
517   IEEE_TYPE s;
518   char buf[BUFMAX];
519
520   HOST_TO_IEEE (f, &s);
521   /* Write the value to a string.  */
522   TO_STRING (&s, buf);
523   /* Read it as the binary floating point type and return that.  */
524   return STR_TO_BFP (buf, NULL);
525 }
526 #endif
527                                                                                 
528 #if defined (L_sf_to_sd) || defined (L_sf_to_dd) || defined (L_sf_to_td) \
529  || defined (L_df_to_sd) || defined (L_df_to_dd) || defined (L_df_to_td) \
530  || ((defined (L_xf_to_sd) || defined (L_xf_to_dd) || defined (L_xf_to_td)) \
531      && LIBGCC2_HAS_XF_MODE)
532 DFP_C_TYPE
533 BFP_TO_DFP (BFP_TYPE x)
534 {
535   DFP_C_TYPE f;
536   IEEE_TYPE s;
537   char buf[BUFMAX];
538   decContext context;
539
540   decContextDefault (&context, CONTEXT_INIT);
541   DFP_INIT_ROUNDMODE (context.round);
542
543   /* Use a C library function to write the floating point value to a string.  */
544 #ifdef BFP_VIA_TYPE
545   /* FIXME: Is there a better way to output an XFmode variable in C?  */
546   sprintf (buf, BFP_FMT, (BFP_VIA_TYPE) x);
547 #else
548   sprintf (buf, BFP_FMT, x);
549 #endif
550
551   /* Convert from the floating point string to a decimal* type.  */
552   FROM_STRING (&s, buf, &context);
553   IEEE_TO_HOST (s, &f);
554
555   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
556     {
557       /* decNumber exception flags we care about here.  */
558       int ieee_flags;
559       int dec_flags = DEC_IEEE_854_Inexact | DEC_IEEE_854_Invalid_operation
560                       | DEC_IEEE_854_Overflow | DEC_IEEE_854_Underflow;
561       dec_flags &= context.status;
562       ieee_flags = DFP_IEEE_FLAGS (dec_flags);
563       if (ieee_flags != 0)
564         DFP_HANDLE_EXCEPTIONS (ieee_flags);
565     }
566
567   return f;
568 }
569 #endif
570
571 #if defined (L_unord_sd) || defined (L_unord_dd) || defined (L_unord_td)
572 CMPtype
573 DFP_UNORD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
574 {
575   decNumber arg1, arg2;
576   IEEE_TYPE a, b;
577
578   HOST_TO_IEEE (arg_a, &a);
579   HOST_TO_IEEE (arg_b, &b);
580   TO_INTERNAL (&a, &arg1);
581   TO_INTERNAL (&b, &arg2);
582   return (decNumberIsNaN (&arg1) || decNumberIsNaN (&arg2));
583 }
584 #endif /* L_unord_sd || L_unord_dd || L_unord_td */
585
586 /* !(L_sd_to_tf || L_dd_to_tf || L_td_to_tf \
587      || L_tf_to_sd || L_tf_to_dd || L_tf_to_td)  */
588 #endif