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
*, 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
)
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
))
94 TO_ENCODED (&encoded_result
, &res
, &context
);
95 IEEE_TO_HOST (encoded_result
, &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
)
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
))
124 TO_ENCODED (&encoded_result
, &res
, &context
);
125 IEEE_TO_HOST (encoded_result
, &result
);
129 /* Comparison operations. */
132 dfp_compare_op (dfp_binary_func op
, DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
136 decNumber arg1
, arg2
, res
;
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
))
154 if (decNumberIsNegative (&res
))
156 else if (decNumberIsZero (&res
))
165 #if defined(L_conv_sd)
167 __host_to_ieee_32 (_Decimal32 in
, decimal32
*out
)
171 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN
)
174 t
= __dec_byte_swap (t
);
178 memcpy (out
, &in
, 4);
182 __ieee_to_host_32 (decimal32 in
, _Decimal32
*out
)
186 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN
)
189 t
= __dec_byte_swap (t
);
193 memcpy (out
, &in
, 4);
195 #endif /* L_conv_sd */
197 #if defined(L_conv_dd)
199 __swap64 (char *src
, char *dst
)
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);
213 memcpy (dst
, src
, 8);
217 __host_to_ieee_64 (_Decimal64 in
, decimal64
*out
)
219 __swap64 ((char *) &in
, (char *) out
);
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)
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);
251 memcpy (dst
, src
, 16);
255 __host_to_ieee_128 (_Decimal128 in
, decimal128
*out
)
257 __swap128 ((char *) &in
, (char *) out
);
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)
269 DFP_ADD (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
271 return dfp_binary_op (decNumberAdd
, arg_a
, arg_b
);
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)
283 DFP_MULTIPLY (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
285 return dfp_binary_op (decNumberMultiply
, arg_a
, arg_b
);
289 #if defined(L_div_sd) || defined(L_div_dd) || defined(L_div_td)
291 DFP_DIVIDE (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
293 return dfp_binary_op (decNumberDivide
, arg_a
, arg_b
);
297 #if defined (L_eq_sd) || defined (L_eq_dd) || defined (L_eq_td)
299 DFP_EQ (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
302 stat
= dfp_compare_op (decNumberCompare
, arg_a
, arg_b
);
303 /* For EQ return zero for true, nonzero for false. */
308 #if defined (L_ne_sd) || defined (L_ne_dd) || defined (L_ne_td)
310 DFP_NE (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
313 stat
= dfp_compare_op (decNumberCompare
, arg_a
, arg_b
);
314 /* For NE return nonzero for true, zero for false. */
319 #if defined (L_lt_sd) || defined (L_lt_dd) || defined (L_lt_td)
321 DFP_LT (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
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;
330 #if defined (L_gt_sd) || defined (L_gt_dd) || defined (L_gt_td)
332 DFP_GT (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
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;
341 #if defined (L_le_sd) || defined (L_le_dd) || defined (L_le_td)
343 DFP_LE (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
346 stat
= dfp_compare_op (decNumberCompare
, arg_a
, arg_b
);
347 /* For LE return 0 (<= 0) for true, 1 for false. */
352 #if defined (L_ge_sd) || defined (L_ge_dd) || defined (L_ge_td)
354 DFP_GE (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
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;
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)
368 DFP_TO_DFP (DFP_C_TYPE f_from
)
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
);
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)
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. */
403 decNumber qval
, n1
, n2
;
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
))
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);
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)
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;
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
, '.');
447 /* Use a C library function to convert to the integral type. */
448 return STR_TO_INT (buf
, NULL
, 10);
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)
457 INT_TO_DFP (INT_TYPE i
)
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
);
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)
483 DFP_TO_BFP (DFP_C_TYPE f
)
488 HOST_TO_IEEE (f
, &s
);
489 /* Write the value to a string. */
491 /* Read it as the binary floating point type and return that. */
492 return STR_TO_BFP (buf
, NULL
);
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)
501 BFP_TO_DFP (BFP_TYPE x
)
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. */
513 /* FIXME: Is there a better way to output an XFmode variable in C? */
514 sprintf (buf
, BFP_FMT
, (BFP_VIA_TYPE
) x
);
516 sprintf (buf
, BFP_FMT
, x
);
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
);
528 #if defined (L_unord_sd) || defined (L_unord_dd) || defined (L_unord_td)
530 DFP_UNORD (DFP_C_TYPE arg_a
, DFP_C_TYPE arg_b
)
532 decNumber arg1
, arg2
;
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 */