mt-sde (CFLAGS_FOR_TARGET): Add -mno-gpopt.
[gcc.git] / gcc / config / dfp-bit.c
1 /* This is a software decimal floating point library.
2 Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
3
4 This file is part of GCC.
5
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.
10
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.)
19
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.
24
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. */
29
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.
34
35 Contributed by Ben Elliston <bje@au.ibm.com>. */
36
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. */
39
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))
44
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <limits.h>
49
50 #include "config/dfp-bit.h"
51
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);
56 #endif
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);
60 #endif
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);
64 #endif
65
66 /* A pointer to a unary decNumber operation. */
67 typedef decNumber* (*dfp_unary_func)
68 (decNumber *, decNumber *, decContext *);
69
70 /* A pointer to a binary decNumber operation. */
71 typedef decNumber* (*dfp_binary_func)
72 (decNumber *, const decNumber *, const decNumber *, decContext *);
73
74 extern uint32_t __dec_byte_swap (uint32_t);
75 \f
76 /* Unary operations. */
77
78 static inline DFP_C_TYPE
79 dfp_unary_op (dfp_unary_func op, DFP_C_TYPE arg)
80 {
81 DFP_C_TYPE result;
82 decContext context;
83 decNumber arg1, res;
84 IEEE_TYPE a, encoded_result;
85
86 HOST_TO_IEEE (arg, &a);
87
88 decContextDefault (&context, CONTEXT_INIT);
89 DFP_INIT_ROUNDMODE (context.round);
90
91 TO_INTERNAL (&a, &arg1);
92
93 /* Perform the operation. */
94 op (&res, &arg1, &context);
95
96 if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
97 {
98 /* decNumber exception flags we care about here. */
99 int ieee_flags;
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);
105 if (ieee_flags != 0)
106 DFP_HANDLE_EXCEPTIONS (ieee_flags);
107 }
108
109 TO_ENCODED (&encoded_result, &res, &context);
110 IEEE_TO_HOST (encoded_result, &result);
111 return result;
112 }
113
114 /* Binary operations. */
115
116 static inline DFP_C_TYPE
117 dfp_binary_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
118 {
119 DFP_C_TYPE result;
120 decContext context;
121 decNumber arg1, arg2, res;
122 IEEE_TYPE a, b, encoded_result;
123
124 HOST_TO_IEEE (arg_a, &a);
125 HOST_TO_IEEE (arg_b, &b);
126
127 decContextDefault (&context, CONTEXT_INIT);
128 DFP_INIT_ROUNDMODE (context.round);
129
130 TO_INTERNAL (&a, &arg1);
131 TO_INTERNAL (&b, &arg2);
132
133 /* Perform the operation. */
134 op (&res, &arg1, &arg2, &context);
135
136 if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
137 {
138 /* decNumber exception flags we care about here. */
139 int ieee_flags;
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);
145 if (ieee_flags != 0)
146 DFP_HANDLE_EXCEPTIONS (ieee_flags);
147 }
148
149 TO_ENCODED (&encoded_result, &res, &context);
150 IEEE_TO_HOST (encoded_result, &result);
151 return result;
152 }
153
154 /* Comparison operations. */
155
156 static inline int
157 dfp_compare_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
158 {
159 IEEE_TYPE a, b;
160 decContext context;
161 decNumber arg1, arg2, res;
162 int result;
163
164 HOST_TO_IEEE (arg_a, &a);
165 HOST_TO_IEEE (arg_b, &b);
166
167 decContextDefault (&context, CONTEXT_INIT);
168 DFP_INIT_ROUNDMODE (context.round);
169
170 TO_INTERNAL (&a, &arg1);
171 TO_INTERNAL (&b, &arg2);
172
173 /* Perform the comparison. */
174 op (&res, &arg1, &arg2, &context);
175
176 if (decNumberIsNegative (&res))
177 result = -1;
178 else if (decNumberIsZero (&res))
179 result = 0;
180 else if (decNumberIsNaN (&res))
181 result = -2;
182 else
183 result = 1;
184
185 return result;
186 }
187
188 \f
189 #if defined(L_conv_sd)
190 void
191 __host_to_ieee_32 (_Decimal32 in, decimal32 *out)
192 {
193 uint32_t t;
194
195 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
196 {
197 memcpy (&t, &in, 4);
198 t = __dec_byte_swap (t);
199 memcpy (out, &t, 4);
200 }
201 else
202 memcpy (out, &in, 4);
203 }
204
205 void
206 __ieee_to_host_32 (decimal32 in, _Decimal32 *out)
207 {
208 uint32_t t;
209
210 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
211 {
212 memcpy (&t, &in, 4);
213 t = __dec_byte_swap (t);
214 memcpy (out, &t, 4);
215 }
216 else
217 memcpy (out, &in, 4);
218 }
219 #endif /* L_conv_sd */
220
221 #if defined(L_conv_dd)
222 static void
223 __swap64 (char *src, char *dst)
224 {
225 uint32_t t1, t2;
226
227 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
228 {
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);
235 }
236 else
237 memcpy (dst, src, 8);
238 }
239
240 void
241 __host_to_ieee_64 (_Decimal64 in, decimal64 *out)
242 {
243 __swap64 ((char *) &in, (char *) out);
244 }
245
246 void
247 __ieee_to_host_64 (decimal64 in, _Decimal64 *out)
248 {
249 __swap64 ((char *) &in, (char *) out);
250 }
251 #endif /* L_conv_dd */
252
253 #if defined(L_conv_td)
254 static void
255 __swap128 (char *src, char *dst)
256 {
257 uint32_t t1, t2, t3, t4;
258
259 if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
260 {
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);
273 }
274 else
275 memcpy (dst, src, 16);
276 }
277
278 void
279 __host_to_ieee_128 (_Decimal128 in, decimal128 *out)
280 {
281 __swap128 ((char *) &in, (char *) out);
282 }
283
284 void
285 __ieee_to_host_128 (decimal128 in, _Decimal128 *out)
286 {
287 __swap128 ((char *) &in, (char *) out);
288 }
289 #endif /* L_conv_td */
290
291 #if defined(L_addsub_sd) || defined(L_addsub_dd) || defined(L_addsub_td)
292 DFP_C_TYPE
293 DFP_ADD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
294 {
295 return dfp_binary_op (decNumberAdd, arg_a, arg_b);
296 }
297
298 DFP_C_TYPE
299 DFP_SUB (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
300 {
301 return dfp_binary_op (decNumberSubtract, arg_a, arg_b);
302 }
303 #endif /* L_addsub */
304
305 #if defined(L_mul_sd) || defined(L_mul_dd) || defined(L_mul_td)
306 DFP_C_TYPE
307 DFP_MULTIPLY (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
308 {
309 return dfp_binary_op (decNumberMultiply, arg_a, arg_b);
310 }
311 #endif /* L_mul */
312
313 #if defined(L_div_sd) || defined(L_div_dd) || defined(L_div_td)
314 DFP_C_TYPE
315 DFP_DIVIDE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
316 {
317 return dfp_binary_op (decNumberDivide, arg_a, arg_b);
318 }
319 #endif /* L_div */
320
321 #if defined (L_eq_sd) || defined (L_eq_dd) || defined (L_eq_td)
322 CMPtype
323 DFP_EQ (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
324 {
325 int stat;
326 stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
327 /* For EQ return zero for true, nonzero for false. */
328 return stat != 0;
329 }
330 #endif /* L_eq */
331
332 #if defined (L_ne_sd) || defined (L_ne_dd) || defined (L_ne_td)
333 CMPtype
334 DFP_NE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
335 {
336 int stat;
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. */
340 return 1;
341 return stat != 0;
342 }
343 #endif /* L_ne */
344
345 #if defined (L_lt_sd) || defined (L_lt_dd) || defined (L_lt_td)
346 CMPtype
347 DFP_LT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
348 {
349 int stat;
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;
353 }
354 #endif /* L_lt */
355
356 #if defined (L_gt_sd) || defined (L_gt_dd) || defined (L_gt_td)
357 CMPtype
358 DFP_GT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
359 {
360 int stat;
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;
364 }
365 #endif
366
367 #if defined (L_le_sd) || defined (L_le_dd) || defined (L_le_td)
368 CMPtype
369 DFP_LE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
370 {
371 int stat;
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. */
375 return 1;
376 return stat == 1;
377 }
378 #endif /* L_le */
379
380 #if defined (L_ge_sd) || defined (L_ge_dd) || defined (L_ge_td)
381 CMPtype
382 DFP_GE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
383 {
384 int stat;
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. */
388 return -1;
389 return (stat != -1) ? 1 : -1;
390 }
391 #endif /* L_ge */
392
393 #define BUFMAX 128
394
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)
397 DFP_C_TYPE_TO
398 DFP_TO_DFP (DFP_C_TYPE f_from)
399 {
400 DFP_C_TYPE_TO f_to;
401 IEEE_TYPE s_from;
402 IEEE_TYPE_TO s_to;
403 decNumber d;
404 decContext context;
405
406 decContextDefault (&context, CONTEXT_INIT);
407 DFP_INIT_ROUNDMODE (context.round);
408
409 HOST_TO_IEEE (f_from, &s_from);
410 TO_INTERNAL (&s_from, &d);
411 TO_ENCODED_TO (&s_to, &d, &context);
412
413 if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
414 {
415 /* decNumber exception flags we care about here. */
416 int ieee_flags;
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);
421 if (ieee_flags != 0)
422 DFP_HANDLE_EXCEPTIONS (ieee_flags);
423 }
424
425 IEEE_TO_HOST_TO (s_to, &f_to);
426 return f_to;
427 }
428 #endif
429
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)
434 INT_TYPE
435 DFP_TO_INT (DFP_C_TYPE x)
436 {
437 /* decNumber's decimal* types have the same format as C's _Decimal*
438 types, but they have different calling conventions. */
439
440 /* TODO: Decimal float to integer conversions should raise FE_INVALID
441 if the result value does not fit into the result type. */
442
443 IEEE_TYPE s;
444 char buf[BUFMAX];
445 char *pos;
446 decNumber qval, n1, n2;
447 decContext context;
448
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;
453
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, '.');
466 if (pos)
467 *pos = 0;
468 /* Use a C library function to convert to the integral type. */
469 return STR_TO_INT (buf, NULL, 10);
470 }
471 #endif
472
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)
477 DFP_C_TYPE
478 INT_TO_DFP (INT_TYPE i)
479 {
480 DFP_C_TYPE f;
481 IEEE_TYPE s;
482 char buf[BUFMAX];
483 decContext context;
484
485 decContextDefault (&context, CONTEXT_INIT);
486 DFP_INIT_ROUNDMODE (context.round);
487
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);
493
494 if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
495 {
496 /* decNumber exception flags we care about here. */
497 int ieee_flags;
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);
502 if (ieee_flags != 0)
503 DFP_HANDLE_EXCEPTIONS (ieee_flags);
504 }
505
506 return f;
507 }
508 #endif
509
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)
514 BFP_TYPE
515 DFP_TO_BFP (DFP_C_TYPE f)
516 {
517 IEEE_TYPE s;
518 char buf[BUFMAX];
519
520 HOST_TO_IEEE (f, &s);
521 /* Write the value to a string. */
522 TO_STRING (&s, buf);
523 /* Read it as the binary floating point type and return that. */
524 return STR_TO_BFP (buf, NULL);
525 }
526 #endif
527
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)
532 DFP_C_TYPE
533 BFP_TO_DFP (BFP_TYPE x)
534 {
535 DFP_C_TYPE f;
536 IEEE_TYPE s;
537 char buf[BUFMAX];
538 decContext context;
539
540 decContextDefault (&context, CONTEXT_INIT);
541 DFP_INIT_ROUNDMODE (context.round);
542
543 /* Use a C library function to write the floating point value to a string. */
544 #ifdef BFP_VIA_TYPE
545 /* FIXME: Is there a better way to output an XFmode variable in C? */
546 sprintf (buf, BFP_FMT, (BFP_VIA_TYPE) x);
547 #else
548 sprintf (buf, BFP_FMT, x);
549 #endif
550
551 /* Convert from the floating point string to a decimal* type. */
552 FROM_STRING (&s, buf, &context);
553 IEEE_TO_HOST (s, &f);
554
555 if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
556 {
557 /* decNumber exception flags we care about here. */
558 int ieee_flags;
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);
563 if (ieee_flags != 0)
564 DFP_HANDLE_EXCEPTIONS (ieee_flags);
565 }
566
567 return f;
568 }
569 #endif
570
571 #if defined (L_unord_sd) || defined (L_unord_dd) || defined (L_unord_td)
572 CMPtype
573 DFP_UNORD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
574 {
575 decNumber arg1, arg2;
576 IEEE_TYPE a, b;
577
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));
583 }
584 #endif /* L_unord_sd || L_unord_dd || L_unord_td */
585
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) */
588 #endif