OSDN Git Service

* dfp-bit.c (DFP_TO_INT): Fix rounding mode.
[pf3gnuchains/gcc-fork.git] / gcc / config / dfp-bit.c
1 /* This is a software decimal floating point library.
2    Copyright (C) 2005, 2006 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 unsigned long __dec_byte_swap (unsigned long);
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   TO_ENCODED (&encoded_result, &res, &context);
92   IEEE_TO_HOST (encoded_result, &result);
93   return result;
94 }
95
96 /* Binary operations.  */
97
98 static inline DFP_C_TYPE
99 dfp_binary_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
100 {
101   DFP_C_TYPE result;
102   decContext context;
103   decNumber arg1, arg2, res;
104   IEEE_TYPE a, b, encoded_result;
105
106   HOST_TO_IEEE (arg_a, &a);
107   HOST_TO_IEEE (arg_b, &b);
108
109   decContextDefault (&context, CONTEXT_INIT);
110   DFP_INIT_ROUNDMODE (context.round);
111
112   TO_INTERNAL (&a, &arg1);
113   TO_INTERNAL (&b, &arg2);
114
115   /* Perform the operation.  */
116   op (&res, &arg1, &arg2, &context);
117
118   TO_ENCODED (&encoded_result, &res, &context);
119   IEEE_TO_HOST (encoded_result, &result);
120   return result;
121 }
122
123 /* Comparison operations.  */
124
125 static inline int
126 dfp_compare_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
127 {
128   IEEE_TYPE a, b;
129   decContext context;
130   decNumber arg1, arg2, res;
131   int result;
132
133   HOST_TO_IEEE (arg_a, &a);
134   HOST_TO_IEEE (arg_b, &b);
135
136   decContextDefault (&context, CONTEXT_INIT);
137   DFP_INIT_ROUNDMODE (context.round);
138
139   TO_INTERNAL (&a, &arg1);
140   TO_INTERNAL (&b, &arg2);
141
142   /* Perform the comparison.  */
143   op (&res, &arg1, &arg2, &context);
144
145   if (decNumberIsNegative (&res))
146     result = -1;
147   else if (decNumberIsZero (&res))
148     result = 0;
149   else
150     result = 1;
151
152   return result;
153 }
154
155 \f
156 #if defined(L_conv_sd)
157 void
158 __host_to_ieee_32 (_Decimal32 in, decimal32 *out)
159 {
160   uint32_t t;
161
162   if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
163     {
164       memcpy (&t, &in, 4);
165       t = __dec_byte_swap (t);
166       memcpy (out, &t, 4);
167     }
168   else
169     memcpy (out, &in, 4);
170 }
171
172 void
173 __ieee_to_host_32 (decimal32 in, _Decimal32 *out)
174 {
175   uint32_t t;
176
177   if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
178     {
179       memcpy (&t, &in, 4);
180       t = __dec_byte_swap (t);
181       memcpy (out, &t, 4);
182     }
183   else
184     memcpy (out, &in, 4);
185 }
186 #endif /* L_conv_sd */
187
188 #if defined(L_conv_dd)
189 static void
190 __swap64 (char *src, char *dst)
191 {
192   uint32_t t1, t2;
193
194   if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN) 
195     {
196       memcpy (&t1, src, 4);
197       memcpy (&t2, src + 4, 4);
198       t1 = __dec_byte_swap (t1);
199       t2 = __dec_byte_swap (t2);
200       memcpy (dst, &t2, 4);
201       memcpy (dst + 4, &t1, 4);
202     }
203   else
204     memcpy (dst, src, 8);
205 }
206
207 void
208 __host_to_ieee_64 (_Decimal64 in, decimal64 *out)
209 {
210   __swap64 ((char *) &in, (char *) out);
211 }
212
213 void
214 __ieee_to_host_64 (decimal64 in, _Decimal64 *out)
215 {
216   __swap64 ((char *) &in, (char *) out);
217 }
218 #endif /* L_conv_dd */
219
220 #if defined(L_conv_td)
221 static void
222 __swap128 (char *src, char *dst)
223 {
224   uint32_t t1, t2, t3, t4;
225
226   if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
227     {
228       memcpy (&t1, src, 4);
229       memcpy (&t2, src + 4, 4);
230       memcpy (&t3, src + 8, 4);
231       memcpy (&t4, src + 12, 4);
232       t1 = __dec_byte_swap (t1);
233       t2 = __dec_byte_swap (t2);
234       t3 = __dec_byte_swap (t3);
235       t4 = __dec_byte_swap (t4);
236       memcpy (dst, &t4, 4);
237       memcpy (dst + 4, &t3, 4);
238       memcpy (dst + 8, &t2, 4);
239       memcpy (dst + 12, &t1, 4);
240     }
241   else
242     memcpy (dst, src, 16);
243 }
244
245 void
246 __host_to_ieee_128 (_Decimal128 in, decimal128 *out)
247 {
248   __swap128 ((char *) &in, (char *) out);
249 }
250
251 void
252 __ieee_to_host_128 (decimal128 in, _Decimal128 *out)
253 {
254   __swap128 ((char *) &in, (char *) out);
255 }
256 #endif /* L_conv_td */
257
258 #if defined(L_addsub_sd) || defined(L_addsub_dd) || defined(L_addsub_td)
259 DFP_C_TYPE
260 DFP_ADD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
261 {
262   return dfp_binary_op (decNumberAdd, arg_a, arg_b);
263 }
264
265 DFP_C_TYPE
266 DFP_SUB (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
267 {
268   return dfp_binary_op (decNumberSubtract, arg_a, arg_b);
269 }
270 #endif /* L_addsub */
271
272 #if defined(L_mul_sd) || defined(L_mul_dd) || defined(L_mul_td)
273 DFP_C_TYPE
274 DFP_MULTIPLY (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
275 {
276   return dfp_binary_op (decNumberMultiply, arg_a, arg_b);
277 }
278 #endif /* L_mul */
279
280 #if defined(L_div_sd) || defined(L_div_dd) || defined(L_div_td)
281 DFP_C_TYPE
282 DFP_DIVIDE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
283 {
284   return dfp_binary_op (decNumberDivide, arg_a, arg_b);
285 }
286 #endif /* L_div */
287
288 #if defined (L_eq_sd) || defined (L_eq_dd) || defined (L_eq_td)
289 CMPtype
290 DFP_EQ (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
291 {
292   int stat;
293   stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
294   /* For EQ return zero for true, nonzero for false.  */
295   return stat != 0;
296 }
297 #endif /* L_eq */
298
299 #if defined (L_ne_sd) || defined (L_ne_dd) || defined (L_ne_td)
300 CMPtype
301 DFP_NE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
302 {
303   int stat;
304   stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
305   /* For NE return nonzero for true, zero for false.  */
306   return stat != 0;
307 }
308 #endif /* L_ne */
309
310 #if defined (L_lt_sd) || defined (L_lt_dd) || defined (L_lt_td)
311 CMPtype
312 DFP_LT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
313 {
314   int stat;
315   stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
316   /* For LT return -1 (<0) for true, 1 for false.  */
317   return (stat == -1) ? -1 : 1;
318 }
319 #endif /* L_lt */
320
321 #if defined (L_gt_sd) || defined (L_gt_dd) || defined (L_gt_td)
322 CMPtype
323 DFP_GT (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 GT return 1 (>0) for true, -1 for false.  */
328   return (stat == 1) ? 1 : -1;
329 }
330 #endif
331
332 #if defined (L_le_sd) || defined (L_le_dd) || defined (L_le_td)
333 CMPtype
334 DFP_LE (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 LE return 0 (<= 0) for true, 1 for false.  */
339   return stat == 1;
340 }
341 #endif /* L_le */
342
343 #if defined (L_ge_sd) || defined (L_ge_dd) || defined (L_ge_td)
344 CMPtype
345 DFP_GE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
346 {
347   int stat;
348   stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
349   /* For GE return 1 (>=0) for true, -1 for false.  */
350   return (stat != -1) ? 1 : -1;
351 }
352 #endif /* L_ge */
353
354 #define BUFMAX 128
355
356 #if defined (L_sd_to_dd) || defined (L_sd_to_td) || defined (L_dd_to_sd) \
357  || defined (L_dd_to_td) || defined (L_td_to_sd) || defined (L_td_to_dd)
358 DFP_C_TYPE_TO
359 DFP_TO_DFP (DFP_C_TYPE f_from)
360 {
361   DFP_C_TYPE_TO f_to;
362   IEEE_TYPE s_from;
363   IEEE_TYPE_TO s_to;
364   decNumber d;
365   decContext context;
366
367   decContextDefault (&context, CONTEXT_INIT);
368   DFP_INIT_ROUNDMODE (context.round);
369
370   HOST_TO_IEEE (f_from, &s_from);
371   TO_INTERNAL (&s_from, &d);
372   TO_ENCODED_TO (&s_to, &d, &context);
373
374   IEEE_TO_HOST_TO (s_to, &f_to);
375   return f_to;
376 }
377 #endif
378
379 #if defined (L_sd_to_si) || defined (L_dd_to_si) || defined (L_td_to_si) \
380   || defined (L_sd_to_di) || defined (L_dd_to_di) || defined (L_td_to_di) \
381   || defined (L_sd_to_usi) || defined (L_dd_to_usi) || defined (L_td_to_usi) \
382   || defined (L_sd_to_udi) || defined (L_dd_to_udi) || defined (L_td_to_udi)
383 INT_TYPE
384 DFP_TO_INT (DFP_C_TYPE x)
385 {
386   /* decNumber's decimal* types have the same format as C's _Decimal*
387      types, but they have different calling conventions.  */
388
389   IEEE_TYPE s;
390   char buf[BUFMAX];
391   char *pos;
392   decNumber qval, n1, n2;
393   decContext context;
394
395   decContextDefault (&context, CONTEXT_INIT);
396   /* Need non-default rounding mode here.  */
397   context.round = DEC_ROUND_DOWN;
398
399   HOST_TO_IEEE (x, &s);
400   TO_INTERNAL (&s, &n1);
401   /* Rescale if the exponent is less than zero.  */
402   decNumberToIntegralValue (&n2, &n1, &context);
403   /* Get a value to use for the quantize call.  */
404   decNumberFromString (&qval, (char *) "1.0", &context);
405   /* Force the exponent to zero.  */
406   decNumberQuantize (&n1, &n2, &qval, &context);
407   /* Get a string, which at this point will not include an exponent.  */
408   decNumberToString (&n1, buf);
409   /* Ignore the fractional part.  */
410   pos = strchr (buf, '.');
411   if (pos)
412     *pos = 0;
413   /* Use a C library function to convert to the integral type.  */
414   return STR_TO_INT (buf, NULL, 10);
415 }
416 #endif
417
418 #if defined (L_si_to_sd) || defined (L_si_to_dd) || defined (L_si_to_td) \
419   || defined (L_di_to_sd) || defined (L_di_to_dd) || defined (L_di_to_td) \
420   || defined (L_usi_to_sd) || defined (L_usi_to_dd) || defined (L_usi_to_td) \
421   || defined (L_udi_to_sd) || defined (L_udi_to_dd) || defined (L_udi_to_td)
422 DFP_C_TYPE
423 INT_TO_DFP (INT_TYPE i)
424 {
425   DFP_C_TYPE f;
426   IEEE_TYPE s;
427   char buf[BUFMAX];
428   decContext context;
429
430   decContextDefault (&context, CONTEXT_INIT);
431   DFP_INIT_ROUNDMODE (context.round);
432
433   /* Use a C library function to get a floating point string.  */
434   sprintf (buf, INT_FMT ".0", CAST_FOR_FMT(i));
435   /* Convert from the floating point string to a decimal* type.  */
436   FROM_STRING (&s, buf, &context);
437   IEEE_TO_HOST (s, &f);
438   return f;
439 }
440 #endif
441
442 #if defined (L_sd_to_sf) || defined (L_dd_to_sf) || defined (L_td_to_sf) \
443  || defined (L_sd_to_df) || defined (L_dd_to_df) || defined (L_td_to_df) \
444  || ((defined (L_sd_to_xf) || defined (L_dd_to_xf) || defined (L_td_to_xf)) \
445      && LIBGCC2_HAS_XF_MODE)
446 BFP_TYPE
447 DFP_TO_BFP (DFP_C_TYPE f)
448 {
449   IEEE_TYPE s;
450   char buf[BUFMAX];
451
452   HOST_TO_IEEE (f, &s);
453   /* Write the value to a string.  */
454   TO_STRING (&s, buf);
455   /* Read it as the binary floating point type and return that.  */
456   return STR_TO_BFP (buf, NULL);
457 }
458 #endif
459                                                                                 
460 #if defined (L_sf_to_sd) || defined (L_sf_to_dd) || defined (L_sf_to_td) \
461  || defined (L_df_to_sd) || defined (L_df_to_dd) || defined (L_df_to_td) \
462  || ((defined (L_xf_to_sd) || defined (L_xf_to_dd) || defined (L_xf_to_td)) \
463      && LIBGCC2_HAS_XF_MODE)
464 DFP_C_TYPE
465 BFP_TO_DFP (BFP_TYPE x)
466 {
467   DFP_C_TYPE f;
468   IEEE_TYPE s;
469   char buf[BUFMAX];
470   decContext context;
471
472   decContextDefault (&context, CONTEXT_INIT);
473   DFP_INIT_ROUNDMODE (context.round);
474
475   /* Use a C library function to write the floating point value to a string.  */
476 #ifdef BFP_VIA_TYPE
477   /* FIXME: Is there a better way to output an XFmode variable in C?  */
478   sprintf (buf, BFP_FMT, (BFP_VIA_TYPE) x);
479 #else
480   sprintf (buf, BFP_FMT, x);
481 #endif
482
483   /* Convert from the floating point string to a decimal* type.  */
484   FROM_STRING (&s, buf, &context);
485   IEEE_TO_HOST (s, &f);
486   return f;
487 }
488 #endif
489
490 #if defined (L_unord_sd) || defined (L_unord_dd) || defined (L_unord_td)
491 CMPtype
492 DFP_UNORD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
493 {
494   decNumber arg1, arg2;
495   IEEE_TYPE a, b;
496
497   HOST_TO_IEEE (arg_a, &a);
498   HOST_TO_IEEE (arg_b, &b);
499   TO_INTERNAL (&a, &arg1);
500   TO_INTERNAL (&b, &arg2);
501   return (decNumberIsNaN (&arg1) || decNumberIsNaN (&arg2));
502 }
503 #endif /* L_unord_sd || L_unord_dd || L_unord_td */