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
))
156 #if defined(L_conv_sd)
158 __host_to_ieee_32 (_Decimal32 in
, decimal32
*out
)
162 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN
)
165 t
= __dec_byte_swap (t
);
169 memcpy (out
, &in
, 4);
173 __ieee_to_host_32 (decimal32 in
, _Decimal32
*out
)
177 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN
)
180 t
= __dec_byte_swap (t
);
184 memcpy (out
, &in
, 4);
186 #endif /* L_conv_sd */
188 #if defined(L_conv_dd)
190 __swap64 (char *src
, char *dst
)
194 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN
)
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);
204 memcpy (dst
, src
, 8);
208 __host_to_ieee_64 (_Decimal64 in
, decimal64
*out
)
210 __swap64 ((char *) &in
, (char *) out
);
214 __ieee_to_host_64 (decimal64 in
, _Decimal64
*out
)
216 __swap64 ((char *) &in
, (char *) out
);
218 #endif /* L_conv_dd */
220 #if defined(L_conv_td)
222 __swap128 (char *src
, char *dst
)
224 uint32_t t1
, t2
, t3
, t4
;
226 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN
)
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);
242 memcpy (dst
, src
, 16);
246 __host_to_ieee_128 (_Decimal128 in
, decimal128
*out
)
248 __swap128 ((char *) &in
, (char *) out
);
252 __ieee_to_host_128 (decimal128 in
, _Decimal128
*out
)
254 __swap128 ((char *) &in
, (char *) out
);
256 #endif /* L_conv_td */
258 #if defined(L_addsub_sd) || defined(L_addsub_dd) || defined(L_addsub_td)
260 DFP_ADD (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
262 return dfp_binary_op (decNumberAdd
, arg_a
, arg_b
);
266 DFP_SUB (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
268 return dfp_binary_op (decNumberSubtract
, arg_a
, arg_b
);
270 #endif /* L_addsub */
272 #if defined(L_mul_sd) || defined(L_mul_dd) || defined(L_mul_td)
274 DFP_MULTIPLY (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
276 return dfp_binary_op (decNumberMultiply
, arg_a
, arg_b
);
280 #if defined(L_div_sd) || defined(L_div_dd) || defined(L_div_td)
282 DFP_DIVIDE (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
284 return dfp_binary_op (decNumberDivide
, arg_a
, arg_b
);
288 #if defined (L_eq_sd) || defined (L_eq_dd) || defined (L_eq_td)
290 DFP_EQ (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
293 stat
= dfp_compare_op (decNumberCompare
, arg_a
, arg_b
);
294 /* For EQ return zero for true, nonzero for false. */
299 #if defined (L_ne_sd) || defined (L_ne_dd) || defined (L_ne_td)
301 DFP_NE (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
304 stat
= dfp_compare_op (decNumberCompare
, arg_a
, arg_b
);
305 /* For NE return nonzero for true, zero for false. */
310 #if defined (L_lt_sd) || defined (L_lt_dd) || defined (L_lt_td)
312 DFP_LT (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
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;
321 #if defined (L_gt_sd) || defined (L_gt_dd) || defined (L_gt_td)
323 DFP_GT (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
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;
332 #if defined (L_le_sd) || defined (L_le_dd) || defined (L_le_td)
334 DFP_LE (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
337 stat
= dfp_compare_op (decNumberCompare
, arg_a
, arg_b
);
338 /* For LE return 0 (<= 0) for true, 1 for false. */
343 #if defined (L_ge_sd) || defined (L_ge_dd) || defined (L_ge_td)
345 DFP_GE (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
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;
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)
359 DFP_TO_DFP (DFP_C_TYPE f_from
)
367 decContextDefault (&context
, CONTEXT_INIT
);
368 DFP_INIT_ROUNDMODE (context
.round
);
370 HOST_TO_IEEE (f_from
, &s_from
);
371 TO_INTERNAL (&s_from
, &d
);
372 TO_ENCODED_TO (&s_to
, &d
, &context
);
374 IEEE_TO_HOST_TO (s_to
, &f_to
);
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)
384 DFP_TO_INT (DFP_C_TYPE x
)
386 /* decNumber's decimal* types have the same format as C's _Decimal*
387 types, but they have different calling conventions. */
392 decNumber qval
, n1
, n2
;
395 /* Use a large context to avoid losing precision. */
396 decContextDefault (&context
, DEC_INIT_DECIMAL128
);
397 /* Need non-default rounding mode here. */
398 context
.round
= DEC_ROUND_DOWN
;
400 HOST_TO_IEEE (x
, &s
);
401 TO_INTERNAL (&s
, &n1
);
402 /* Rescale if the exponent is less than zero. */
403 decNumberToIntegralValue (&n2
, &n1
, &context
);
404 /* Get a value to use for the quantize call. */
405 decNumberFromString (&qval
, (char *) "1.0", &context
);
406 /* Force the exponent to zero. */
407 decNumberQuantize (&n1
, &n2
, &qval
, &context
);
408 /* Get a string, which at this point will not include an exponent. */
409 decNumberToString (&n1
, buf
);
410 /* Ignore the fractional part. */
411 pos
= strchr (buf
, '.');
414 /* Use a C library function to convert to the integral type. */
415 return STR_TO_INT (buf
, NULL
, 10);
419 #if defined (L_si_to_sd) || defined (L_si_to_dd) || defined (L_si_to_td) \
420 || defined (L_di_to_sd) || defined (L_di_to_dd) || defined (L_di_to_td) \
421 || defined (L_usi_to_sd) || defined (L_usi_to_dd) || defined (L_usi_to_td) \
422 || defined (L_udi_to_sd) || defined (L_udi_to_dd) || defined (L_udi_to_td)
424 INT_TO_DFP (INT_TYPE i
)
431 decContextDefault (&context
, CONTEXT_INIT
);
432 DFP_INIT_ROUNDMODE (context
.round
);
434 /* Use a C library function to get a floating point string. */
435 sprintf (buf
, INT_FMT
".0", CAST_FOR_FMT(i
));
436 /* Convert from the floating point string to a decimal* type. */
437 FROM_STRING (&s
, buf
, &context
);
438 IEEE_TO_HOST (s
, &f
);
443 #if defined (L_sd_to_sf) || defined (L_dd_to_sf) || defined (L_td_to_sf) \
444 || defined (L_sd_to_df) || defined (L_dd_to_df) || defined (L_td_to_df) \
445 || ((defined (L_sd_to_xf) || defined (L_dd_to_xf) || defined (L_td_to_xf)) \
446 && LIBGCC2_HAS_XF_MODE)
448 DFP_TO_BFP (DFP_C_TYPE f
)
453 HOST_TO_IEEE (f
, &s
);
454 /* Write the value to a string. */
456 /* Read it as the binary floating point type and return that. */
457 return STR_TO_BFP (buf
, NULL
);
461 #if defined (L_sf_to_sd) || defined (L_sf_to_dd) || defined (L_sf_to_td) \
462 || defined (L_df_to_sd) || defined (L_df_to_dd) || defined (L_df_to_td) \
463 || ((defined (L_xf_to_sd) || defined (L_xf_to_dd) || defined (L_xf_to_td)) \
464 && LIBGCC2_HAS_XF_MODE)
466 BFP_TO_DFP (BFP_TYPE x
)
473 decContextDefault (&context
, CONTEXT_INIT
);
474 DFP_INIT_ROUNDMODE (context
.round
);
476 /* Use a C library function to write the floating point value to a string. */
478 /* FIXME: Is there a better way to output an XFmode variable in C? */
479 sprintf (buf
, BFP_FMT
, (BFP_VIA_TYPE
) x
);
481 sprintf (buf
, BFP_FMT
, x
);
484 /* Convert from the floating point string to a decimal* type. */
485 FROM_STRING (&s
, buf
, &context
);
486 IEEE_TO_HOST (s
, &f
);
491 #if defined (L_unord_sd) || defined (L_unord_dd) || defined (L_unord_td)
493 DFP_UNORD (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
495 decNumber arg1
, arg2
;
498 HOST_TO_IEEE (arg_a
, &a
);
499 HOST_TO_IEEE (arg_b
, &b
);
500 TO_INTERNAL (&a
, &arg1
);
501 TO_INTERNAL (&b
, &arg2
);
502 return (decNumberIsNaN (&arg1
) || decNumberIsNaN (&arg2
));
504 #endif /* L_unord_sd || L_unord_dd || L_unord_td */