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
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 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)
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 TO_ENCODED (&encoded_result, &res, &context);
92 IEEE_TO_HOST (encoded_result, &result);
96 /* Binary operations. */
98 static inline DFP_C_TYPE
99 dfp_binary_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
103 decNumber arg1, arg2, res;
104 IEEE_TYPE a, b, encoded_result;
106 HOST_TO_IEEE (arg_a, &a);
107 HOST_TO_IEEE (arg_b, &b);
109 decContextDefault (&context, CONTEXT_INIT);
110 DFP_INIT_ROUNDMODE (context.round);
112 TO_INTERNAL (&a, &arg1);
113 TO_INTERNAL (&b, &arg2);
115 /* Perform the operation. */
116 op (&res, &arg1, &arg2, &context);
118 TO_ENCODED (&encoded_result, &res, &context);
119 IEEE_TO_HOST (encoded_result, &result);
123 /* Comparison operations. */
126 dfp_compare_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
130 decNumber arg1, arg2, res;
133 HOST_TO_IEEE (arg_a, &a);
134 HOST_TO_IEEE (arg_b, &b);
136 decContextDefault (&context, CONTEXT_INIT);
137 DFP_INIT_ROUNDMODE (context.round);
139 TO_INTERNAL (&a, &arg1);
140 TO_INTERNAL (&b, &arg2);
142 /* Perform the comparison. */
143 op (&res, &arg1, &arg2, &context);
145 if (decNumberIsNegative (&res))
147 else if (decNumberIsZero (&res))
149 else if (decNumberIsNaN (&res))
158 #if defined(L_conv_sd)
160 __host_to_ieee_32 (_Decimal32 in, decimal32 *out)
164 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
167 t = __dec_byte_swap (t);
171 memcpy (out, &in, 4);
175 __ieee_to_host_32 (decimal32 in, _Decimal32 *out)
179 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
182 t = __dec_byte_swap (t);
186 memcpy (out, &in, 4);
188 #endif /* L_conv_sd */
190 #if defined(L_conv_dd)
192 __swap64 (char *src, char *dst)
196 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
198 memcpy (&t1, src, 4);
199 memcpy (&t2, src + 4, 4);
200 t1 = __dec_byte_swap (t1);
201 t2 = __dec_byte_swap (t2);
202 memcpy (dst, &t2, 4);
203 memcpy (dst + 4, &t1, 4);
206 memcpy (dst, src, 8);
210 __host_to_ieee_64 (_Decimal64 in, decimal64 *out)
212 __swap64 ((char *) &in, (char *) out);
216 __ieee_to_host_64 (decimal64 in, _Decimal64 *out)
218 __swap64 ((char *) &in, (char *) out);
220 #endif /* L_conv_dd */
222 #if defined(L_conv_td)
224 __swap128 (char *src, char *dst)
226 uint32_t t1, t2, t3, t4;
228 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
230 memcpy (&t1, src, 4);
231 memcpy (&t2, src + 4, 4);
232 memcpy (&t3, src + 8, 4);
233 memcpy (&t4, src + 12, 4);
234 t1 = __dec_byte_swap (t1);
235 t2 = __dec_byte_swap (t2);
236 t3 = __dec_byte_swap (t3);
237 t4 = __dec_byte_swap (t4);
238 memcpy (dst, &t4, 4);
239 memcpy (dst + 4, &t3, 4);
240 memcpy (dst + 8, &t2, 4);
241 memcpy (dst + 12, &t1, 4);
244 memcpy (dst, src, 16);
248 __host_to_ieee_128 (_Decimal128 in, decimal128 *out)
250 __swap128 ((char *) &in, (char *) out);
254 __ieee_to_host_128 (decimal128 in, _Decimal128 *out)
256 __swap128 ((char *) &in, (char *) out);
258 #endif /* L_conv_td */
260 #if defined(L_addsub_sd) || defined(L_addsub_dd) || defined(L_addsub_td)
262 DFP_ADD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
264 return dfp_binary_op (decNumberAdd, arg_a, arg_b);
268 DFP_SUB (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
270 return dfp_binary_op (decNumberSubtract, arg_a, arg_b);
272 #endif /* L_addsub */
274 #if defined(L_mul_sd) || defined(L_mul_dd) || defined(L_mul_td)
276 DFP_MULTIPLY (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
278 return dfp_binary_op (decNumberMultiply, arg_a, arg_b);
282 #if defined(L_div_sd) || defined(L_div_dd) || defined(L_div_td)
284 DFP_DIVIDE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
286 return dfp_binary_op (decNumberDivide, arg_a, arg_b);
290 #if defined (L_eq_sd) || defined (L_eq_dd) || defined (L_eq_td)
292 DFP_EQ (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
295 stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
296 /* For EQ return zero for true, nonzero for false. */
301 #if defined (L_ne_sd) || defined (L_ne_dd) || defined (L_ne_td)
303 DFP_NE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
306 stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
307 /* For NE return zero for true, nonzero for false. */
308 if (__builtin_expect (stat == -2, 0)) /* An operand is NaN. */
314 #if defined (L_lt_sd) || defined (L_lt_dd) || defined (L_lt_td)
316 DFP_LT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
319 stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
320 /* For LT return -1 (<0) for true, 1 for false. */
321 return (stat == -1) ? -1 : 1;
325 #if defined (L_gt_sd) || defined (L_gt_dd) || defined (L_gt_td)
327 DFP_GT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
330 stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
331 /* For GT return 1 (>0) for true, -1 for false. */
332 return (stat == 1) ? 1 : -1;
336 #if defined (L_le_sd) || defined (L_le_dd) || defined (L_le_td)
338 DFP_LE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
341 stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
342 /* For LE return 0 (<= 0) for true, 1 for false. */
343 if (__builtin_expect (stat == -2, 0)) /* An operand is NaN. */
349 #if defined (L_ge_sd) || defined (L_ge_dd) || defined (L_ge_td)
351 DFP_GE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
354 stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
355 /* For GE return 1 (>=0) for true, -1 for false. */
356 if (__builtin_expect (stat == -2, 0)) /* An operand is NaN. */
358 return (stat != -1) ? 1 : -1;
364 #if defined (L_sd_to_dd) || defined (L_sd_to_td) || defined (L_dd_to_sd) \
365 || defined (L_dd_to_td) || defined (L_td_to_sd) || defined (L_td_to_dd)
367 DFP_TO_DFP (DFP_C_TYPE f_from)
375 decContextDefault (&context, CONTEXT_INIT);
376 DFP_INIT_ROUNDMODE (context.round);
378 HOST_TO_IEEE (f_from, &s_from);
379 TO_INTERNAL (&s_from, &d);
380 TO_ENCODED_TO (&s_to, &d, &context);
382 IEEE_TO_HOST_TO (s_to, &f_to);
387 #if defined (L_sd_to_si) || defined (L_dd_to_si) || defined (L_td_to_si) \
388 || defined (L_sd_to_di) || defined (L_dd_to_di) || defined (L_td_to_di) \
389 || defined (L_sd_to_usi) || defined (L_dd_to_usi) || defined (L_td_to_usi) \
390 || defined (L_sd_to_udi) || defined (L_dd_to_udi) || defined (L_td_to_udi)
392 DFP_TO_INT (DFP_C_TYPE x)
394 /* decNumber's decimal* types have the same format as C's _Decimal*
395 types, but they have different calling conventions. */
400 decNumber qval, n1, n2;
403 /* Use a large context to avoid losing precision. */
404 decContextDefault (&context, DEC_INIT_DECIMAL128);
405 /* Need non-default rounding mode here. */
406 context.round = DEC_ROUND_DOWN;
408 HOST_TO_IEEE (x, &s);
409 TO_INTERNAL (&s, &n1);
410 /* Rescale if the exponent is less than zero. */
411 decNumberToIntegralValue (&n2, &n1, &context);
412 /* Get a value to use for the quantize call. */
413 decNumberFromString (&qval, (char *) "1.0", &context);
414 /* Force the exponent to zero. */
415 decNumberQuantize (&n1, &n2, &qval, &context);
416 /* Get a string, which at this point will not include an exponent. */
417 decNumberToString (&n1, buf);
418 /* Ignore the fractional part. */
419 pos = strchr (buf, '.');
422 /* Use a C library function to convert to the integral type. */
423 return STR_TO_INT (buf, NULL, 10);
427 #if defined (L_si_to_sd) || defined (L_si_to_dd) || defined (L_si_to_td) \
428 || defined (L_di_to_sd) || defined (L_di_to_dd) || defined (L_di_to_td) \
429 || defined (L_usi_to_sd) || defined (L_usi_to_dd) || defined (L_usi_to_td) \
430 || defined (L_udi_to_sd) || defined (L_udi_to_dd) || defined (L_udi_to_td)
432 INT_TO_DFP (INT_TYPE i)
439 decContextDefault (&context, CONTEXT_INIT);
440 DFP_INIT_ROUNDMODE (context.round);
442 /* Use a C library function to get a floating point string. */
443 sprintf (buf, INT_FMT ".0", CAST_FOR_FMT(i));
444 /* Convert from the floating point string to a decimal* type. */
445 FROM_STRING (&s, buf, &context);
446 IEEE_TO_HOST (s, &f);
451 #if defined (L_sd_to_sf) || defined (L_dd_to_sf) || defined (L_td_to_sf) \
452 || defined (L_sd_to_df) || defined (L_dd_to_df) || defined (L_td_to_df) \
453 || ((defined (L_sd_to_xf) || defined (L_dd_to_xf) || defined (L_td_to_xf)) \
454 && LIBGCC2_HAS_XF_MODE)
456 DFP_TO_BFP (DFP_C_TYPE f)
461 HOST_TO_IEEE (f, &s);
462 /* Write the value to a string. */
464 /* Read it as the binary floating point type and return that. */
465 return STR_TO_BFP (buf, NULL);
469 #if defined (L_sf_to_sd) || defined (L_sf_to_dd) || defined (L_sf_to_td) \
470 || defined (L_df_to_sd) || defined (L_df_to_dd) || defined (L_df_to_td) \
471 || ((defined (L_xf_to_sd) || defined (L_xf_to_dd) || defined (L_xf_to_td)) \
472 && LIBGCC2_HAS_XF_MODE)
474 BFP_TO_DFP (BFP_TYPE x)
481 decContextDefault (&context, CONTEXT_INIT);
482 DFP_INIT_ROUNDMODE (context.round);
484 /* Use a C library function to write the floating point value to a string. */
486 /* FIXME: Is there a better way to output an XFmode variable in C? */
487 sprintf (buf, BFP_FMT, (BFP_VIA_TYPE) x);
489 sprintf (buf, BFP_FMT, x);
492 /* Convert from the floating point string to a decimal* type. */
493 FROM_STRING (&s, buf, &context);
494 IEEE_TO_HOST (s, &f);
499 #if defined (L_unord_sd) || defined (L_unord_dd) || defined (L_unord_td)
501 DFP_UNORD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
503 decNumber arg1, arg2;
506 HOST_TO_IEEE (arg_a, &a);
507 HOST_TO_IEEE (arg_b, &b);
508 TO_INTERNAL (&a, &arg1);
509 TO_INTERNAL (&b, &arg2);
510 return (decNumberIsNaN (&arg1) || decNumberIsNaN (&arg2));
512 #endif /* L_unord_sd || L_unord_dd || L_unord_td */