2007-01-03 Paul Brook <paul@codesourcery.com>
[official-gcc.git] / gcc / config / dfp-bit.c
blob0ee2083e835b7f0bf43392f08fab5edb016ecd2b
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
9 version.
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
18 executable.)
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
23 for more details.
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
28 02110-1301, USA. */
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 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <limits.h>
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);
51 #endif
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);
55 #endif
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);
59 #endif
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)
76 DFP_C_TYPE result;
77 decContext context;
78 decNumber arg1, res;
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);
93 return 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)
101 DFP_C_TYPE result;
102 decContext context;
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);
120 return result;
123 /* Comparison operations. */
125 static inline int
126 dfp_compare_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
128 IEEE_TYPE a, b;
129 decContext context;
130 decNumber arg1, arg2, res;
131 int result;
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))
146 result = -1;
147 else if (decNumberIsZero (&res))
148 result = 0;
149 else
150 result = 1;
152 return result;
156 #if defined(L_conv_sd)
157 void
158 __host_to_ieee_32 (_Decimal32 in, decimal32 *out)
160 uint32_t t;
162 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
164 memcpy (&t, &in, 4);
165 t = __dec_byte_swap (t);
166 memcpy (out, &t, 4);
168 else
169 memcpy (out, &in, 4);
172 void
173 __ieee_to_host_32 (decimal32 in, _Decimal32 *out)
175 uint32_t t;
177 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
179 memcpy (&t, &in, 4);
180 t = __dec_byte_swap (t);
181 memcpy (out, &t, 4);
183 else
184 memcpy (out, &in, 4);
186 #endif /* L_conv_sd */
188 #if defined(L_conv_dd)
189 static void
190 __swap64 (char *src, char *dst)
192 uint32_t t1, t2;
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);
203 else
204 memcpy (dst, src, 8);
207 void
208 __host_to_ieee_64 (_Decimal64 in, decimal64 *out)
210 __swap64 ((char *) &in, (char *) out);
213 void
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)
221 static void
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);
241 else
242 memcpy (dst, src, 16);
245 void
246 __host_to_ieee_128 (_Decimal128 in, decimal128 *out)
248 __swap128 ((char *) &in, (char *) out);
251 void
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)
259 DFP_C_TYPE
260 DFP_ADD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
262 return dfp_binary_op (decNumberAdd, arg_a, arg_b);
265 DFP_C_TYPE
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)
273 DFP_C_TYPE
274 DFP_MULTIPLY (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
276 return dfp_binary_op (decNumberMultiply, arg_a, arg_b);
278 #endif /* L_mul */
280 #if defined(L_div_sd) || defined(L_div_dd) || defined(L_div_td)
281 DFP_C_TYPE
282 DFP_DIVIDE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
284 return dfp_binary_op (decNumberDivide, arg_a, arg_b);
286 #endif /* L_div */
288 #if defined (L_eq_sd) || defined (L_eq_dd) || defined (L_eq_td)
289 CMPtype
290 DFP_EQ (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
292 int stat;
293 stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
294 /* For EQ return zero for true, nonzero for false. */
295 return stat != 0;
297 #endif /* L_eq */
299 #if defined (L_ne_sd) || defined (L_ne_dd) || defined (L_ne_td)
300 CMPtype
301 DFP_NE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
303 int stat;
304 stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
305 /* For NE return nonzero for true, zero for false. */
306 return stat != 0;
308 #endif /* L_ne */
310 #if defined (L_lt_sd) || defined (L_lt_dd) || defined (L_lt_td)
311 CMPtype
312 DFP_LT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
314 int stat;
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;
319 #endif /* L_lt */
321 #if defined (L_gt_sd) || defined (L_gt_dd) || defined (L_gt_td)
322 CMPtype
323 DFP_GT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
325 int stat;
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;
330 #endif
332 #if defined (L_le_sd) || defined (L_le_dd) || defined (L_le_td)
333 CMPtype
334 DFP_LE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
336 int stat;
337 stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
338 /* For LE return 0 (<= 0) for true, 1 for false. */
339 return stat == 1;
341 #endif /* L_le */
343 #if defined (L_ge_sd) || defined (L_ge_dd) || defined (L_ge_td)
344 CMPtype
345 DFP_GE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
347 int stat;
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;
352 #endif /* L_ge */
354 #define BUFMAX 128
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)
358 DFP_C_TYPE_TO
359 DFP_TO_DFP (DFP_C_TYPE f_from)
361 DFP_C_TYPE_TO f_to;
362 IEEE_TYPE s_from;
363 IEEE_TYPE_TO s_to;
364 decNumber d;
365 decContext context;
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);
375 return f_to;
377 #endif
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)
383 INT_TYPE
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. */
389 IEEE_TYPE s;
390 char buf[BUFMAX];
391 char *pos;
392 decNumber qval, n1, n2;
393 decContext context;
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, '.');
412 if (pos)
413 *pos = 0;
414 /* Use a C library function to convert to the integral type. */
415 return STR_TO_INT (buf, NULL, 10);
417 #endif
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)
423 DFP_C_TYPE
424 INT_TO_DFP (INT_TYPE i)
426 DFP_C_TYPE f;
427 IEEE_TYPE s;
428 char buf[BUFMAX];
429 decContext context;
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);
439 return f;
441 #endif
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)
447 BFP_TYPE
448 DFP_TO_BFP (DFP_C_TYPE f)
450 IEEE_TYPE s;
451 char buf[BUFMAX];
453 HOST_TO_IEEE (f, &s);
454 /* Write the value to a string. */
455 TO_STRING (&s, buf);
456 /* Read it as the binary floating point type and return that. */
457 return STR_TO_BFP (buf, NULL);
459 #endif
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)
465 DFP_C_TYPE
466 BFP_TO_DFP (BFP_TYPE x)
468 DFP_C_TYPE f;
469 IEEE_TYPE s;
470 char buf[BUFMAX];
471 decContext context;
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. */
477 #ifdef BFP_VIA_TYPE
478 /* FIXME: Is there a better way to output an XFmode variable in C? */
479 sprintf (buf, BFP_FMT, (BFP_VIA_TYPE) x);
480 #else
481 sprintf (buf, BFP_FMT, x);
482 #endif
484 /* Convert from the floating point string to a decimal* type. */
485 FROM_STRING (&s, buf, &context);
486 IEEE_TO_HOST (s, &f);
487 return f;
489 #endif
491 #if defined (L_unord_sd) || defined (L_unord_dd) || defined (L_unord_td)
492 CMPtype
493 DFP_UNORD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
495 decNumber arg1, arg2;
496 IEEE_TYPE a, b;
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 */