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. */
40 /* FIXME: This implementation doesn't support TFmode conversions. */
41 #if !(defined (L_sd_to_tf) || defined (L_dd_to_tf) \
42 || defined (L_td_to_tf) || defined (L_tf_to_sd) \
43 || defined (L_tf_to_dd) || defined (L_tf_to_td))
50 #include "config/dfp-bit.h"
52 /* Forward declarations. */
53 #if WIDTH == 32 || WIDTH_TO == 32
54 void __host_to_ieee_32 (_Decimal32 in
, decimal32
*out
);
55 void __ieee_to_host_32 (decimal32 in
, _Decimal32
*out
);
57 #if WIDTH == 64 || WIDTH_TO == 64
58 void __host_to_ieee_64 (_Decimal64 in
, decimal64
*out
);
59 void __ieee_to_host_64 (decimal64 in
, _Decimal64
*out
);
61 #if WIDTH == 128 || WIDTH_TO == 128
62 void __host_to_ieee_128 (_Decimal128 in
, decimal128
*out
);
63 void __ieee_to_host_128 (decimal128 in
, _Decimal128
*out
);
66 /* A pointer to a unary decNumber operation. */
67 typedef decNumber
* (*dfp_unary_func
)
68 (decNumber
*, decNumber
*, decContext
*);
70 /* A pointer to a binary decNumber operation. */
71 typedef decNumber
* (*dfp_binary_func
)
72 (decNumber
*, const decNumber
*, const decNumber
*, decContext
*);
74 extern uint32_t __dec_byte_swap (uint32_t);
76 /* Unary operations. */
78 static inline DFP_C_TYPE
79 dfp_unary_op (dfp_unary_func op
, DFP_C_TYPE arg
)
84 IEEE_TYPE a
, encoded_result
;
86 HOST_TO_IEEE (arg
, &a
);
88 decContextDefault (&context
, CONTEXT_INIT
);
89 DFP_INIT_ROUNDMODE (context
.round
);
91 TO_INTERNAL (&a
, &arg1
);
93 /* Perform the operation. */
94 op (&res
, &arg1
, &context
);
96 if (DFP_EXCEPTIONS_ENABLED
&& context
.status
!= 0)
98 /* decNumber exception flags we care about here. */
100 int dec_flags
= DEC_IEEE_854_Division_by_zero
| DEC_IEEE_854_Inexact
101 | DEC_IEEE_854_Invalid_operation
| DEC_IEEE_854_Overflow
102 | DEC_IEEE_854_Underflow
;
103 dec_flags
&= context
.status
;
104 ieee_flags
= DFP_IEEE_FLAGS (dec_flags
);
106 DFP_HANDLE_EXCEPTIONS (ieee_flags
);
109 TO_ENCODED (&encoded_result
, &res
, &context
);
110 IEEE_TO_HOST (encoded_result
, &result
);
114 /* Binary operations. */
116 static inline DFP_C_TYPE
117 dfp_binary_op (dfp_binary_func op
, DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
121 decNumber arg1
, arg2
, res
;
122 IEEE_TYPE a
, b
, encoded_result
;
124 HOST_TO_IEEE (arg_a
, &a
);
125 HOST_TO_IEEE (arg_b
, &b
);
127 decContextDefault (&context
, CONTEXT_INIT
);
128 DFP_INIT_ROUNDMODE (context
.round
);
130 TO_INTERNAL (&a
, &arg1
);
131 TO_INTERNAL (&b
, &arg2
);
133 /* Perform the operation. */
134 op (&res
, &arg1
, &arg2
, &context
);
136 if (DFP_EXCEPTIONS_ENABLED
&& context
.status
!= 0)
138 /* decNumber exception flags we care about here. */
140 int dec_flags
= DEC_IEEE_854_Division_by_zero
| DEC_IEEE_854_Inexact
141 | DEC_IEEE_854_Invalid_operation
| DEC_IEEE_854_Overflow
142 | DEC_IEEE_854_Underflow
;
143 dec_flags
&= context
.status
;
144 ieee_flags
= DFP_IEEE_FLAGS (dec_flags
);
146 DFP_HANDLE_EXCEPTIONS (ieee_flags
);
149 TO_ENCODED (&encoded_result
, &res
, &context
);
150 IEEE_TO_HOST (encoded_result
, &result
);
154 /* Comparison operations. */
157 dfp_compare_op (dfp_binary_func op
, DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
161 decNumber arg1
, arg2
, res
;
164 HOST_TO_IEEE (arg_a
, &a
);
165 HOST_TO_IEEE (arg_b
, &b
);
167 decContextDefault (&context
, CONTEXT_INIT
);
168 DFP_INIT_ROUNDMODE (context
.round
);
170 TO_INTERNAL (&a
, &arg1
);
171 TO_INTERNAL (&b
, &arg2
);
173 /* Perform the comparison. */
174 op (&res
, &arg1
, &arg2
, &context
);
176 if (decNumberIsNegative (&res
))
178 else if (decNumberIsZero (&res
))
180 else if (decNumberIsNaN (&res
))
189 #if defined(L_conv_sd)
191 __host_to_ieee_32 (_Decimal32 in
, decimal32
*out
)
195 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN
)
198 t
= __dec_byte_swap (t
);
202 memcpy (out
, &in
, 4);
206 __ieee_to_host_32 (decimal32 in
, _Decimal32
*out
)
210 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN
)
213 t
= __dec_byte_swap (t
);
217 memcpy (out
, &in
, 4);
219 #endif /* L_conv_sd */
221 #if defined(L_conv_dd)
223 __swap64 (char *src
, char *dst
)
227 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN
)
229 memcpy (&t1
, src
, 4);
230 memcpy (&t2
, src
+ 4, 4);
231 t1
= __dec_byte_swap (t1
);
232 t2
= __dec_byte_swap (t2
);
233 memcpy (dst
, &t2
, 4);
234 memcpy (dst
+ 4, &t1
, 4);
237 memcpy (dst
, src
, 8);
241 __host_to_ieee_64 (_Decimal64 in
, decimal64
*out
)
243 __swap64 ((char *) &in
, (char *) out
);
247 __ieee_to_host_64 (decimal64 in
, _Decimal64
*out
)
249 __swap64 ((char *) &in
, (char *) out
);
251 #endif /* L_conv_dd */
253 #if defined(L_conv_td)
255 __swap128 (char *src
, char *dst
)
257 uint32_t t1
, t2
, t3
, t4
;
259 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN
)
261 memcpy (&t1
, src
, 4);
262 memcpy (&t2
, src
+ 4, 4);
263 memcpy (&t3
, src
+ 8, 4);
264 memcpy (&t4
, src
+ 12, 4);
265 t1
= __dec_byte_swap (t1
);
266 t2
= __dec_byte_swap (t2
);
267 t3
= __dec_byte_swap (t3
);
268 t4
= __dec_byte_swap (t4
);
269 memcpy (dst
, &t4
, 4);
270 memcpy (dst
+ 4, &t3
, 4);
271 memcpy (dst
+ 8, &t2
, 4);
272 memcpy (dst
+ 12, &t1
, 4);
275 memcpy (dst
, src
, 16);
279 __host_to_ieee_128 (_Decimal128 in
, decimal128
*out
)
281 __swap128 ((char *) &in
, (char *) out
);
285 __ieee_to_host_128 (decimal128 in
, _Decimal128
*out
)
287 __swap128 ((char *) &in
, (char *) out
);
289 #endif /* L_conv_td */
291 #if defined(L_addsub_sd) || defined(L_addsub_dd) || defined(L_addsub_td)
293 DFP_ADD (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
295 return dfp_binary_op (decNumberAdd
, arg_a
, arg_b
);
299 DFP_SUB (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
301 return dfp_binary_op (decNumberSubtract
, arg_a
, arg_b
);
303 #endif /* L_addsub */
305 #if defined(L_mul_sd) || defined(L_mul_dd) || defined(L_mul_td)
307 DFP_MULTIPLY (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
309 return dfp_binary_op (decNumberMultiply
, arg_a
, arg_b
);
313 #if defined(L_div_sd) || defined(L_div_dd) || defined(L_div_td)
315 DFP_DIVIDE (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
317 return dfp_binary_op (decNumberDivide
, arg_a
, arg_b
);
321 #if defined (L_eq_sd) || defined (L_eq_dd) || defined (L_eq_td)
323 DFP_EQ (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
326 stat
= dfp_compare_op (decNumberCompare
, arg_a
, arg_b
);
327 /* For EQ return zero for true, nonzero for false. */
332 #if defined (L_ne_sd) || defined (L_ne_dd) || defined (L_ne_td)
334 DFP_NE (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
337 stat
= dfp_compare_op (decNumberCompare
, arg_a
, arg_b
);
338 /* For NE return zero for true, nonzero for false. */
339 if (__builtin_expect (stat
== -2, 0)) /* An operand is NaN. */
345 #if defined (L_lt_sd) || defined (L_lt_dd) || defined (L_lt_td)
347 DFP_LT (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
350 stat
= dfp_compare_op (decNumberCompare
, arg_a
, arg_b
);
351 /* For LT return -1 (<0) for true, 1 for false. */
352 return (stat
== -1) ? -1 : 1;
356 #if defined (L_gt_sd) || defined (L_gt_dd) || defined (L_gt_td)
358 DFP_GT (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
361 stat
= dfp_compare_op (decNumberCompare
, arg_a
, arg_b
);
362 /* For GT return 1 (>0) for true, -1 for false. */
363 return (stat
== 1) ? 1 : -1;
367 #if defined (L_le_sd) || defined (L_le_dd) || defined (L_le_td)
369 DFP_LE (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
372 stat
= dfp_compare_op (decNumberCompare
, arg_a
, arg_b
);
373 /* For LE return 0 (<= 0) for true, 1 for false. */
374 if (__builtin_expect (stat
== -2, 0)) /* An operand is NaN. */
380 #if defined (L_ge_sd) || defined (L_ge_dd) || defined (L_ge_td)
382 DFP_GE (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
385 stat
= dfp_compare_op (decNumberCompare
, arg_a
, arg_b
);
386 /* For GE return 1 (>=0) for true, -1 for false. */
387 if (__builtin_expect (stat
== -2, 0)) /* An operand is NaN. */
389 return (stat
!= -1) ? 1 : -1;
395 #if defined (L_sd_to_dd) || defined (L_sd_to_td) || defined (L_dd_to_sd) \
396 || defined (L_dd_to_td) || defined (L_td_to_sd) || defined (L_td_to_dd)
398 DFP_TO_DFP (DFP_C_TYPE f_from
)
406 decContextDefault (&context
, CONTEXT_INIT
);
407 DFP_INIT_ROUNDMODE (context
.round
);
409 HOST_TO_IEEE (f_from
, &s_from
);
410 TO_INTERNAL (&s_from
, &d
);
411 TO_ENCODED_TO (&s_to
, &d
, &context
);
413 if (DFP_EXCEPTIONS_ENABLED
&& context
.status
!= 0)
415 /* decNumber exception flags we care about here. */
417 int dec_flags
= DEC_IEEE_854_Inexact
| DEC_IEEE_854_Invalid_operation
418 | DEC_IEEE_854_Overflow
;
419 dec_flags
&= context
.status
;
420 ieee_flags
= DFP_IEEE_FLAGS (dec_flags
);
422 DFP_HANDLE_EXCEPTIONS (ieee_flags
);
425 IEEE_TO_HOST_TO (s_to
, &f_to
);
430 #if defined (L_sd_to_si) || defined (L_dd_to_si) || defined (L_td_to_si) \
431 || defined (L_sd_to_di) || defined (L_dd_to_di) || defined (L_td_to_di) \
432 || defined (L_sd_to_usi) || defined (L_dd_to_usi) || defined (L_td_to_usi) \
433 || defined (L_sd_to_udi) || defined (L_dd_to_udi) || defined (L_td_to_udi)
435 DFP_TO_INT (DFP_C_TYPE x
)
437 /* decNumber's decimal* types have the same format as C's _Decimal*
438 types, but they have different calling conventions. */
440 /* TODO: Decimal float to integer conversions should raise FE_INVALID
441 if the result value does not fit into the result type. */
446 decNumber qval
, n1
, n2
;
449 /* Use a large context to avoid losing precision. */
450 decContextDefault (&context
, DEC_INIT_DECIMAL128
);
451 /* Need non-default rounding mode here. */
452 context
.round
= DEC_ROUND_DOWN
;
454 HOST_TO_IEEE (x
, &s
);
455 TO_INTERNAL (&s
, &n1
);
456 /* Rescale if the exponent is less than zero. */
457 decNumberToIntegralValue (&n2
, &n1
, &context
);
458 /* Get a value to use for the quantize call. */
459 decNumberFromString (&qval
, (char *) "1.", &context
);
460 /* Force the exponent to zero. */
461 decNumberQuantize (&n1
, &n2
, &qval
, &context
);
462 /* Get a string, which at this point will not include an exponent. */
463 decNumberToString (&n1
, buf
);
464 /* Ignore the fractional part. */
465 pos
= strchr (buf
, '.');
468 /* Use a C library function to convert to the integral type. */
469 return STR_TO_INT (buf
, NULL
, 10);
473 #if defined (L_si_to_sd) || defined (L_si_to_dd) || defined (L_si_to_td) \
474 || defined (L_di_to_sd) || defined (L_di_to_dd) || defined (L_di_to_td) \
475 || defined (L_usi_to_sd) || defined (L_usi_to_dd) || defined (L_usi_to_td) \
476 || defined (L_udi_to_sd) || defined (L_udi_to_dd) || defined (L_udi_to_td)
478 INT_TO_DFP (INT_TYPE i
)
485 decContextDefault (&context
, CONTEXT_INIT
);
486 DFP_INIT_ROUNDMODE (context
.round
);
488 /* Use a C library function to get a floating point string. */
489 sprintf (buf
, INT_FMT
".0", CAST_FOR_FMT(i
));
490 /* Convert from the floating point string to a decimal* type. */
491 FROM_STRING (&s
, buf
, &context
);
492 IEEE_TO_HOST (s
, &f
);
494 if (DFP_EXCEPTIONS_ENABLED
&& context
.status
!= 0)
496 /* decNumber exception flags we care about here. */
498 int dec_flags
= DEC_IEEE_854_Inexact
| DEC_IEEE_854_Invalid_operation
499 | DEC_IEEE_854_Overflow
;
500 dec_flags
&= context
.status
;
501 ieee_flags
= DFP_IEEE_FLAGS (dec_flags
);
503 DFP_HANDLE_EXCEPTIONS (ieee_flags
);
510 #if defined (L_sd_to_sf) || defined (L_dd_to_sf) || defined (L_td_to_sf) \
511 || defined (L_sd_to_df) || defined (L_dd_to_df) || defined (L_td_to_df) \
512 || ((defined (L_sd_to_xf) || defined (L_dd_to_xf) || defined (L_td_to_xf)) \
513 && LIBGCC2_HAS_XF_MODE)
515 DFP_TO_BFP (DFP_C_TYPE f
)
520 HOST_TO_IEEE (f
, &s
);
521 /* Write the value to a string. */
523 /* Read it as the binary floating point type and return that. */
524 return STR_TO_BFP (buf
, NULL
);
528 #if defined (L_sf_to_sd) || defined (L_sf_to_dd) || defined (L_sf_to_td) \
529 || defined (L_df_to_sd) || defined (L_df_to_dd) || defined (L_df_to_td) \
530 || ((defined (L_xf_to_sd) || defined (L_xf_to_dd) || defined (L_xf_to_td)) \
531 && LIBGCC2_HAS_XF_MODE)
533 BFP_TO_DFP (BFP_TYPE x
)
540 decContextDefault (&context
, CONTEXT_INIT
);
541 DFP_INIT_ROUNDMODE (context
.round
);
543 /* Use a C library function to write the floating point value to a string. */
545 /* FIXME: Is there a better way to output an XFmode variable in C? */
546 sprintf (buf
, BFP_FMT
, (BFP_VIA_TYPE
) x
);
548 sprintf (buf
, BFP_FMT
, x
);
551 /* Convert from the floating point string to a decimal* type. */
552 FROM_STRING (&s
, buf
, &context
);
553 IEEE_TO_HOST (s
, &f
);
555 if (DFP_EXCEPTIONS_ENABLED
&& context
.status
!= 0)
557 /* decNumber exception flags we care about here. */
559 int dec_flags
= DEC_IEEE_854_Inexact
| DEC_IEEE_854_Invalid_operation
560 | DEC_IEEE_854_Overflow
| DEC_IEEE_854_Underflow
;
561 dec_flags
&= context
.status
;
562 ieee_flags
= DFP_IEEE_FLAGS (dec_flags
);
564 DFP_HANDLE_EXCEPTIONS (ieee_flags
);
571 #if defined (L_unord_sd) || defined (L_unord_dd) || defined (L_unord_td)
573 DFP_UNORD (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
575 decNumber arg1
, arg2
;
578 HOST_TO_IEEE (arg_a
, &a
);
579 HOST_TO_IEEE (arg_b
, &b
);
580 TO_INTERNAL (&a
, &arg1
);
581 TO_INTERNAL (&b
, &arg2
);
582 return (decNumberIsNaN (&arg1
) || decNumberIsNaN (&arg2
));
584 #endif /* L_unord_sd || L_unord_dd || L_unord_td */
586 /* !(L_sd_to_tf || L_dd_to_tf || L_td_to_tf \
587 || L_tf_to_sd || L_tf_to_dd || L_tf_to_td) */