OSDN Git Service

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