2006-06-19 Andreas Krebbel <krebbel1@de.ibm.com>
[official-gcc.git] / gcc / config / dfp-bit.c
blobc9374c51f0641a010f3428baaa9937b6baabda36
1 /* This is a software decimal floating point library.
2 Copyright (C) 2005, 2006 Free Software Foundation, Inc.
4 This file is part of GCC.
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.
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.)
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.
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. */
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.
35 Contributed by Ben Elliston <bje@au.ibm.com>. */
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. */
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <limits.h>
45 #include "config/dfp-bit.h"
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
61 /* A pointer to a unary decNumber operation. */
62 typedef decNumber* (*dfp_unary_func)
63 (decNumber *, decNumber *, decContext *);
65 /* A pointer to a binary decNumber operation. */
66 typedef decNumber* (*dfp_binary_func)
67 (decNumber *, decNumber *, decNumber *, decContext *);
69 extern unsigned long __dec_byte_swap (unsigned long);
71 /* Unary operations. */
73 static inline DFP_C_TYPE
74 dfp_unary_op (dfp_unary_func op, DFP_C_TYPE arg)
76 DFP_C_TYPE result;
77 decContext context;
78 decNumber arg1, res;
79 IEEE_TYPE a, encoded_result;
81 HOST_TO_IEEE (arg, &a);
83 decContextDefault (&context, CONTEXT_INIT);
84 context.round = CONTEXT_ROUND;
86 TO_INTERNAL (&a, &arg1);
88 /* Perform the operation. */
89 op (&res, &arg1, &context);
91 if (CONTEXT_TRAPS && CONTEXT_ERRORS (context))
92 DFP_RAISE (0);
94 TO_ENCODED (&encoded_result, &res, &context);
95 IEEE_TO_HOST (encoded_result, &result);
96 return result;
99 /* Binary operations. */
101 static inline DFP_C_TYPE
102 dfp_binary_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
104 DFP_C_TYPE result;
105 decContext context;
106 decNumber arg1, arg2, res;
107 IEEE_TYPE a, b, encoded_result;
109 HOST_TO_IEEE (arg_a, &a);
110 HOST_TO_IEEE (arg_b, &b);
112 decContextDefault (&context, CONTEXT_INIT);
113 context.round = CONTEXT_ROUND;
115 TO_INTERNAL (&a, &arg1);
116 TO_INTERNAL (&b, &arg2);
118 /* Perform the operation. */
119 op (&res, &arg1, &arg2, &context);
121 if (CONTEXT_TRAPS && CONTEXT_ERRORS (context))
122 DFP_RAISE (0);
124 TO_ENCODED (&encoded_result, &res, &context);
125 IEEE_TO_HOST (encoded_result, &result);
126 return result;
129 /* Comparison operations. */
131 static inline int
132 dfp_compare_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
134 IEEE_TYPE a, b;
135 decContext context;
136 decNumber arg1, arg2, res;
137 int result;
139 HOST_TO_IEEE (arg_a, &a);
140 HOST_TO_IEEE (arg_b, &b);
142 decContextDefault (&context, CONTEXT_INIT);
143 context.round = CONTEXT_ROUND;
145 TO_INTERNAL (&a, &arg1);
146 TO_INTERNAL (&b, &arg2);
148 /* Perform the comparison. */
149 op (&res, &arg1, &arg2, &context);
151 if (CONTEXT_TRAPS && CONTEXT_ERRORS (context))
152 DFP_RAISE (0);
154 if (decNumberIsNegative (&res))
155 result = -1;
156 else if (decNumberIsZero (&res))
157 result = 0;
158 else
159 result = 1;
161 return result;
165 #if defined(L_conv_sd)
166 void
167 __host_to_ieee_32 (_Decimal32 in, decimal32 *out)
169 uint32_t t;
171 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
173 memcpy (&t, &in, 4);
174 t = __dec_byte_swap (t);
175 memcpy (out, &t, 4);
177 else
178 memcpy (out, &in, 4);
181 void
182 __ieee_to_host_32 (decimal32 in, _Decimal32 *out)
184 uint32_t t;
186 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
188 memcpy (&t, &in, 4);
189 t = __dec_byte_swap (t);
190 memcpy (out, &t, 4);
192 else
193 memcpy (out, &in, 4);
195 #endif /* L_conv_sd */
197 #if defined(L_conv_dd)
198 static void
199 __swap64 (char *src, char *dst)
201 uint32_t t1, t2;
203 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
205 memcpy (&t1, src, 4);
206 memcpy (&t2, src + 4, 4);
207 t1 = __dec_byte_swap (t1);
208 t2 = __dec_byte_swap (t2);
209 memcpy (dst, &t2, 4);
210 memcpy (dst + 4, &t1, 4);
212 else
213 memcpy (dst, src, 8);
216 void
217 __host_to_ieee_64 (_Decimal64 in, decimal64 *out)
219 __swap64 ((char *) &in, (char *) out);
222 void
223 __ieee_to_host_64 (decimal64 in, _Decimal64 *out)
225 __swap64 ((char *) &in, (char *) out);
227 #endif /* L_conv_dd */
229 #if defined(L_conv_td)
230 static void
231 __swap128 (char *src, char *dst)
233 uint32_t t1, t2, t3, t4;
235 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
237 memcpy (&t1, src, 4);
238 memcpy (&t2, src + 4, 4);
239 memcpy (&t3, src + 8, 4);
240 memcpy (&t4, src + 12, 4);
241 t1 = __dec_byte_swap (t1);
242 t2 = __dec_byte_swap (t2);
243 t3 = __dec_byte_swap (t3);
244 t4 = __dec_byte_swap (t4);
245 memcpy (dst, &t4, 4);
246 memcpy (dst + 4, &t3, 4);
247 memcpy (dst + 8, &t2, 4);
248 memcpy (dst + 12, &t1, 4);
250 else
251 memcpy (dst, src, 16);
254 void
255 __host_to_ieee_128 (_Decimal128 in, decimal128 *out)
257 __swap128 ((char *) &in, (char *) out);
260 void
261 __ieee_to_host_128 (decimal128 in, _Decimal128 *out)
263 __swap128 ((char *) &in, (char *) out);
265 #endif /* L_conv_td */
267 #if defined(L_addsub_sd) || defined(L_addsub_dd) || defined(L_addsub_td)
268 DFP_C_TYPE
269 DFP_ADD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
271 return dfp_binary_op (decNumberAdd, arg_a, arg_b);
274 DFP_C_TYPE
275 DFP_SUB (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
277 return dfp_binary_op (decNumberSubtract, arg_a, arg_b);
279 #endif /* L_addsub */
281 #if defined(L_mul_sd) || defined(L_mul_dd) || defined(L_mul_td)
282 DFP_C_TYPE
283 DFP_MULTIPLY (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
285 return dfp_binary_op (decNumberMultiply, arg_a, arg_b);
287 #endif /* L_mul */
289 #if defined(L_div_sd) || defined(L_div_dd) || defined(L_div_td)
290 DFP_C_TYPE
291 DFP_DIVIDE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
293 return dfp_binary_op (decNumberDivide, arg_a, arg_b);
295 #endif /* L_div */
297 #if defined (L_eq_sd) || defined (L_eq_dd) || defined (L_eq_td)
298 CMPtype
299 DFP_EQ (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
301 int stat;
302 stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
303 /* For EQ return zero for true, nonzero for false. */
304 return stat != 0;
306 #endif /* L_eq */
308 #if defined (L_ne_sd) || defined (L_ne_dd) || defined (L_ne_td)
309 CMPtype
310 DFP_NE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
312 int stat;
313 stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
314 /* For NE return nonzero for true, zero for false. */
315 return stat != 0;
317 #endif /* L_ne */
319 #if defined (L_lt_sd) || defined (L_lt_dd) || defined (L_lt_td)
320 CMPtype
321 DFP_LT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
323 int stat;
324 stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
325 /* For LT return -1 (<0) for true, 1 for false. */
326 return (stat == -1) ? -1 : 1;
328 #endif /* L_lt */
330 #if defined (L_gt_sd) || defined (L_gt_dd) || defined (L_gt_td)
331 CMPtype
332 DFP_GT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
334 int stat;
335 stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
336 /* For GT return 1 (>0) for true, -1 for false. */
337 return (stat == 1) ? 1 : -1;
339 #endif
341 #if defined (L_le_sd) || defined (L_le_dd) || defined (L_le_td)
342 CMPtype
343 DFP_LE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
345 int stat;
346 stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
347 /* For LE return 0 (<= 0) for true, 1 for false. */
348 return stat == 1;
350 #endif /* L_le */
352 #if defined (L_ge_sd) || defined (L_ge_dd) || defined (L_ge_td)
353 CMPtype
354 DFP_GE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
356 int stat;
357 stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
358 /* For GE return 1 (>=0) for true, -1 for false. */
359 return (stat != -1) ? 1 : -1;
361 #endif /* L_ge */
363 #define BUFMAX 128
365 #if defined (L_sd_to_dd) || defined (L_sd_to_td) || defined (L_dd_to_sd) \
366 || defined (L_dd_to_td) || defined (L_td_to_sd) || defined (L_td_to_dd)
367 DFP_C_TYPE_TO
368 DFP_TO_DFP (DFP_C_TYPE f_from)
370 DFP_C_TYPE_TO f_to;
371 IEEE_TYPE s_from;
372 IEEE_TYPE_TO s_to;
373 decNumber d;
374 decContext context;
376 decContextDefault (&context, CONTEXT_INIT);
377 context.round = CONTEXT_ROUND;
379 HOST_TO_IEEE (f_from, &s_from);
380 TO_INTERNAL (&s_from, &d);
381 TO_ENCODED_TO (&s_to, &d, &context);
382 if (CONTEXT_TRAPS && (context.status & DEC_Inexact) != 0)
383 DFP_RAISE (DEC_Inexact);
385 IEEE_TO_HOST_TO (s_to, &f_to);
386 return f_to;
388 #endif
390 #if defined (L_sd_to_si) || defined (L_dd_to_si) || defined (L_td_to_si) \
391 || defined (L_sd_to_di) || defined (L_dd_to_di) || defined (L_td_to_di) \
392 || defined (L_sd_to_usi) || defined (L_dd_to_usi) || defined (L_td_to_usi) \
393 || defined (L_sd_to_udi) || defined (L_dd_to_udi) || defined (L_td_to_udi)
394 INT_TYPE
395 DFP_TO_INT (DFP_C_TYPE x)
397 /* decNumber's decimal* types have the same format as C's _Decimal*
398 types, but they have different calling conventions. */
400 IEEE_TYPE s;
401 char buf[BUFMAX];
402 char *pos;
403 decNumber qval, n1, n2;
404 decContext context;
406 decContextDefault (&context, CONTEXT_INIT);
407 /* Need non-default rounding mode here. */
408 context.round = DEC_ROUND_DOWN;
410 HOST_TO_IEEE (x, &s);
411 TO_INTERNAL (&s, &n1);
412 /* Rescale if the exponent is less than zero. */
413 decNumberToIntegralValue (&n2, &n1, &context);
414 /* Get a value to use for the quantize call. */
415 decNumberFromString (&qval, (char *) "1.0", &context);
416 /* Force the exponent to zero. */
417 decNumberQuantize (&n1, &n2, &qval, &context);
418 /* This is based on text in N1107 section 5.1; it might turn out to be
419 undefined behavior instead. */
420 if (context.status & DEC_Invalid_operation)
422 #if defined (L_sd_to_si) || defined (L_dd_to_si) || defined (L_td_to_si)
423 if (decNumberIsNegative(&n2))
424 return INT_MIN;
425 else
426 return INT_MAX;
427 #elif defined (L_sd_to_di) || defined (L_dd_to_di) || defined (L_td_to_di)
428 if (decNumberIsNegative(&n2))
429 /* Find a defined constant that will work here. */
430 return (-9223372036854775807LL - 1LL);
431 else
432 /* Find a defined constant that will work here. */
433 return 9223372036854775807LL;
434 #elif defined (L_sd_to_usi) || defined (L_dd_to_usi) || defined (L_td_to_usi)
435 return UINT_MAX;
436 #elif defined (L_sd_to_udi) || defined (L_dd_to_udi) || defined (L_td_to_udi)
437 /* Find a defined constant that will work here. */
438 return 18446744073709551615ULL;
439 #endif
441 /* Get a string, which at this point will not include an exponent. */
442 decNumberToString (&n1, buf);
443 /* Ignore the fractional part. */
444 pos = strchr (buf, '.');
445 if (pos)
446 *pos = 0;
447 /* Use a C library function to convert to the integral type. */
448 return STR_TO_INT (buf, NULL, 10);
450 #endif
452 #if defined (L_si_to_sd) || defined (L_si_to_dd) || defined (L_si_to_td) \
453 || defined (L_di_to_sd) || defined (L_di_to_dd) || defined (L_di_to_td) \
454 || defined (L_usi_to_sd) || defined (L_usi_to_dd) || defined (L_usi_to_td) \
455 || defined (L_udi_to_sd) || defined (L_udi_to_dd) || defined (L_udi_to_td)
456 DFP_C_TYPE
457 INT_TO_DFP (INT_TYPE i)
459 DFP_C_TYPE f;
460 IEEE_TYPE s;
461 char buf[BUFMAX];
462 decContext context;
464 decContextDefault (&context, CONTEXT_INIT);
465 context.round = CONTEXT_ROUND;
467 /* Use a C library function to get a floating point string. */
468 sprintf (buf, INT_FMT ".0", CAST_FOR_FMT(i));
469 /* Convert from the floating point string to a decimal* type. */
470 FROM_STRING (&s, buf, &context);
471 IEEE_TO_HOST (s, &f);
472 if (CONTEXT_TRAPS && (context.status & DEC_Inexact) != 0)
473 DFP_RAISE (DEC_Inexact);
474 return f;
476 #endif
478 #if defined (L_sd_to_sf) || defined (L_dd_to_sf) || defined (L_td_to_sf) \
479 || defined (L_sd_to_df) || defined (L_dd_to_df) || defined (L_td_to_df) \
480 || ((defined (L_sd_to_xf) || defined (L_dd_to_xf) || defined (L_td_to_xf)) \
481 && LIBGCC2_HAS_XF_MODE)
482 BFP_TYPE
483 DFP_TO_BFP (DFP_C_TYPE f)
485 IEEE_TYPE s;
486 char buf[BUFMAX];
488 HOST_TO_IEEE (f, &s);
489 /* Write the value to a string. */
490 TO_STRING (&s, buf);
491 /* Read it as the binary floating point type and return that. */
492 return STR_TO_BFP (buf, NULL);
494 #endif
496 #if defined (L_sf_to_sd) || defined (L_sf_to_dd) || defined (L_sf_to_td) \
497 || defined (L_df_to_sd) || defined (L_df_to_dd) || defined (L_df_to_td) \
498 || ((defined (L_xf_to_sd) || defined (L_xf_to_dd) || defined (L_xf_to_td)) \
499 && LIBGCC2_HAS_XF_MODE)
500 DFP_C_TYPE
501 BFP_TO_DFP (BFP_TYPE x)
503 DFP_C_TYPE f;
504 IEEE_TYPE s;
505 char buf[BUFMAX];
506 decContext context;
508 decContextDefault (&context, CONTEXT_INIT);
509 context.round = CONTEXT_ROUND;
511 /* Use a C library function to write the floating point value to a string. */
512 #ifdef BFP_VIA_TYPE
513 /* FIXME: Is there a better way to output an XFmode variable in C? */
514 sprintf (buf, BFP_FMT, (BFP_VIA_TYPE) x);
515 #else
516 sprintf (buf, BFP_FMT, x);
517 #endif
519 /* Convert from the floating point string to a decimal* type. */
520 FROM_STRING (&s, buf, &context);
521 IEEE_TO_HOST (s, &f);
522 if (CONTEXT_TRAPS && (context.status & DEC_Inexact) != 0)
523 DFP_RAISE (DEC_Inexact);
524 return f;
526 #endif
528 #if defined (L_unord_sd) || defined (L_unord_dd) || defined (L_unord_td)
529 CMPtype
530 DFP_UNORD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
532 decNumber arg1, arg2;
533 IEEE_TYPE a, b;
535 HOST_TO_IEEE (arg_a, &a);
536 HOST_TO_IEEE (arg_b, &b);
537 TO_INTERNAL (&a, &arg1);
538 TO_INTERNAL (&b, &arg2);
539 return (decNumberIsNaN (&arg1) || decNumberIsNaN (&arg2));
541 #endif /* L_unord_sd || L_unord_dd || L_unord_td */