1 /* This is a software decimal floating point library.
2 Copyright (C) 2005, 2006, 2007 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
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
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
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
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. */
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);
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);
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);
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 *, const decNumber *, const decNumber *, decContext *);
69 extern uint32_t __dec_byte_swap (uint32_t);
71 /* Unary operations. */
73 static inline DFP_C_TYPE
74 dfp_unary_op (dfp_unary_func op, DFP_C_TYPE arg)
79 IEEE_TYPE a, encoded_result;
81 HOST_TO_IEEE (arg, &a);
83 decContextDefault (&context, CONTEXT_INIT);
84 DFP_INIT_ROUNDMODE (context.round);
86 TO_INTERNAL (&a, &arg1);
88 /* Perform the operation. */
89 op (&res, &arg1, &context);
91 if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
93 /* decNumber exception flags we care about here. */
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);
101 DFP_HANDLE_EXCEPTIONS (ieee_flags);
104 TO_ENCODED (&encoded_result, &res, &context);
105 IEEE_TO_HOST (encoded_result, &result);
109 /* Binary operations. */
111 static inline DFP_C_TYPE
112 dfp_binary_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
116 decNumber arg1, arg2, res;
117 IEEE_TYPE a, b, encoded_result;
119 HOST_TO_IEEE (arg_a, &a);
120 HOST_TO_IEEE (arg_b, &b);
122 decContextDefault (&context, CONTEXT_INIT);
123 DFP_INIT_ROUNDMODE (context.round);
125 TO_INTERNAL (&a, &arg1);
126 TO_INTERNAL (&b, &arg2);
128 /* Perform the operation. */
129 op (&res, &arg1, &arg2, &context);
131 if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
133 /* decNumber exception flags we care about here. */
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);
141 DFP_HANDLE_EXCEPTIONS (ieee_flags);
144 TO_ENCODED (&encoded_result, &res, &context);
145 IEEE_TO_HOST (encoded_result, &result);
149 /* Comparison operations. */
152 dfp_compare_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
156 decNumber arg1, arg2, res;
159 HOST_TO_IEEE (arg_a, &a);
160 HOST_TO_IEEE (arg_b, &b);
162 decContextDefault (&context, CONTEXT_INIT);
163 DFP_INIT_ROUNDMODE (context.round);
165 TO_INTERNAL (&a, &arg1);
166 TO_INTERNAL (&b, &arg2);
168 /* Perform the comparison. */
169 op (&res, &arg1, &arg2, &context);
171 if (decNumberIsNegative (&res))
173 else if (decNumberIsZero (&res))
175 else if (decNumberIsNaN (&res))
184 #if defined(L_conv_sd)
186 __host_to_ieee_32 (_Decimal32 in, decimal32 *out)
190 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
193 t = __dec_byte_swap (t);
197 memcpy (out, &in, 4);
201 __ieee_to_host_32 (decimal32 in, _Decimal32 *out)
205 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
208 t = __dec_byte_swap (t);
212 memcpy (out, &in, 4);
214 #endif /* L_conv_sd */
216 #if defined(L_conv_dd)
218 __swap64 (char *src, char *dst)
222 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
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);
232 memcpy (dst, src, 8);
236 __host_to_ieee_64 (_Decimal64 in, decimal64 *out)
238 __swap64 ((char *) &in, (char *) out);
242 __ieee_to_host_64 (decimal64 in, _Decimal64 *out)
244 __swap64 ((char *) &in, (char *) out);
246 #endif /* L_conv_dd */
248 #if defined(L_conv_td)
250 __swap128 (char *src, char *dst)
252 uint32_t t1, t2, t3, t4;
254 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
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);
270 memcpy (dst, src, 16);
274 __host_to_ieee_128 (_Decimal128 in, decimal128 *out)
276 __swap128 ((char *) &in, (char *) out);
280 __ieee_to_host_128 (decimal128 in, _Decimal128 *out)
282 __swap128 ((char *) &in, (char *) out);
284 #endif /* L_conv_td */
286 #if defined(L_addsub_sd) || defined(L_addsub_dd) || defined(L_addsub_td)
288 DFP_ADD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
290 return dfp_binary_op (decNumberAdd, arg_a, arg_b);
294 DFP_SUB (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
296 return dfp_binary_op (decNumberSubtract, arg_a, arg_b);
298 #endif /* L_addsub */
300 #if defined(L_mul_sd) || defined(L_mul_dd) || defined(L_mul_td)
302 DFP_MULTIPLY (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
304 return dfp_binary_op (decNumberMultiply, arg_a, arg_b);
308 #if defined(L_div_sd) || defined(L_div_dd) || defined(L_div_td)
310 DFP_DIVIDE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
312 return dfp_binary_op (decNumberDivide, arg_a, arg_b);
316 #if defined (L_eq_sd) || defined (L_eq_dd) || defined (L_eq_td)
318 DFP_EQ (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
321 stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
322 /* For EQ return zero for true, nonzero for false. */
327 #if defined (L_ne_sd) || defined (L_ne_dd) || defined (L_ne_td)
329 DFP_NE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
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. */
340 #if defined (L_lt_sd) || defined (L_lt_dd) || defined (L_lt_td)
342 DFP_LT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
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;
351 #if defined (L_gt_sd) || defined (L_gt_dd) || defined (L_gt_td)
353 DFP_GT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
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;
362 #if defined (L_le_sd) || defined (L_le_dd) || defined (L_le_td)
364 DFP_LE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
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. */
375 #if defined (L_ge_sd) || defined (L_ge_dd) || defined (L_ge_td)
377 DFP_GE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
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. */
384 return (stat != -1) ? 1 : -1;
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)
393 DFP_TO_DFP (DFP_C_TYPE f_from)
401 decContextDefault (&context, CONTEXT_INIT);
402 DFP_INIT_ROUNDMODE (context.round);
404 HOST_TO_IEEE (f_from, &s_from);
405 TO_INTERNAL (&s_from, &d);
406 TO_ENCODED_TO (&s_to, &d, &context);
408 if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
410 /* decNumber exception flags we care about here. */
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);
416 DFP_HANDLE_EXCEPTIONS (ieee_flags);
419 IEEE_TO_HOST_TO (s_to, &f_to);
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)
429 DFP_TO_INT (DFP_C_TYPE x)
431 /* decNumber's decimal* types have the same format as C's _Decimal*
432 types, but they have different calling conventions. */
434 /* TODO: Decimal float to integer conversions should raise FE_INVALID
435 if the result value does not fit into the result type. */
440 decNumber qval, n1, n2;
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;
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, '.');
462 /* Use a C library function to convert to the integral type. */
463 return STR_TO_INT (buf, NULL, 10);
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)
472 INT_TO_DFP (INT_TYPE i)
479 decContextDefault (&context, CONTEXT_INIT);
480 DFP_INIT_ROUNDMODE (context.round);
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);
488 if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
490 /* decNumber exception flags we care about here. */
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);
497 DFP_HANDLE_EXCEPTIONS (ieee_flags);
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)
509 DFP_TO_BFP (DFP_C_TYPE f)
514 HOST_TO_IEEE (f, &s);
515 /* Write the value to a string. */
517 /* Read it as the binary floating point type and return that. */
518 return STR_TO_BFP (buf, NULL);
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)
527 BFP_TO_DFP (BFP_TYPE x)
534 decContextDefault (&context, CONTEXT_INIT);
535 DFP_INIT_ROUNDMODE (context.round);
537 /* Use a C library function to write the floating point value to a string. */
539 /* FIXME: Is there a better way to output an XFmode variable in C? */
540 sprintf (buf, BFP_FMT, (BFP_VIA_TYPE) x);
542 sprintf (buf, BFP_FMT, x);
545 /* Convert from the floating point string to a decimal* type. */
546 FROM_STRING (&s, buf, &context);
547 IEEE_TO_HOST (s, &f);
549 if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
551 /* decNumber exception flags we care about here. */
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);
558 DFP_HANDLE_EXCEPTIONS (ieee_flags);
565 #if defined (L_unord_sd) || defined (L_unord_dd) || defined (L_unord_td)
567 DFP_UNORD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
569 decNumber arg1, arg2;
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));
578 #endif /* L_unord_sd || L_unord_dd || L_unord_td */