]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/gcc/config/dfp-bit.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / gcc / config / dfp-bit.c
1 /* This is a software decimal floating point library.
2    Copyright (C) 2005, 2006 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 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <limits.h>
44
45 #include "config/dfp-bit.h"
46
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
60
61 /* A pointer to a unary decNumber operation.  */
62 typedef decNumber* (*dfp_unary_func)
63      (decNumber *, decNumber *, decContext *);
64
65 /* A pointer to a binary decNumber operation.  */
66 typedef decNumber* (*dfp_binary_func)
67      (decNumber *, decNumber *, decNumber *, decContext *);
68
69 extern unsigned long __dec_byte_swap (unsigned long);
70 \f
71 /* Unary operations.  */
72
73 static inline DFP_C_TYPE
74 dfp_unary_op (dfp_unary_func op, DFP_C_TYPE arg)
75 {
76   DFP_C_TYPE result;
77   decContext context;
78   decNumber arg1, res;
79   IEEE_TYPE a, encoded_result;
80
81   HOST_TO_IEEE (arg, &a);
82
83   decContextDefault (&context, CONTEXT_INIT);
84   context.round = CONTEXT_ROUND;
85
86   TO_INTERNAL (&a, &arg1);
87
88   /* Perform the operation.  */
89   op (&res, &arg1, &context);
90
91   if (CONTEXT_TRAPS && CONTEXT_ERRORS (context))
92     DFP_RAISE (0);
93
94   TO_ENCODED (&encoded_result, &res, &context);
95   IEEE_TO_HOST (encoded_result, &result);
96   return result;
97 }
98
99 /* Binary operations.  */
100
101 static inline DFP_C_TYPE
102 dfp_binary_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
103 {
104   DFP_C_TYPE result;
105   decContext context;
106   decNumber arg1, arg2, res;
107   IEEE_TYPE a, b, encoded_result;
108
109   HOST_TO_IEEE (arg_a, &a);
110   HOST_TO_IEEE (arg_b, &b);
111
112   decContextDefault (&context, CONTEXT_INIT);
113   context.round = CONTEXT_ROUND;
114
115   TO_INTERNAL (&a, &arg1);
116   TO_INTERNAL (&b, &arg2);
117
118   /* Perform the operation.  */
119   op (&res, &arg1, &arg2, &context);
120
121   if (CONTEXT_TRAPS && CONTEXT_ERRORS (context))
122     DFP_RAISE (0);
123
124   TO_ENCODED (&encoded_result, &res, &context);
125   IEEE_TO_HOST (encoded_result, &result);
126   return result;
127 }
128
129 /* Comparison operations.  */
130
131 static inline int
132 dfp_compare_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
133 {
134   IEEE_TYPE a, b;
135   decContext context;
136   decNumber arg1, arg2, res;
137   int result;
138
139   HOST_TO_IEEE (arg_a, &a);
140   HOST_TO_IEEE (arg_b, &b);
141
142   decContextDefault (&context, CONTEXT_INIT);
143   context.round = CONTEXT_ROUND;
144
145   TO_INTERNAL (&a, &arg1);
146   TO_INTERNAL (&b, &arg2);
147
148   /* Perform the comparison.  */
149   op (&res, &arg1, &arg2, &context);
150
151   if (CONTEXT_TRAPS && CONTEXT_ERRORS (context))
152     DFP_RAISE (0);
153
154   if (decNumberIsNegative (&res))
155     result = -1;
156   else if (decNumberIsZero (&res))
157     result = 0;
158   else
159     result = 1;
160
161   return result;
162 }
163
164 \f
165 #if defined(L_conv_sd)
166 void
167 __host_to_ieee_32 (_Decimal32 in, decimal32 *out)
168 {
169   uint32_t t;
170
171   if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
172     {
173       memcpy (&t, &in, 4);
174       t = __dec_byte_swap (t);
175       memcpy (out, &t, 4);
176     }
177   else
178     memcpy (out, &in, 4);
179 }
180
181 void
182 __ieee_to_host_32 (decimal32 in, _Decimal32 *out)
183 {
184   uint32_t t;
185
186   if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
187     {
188       memcpy (&t, &in, 4);
189       t = __dec_byte_swap (t);
190       memcpy (out, &t, 4);
191     }
192   else
193     memcpy (out, &in, 4);
194 }
195 #endif /* L_conv_sd */
196
197 #if defined(L_conv_dd)
198 static void
199 __swap64 (char *src, char *dst)
200 {
201   uint32_t t1, t2;
202
203   if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN) 
204     {
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);
211     }
212   else
213     memcpy (dst, src, 8);
214 }
215
216 void
217 __host_to_ieee_64 (_Decimal64 in, decimal64 *out)
218 {
219   __swap64 ((char *) &in, (char *) out);
220 }
221
222 void
223 __ieee_to_host_64 (decimal64 in, _Decimal64 *out)
224 {
225   __swap64 ((char *) &in, (char *) out);
226 }
227 #endif /* L_conv_dd */
228
229 #if defined(L_conv_td)
230 static void
231 __swap128 (char *src, char *dst)
232 {
233   uint32_t t1, t2, t3, t4;
234
235   if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
236     {
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);
249     }
250   else
251     memcpy (dst, src, 16);
252 }
253
254 void
255 __host_to_ieee_128 (_Decimal128 in, decimal128 *out)
256 {
257   __swap128 ((char *) &in, (char *) out);
258 }
259
260 void
261 __ieee_to_host_128 (decimal128 in, _Decimal128 *out)
262 {
263   __swap128 ((char *) &in, (char *) out);
264 }
265 #endif /* L_conv_td */
266
267 #if defined(L_addsub_sd) || defined(L_addsub_dd) || defined(L_addsub_td)
268 DFP_C_TYPE
269 DFP_ADD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
270 {
271   return dfp_binary_op (decNumberAdd, arg_a, arg_b);
272 }
273
274 DFP_C_TYPE
275 DFP_SUB (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
276 {
277   return dfp_binary_op (decNumberSubtract, arg_a, arg_b);
278 }
279 #endif /* L_addsub */
280
281 #if defined(L_mul_sd) || defined(L_mul_dd) || defined(L_mul_td)
282 DFP_C_TYPE
283 DFP_MULTIPLY (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
284 {
285   return dfp_binary_op (decNumberMultiply, arg_a, arg_b);
286 }
287 #endif /* L_mul */
288
289 #if defined(L_div_sd) || defined(L_div_dd) || defined(L_div_td)
290 DFP_C_TYPE
291 DFP_DIVIDE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
292 {
293   return dfp_binary_op (decNumberDivide, arg_a, arg_b);
294 }
295 #endif /* L_div */
296
297 #if defined (L_eq_sd) || defined (L_eq_dd) || defined (L_eq_td)
298 CMPtype
299 DFP_EQ (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
300 {
301   int stat;
302   stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
303   /* For EQ return zero for true, nonzero for false.  */
304   return stat != 0;
305 }
306 #endif /* L_eq */
307
308 #if defined (L_ne_sd) || defined (L_ne_dd) || defined (L_ne_td)
309 CMPtype
310 DFP_NE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
311 {
312   int stat;
313   stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
314   /* For NE return nonzero for true, zero for false.  */
315   return stat != 0;
316 }
317 #endif /* L_ne */
318
319 #if defined (L_lt_sd) || defined (L_lt_dd) || defined (L_lt_td)
320 CMPtype
321 DFP_LT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
322 {
323   int stat;
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;
327 }
328 #endif /* L_lt */
329
330 #if defined (L_gt_sd) || defined (L_gt_dd) || defined (L_gt_td)
331 CMPtype
332 DFP_GT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
333 {
334   int stat;
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;
338 }
339 #endif
340
341 #if defined (L_le_sd) || defined (L_le_dd) || defined (L_le_td)
342 CMPtype
343 DFP_LE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
344 {
345   int stat;
346   stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
347   /* For LE return 0 (<= 0) for true, 1 for false.  */
348   return stat == 1;
349 }
350 #endif /* L_le */
351
352 #if defined (L_ge_sd) || defined (L_ge_dd) || defined (L_ge_td)
353 CMPtype
354 DFP_GE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
355 {
356   int stat;
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;
360 }
361 #endif /* L_ge */
362
363 #define BUFMAX 128
364
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)
367 DFP_C_TYPE_TO
368 DFP_TO_DFP (DFP_C_TYPE f_from)
369 {
370   DFP_C_TYPE_TO f_to;
371   IEEE_TYPE s_from;
372   IEEE_TYPE_TO s_to;
373   decNumber d;
374   decContext context;
375
376   decContextDefault (&context, CONTEXT_INIT);
377   context.round = CONTEXT_ROUND;
378
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);
384
385   IEEE_TO_HOST_TO (s_to, &f_to);
386   return f_to;
387 }
388 #endif
389
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)
394 INT_TYPE
395 DFP_TO_INT (DFP_C_TYPE x)
396 {
397   /* decNumber's decimal* types have the same format as C's _Decimal*
398      types, but they have different calling conventions.  */
399
400   IEEE_TYPE s;
401   char buf[BUFMAX];
402   char *pos;
403   decNumber qval, n1, n2;
404   decContext context;
405
406   decContextDefault (&context, CONTEXT_INIT);
407   /* Need non-default rounding mode here.  */
408   context.round = DEC_ROUND_DOWN;
409
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)
421     {
422 #if defined (L_sd_to_si) || defined (L_dd_to_si) || defined (L_td_to_si)
423       if (decNumberIsNegative(&n2))
424         return INT_MIN;
425       else
426         return INT_MAX;
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);
431       else
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)
435       return UINT_MAX;
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;
439 #endif
440     }
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, '.');
445   if (pos)
446     *pos = 0;
447   /* Use a C library function to convert to the integral type.  */
448   return STR_TO_INT (buf, NULL, 10);
449 }
450 #endif
451
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)
456 DFP_C_TYPE
457 INT_TO_DFP (INT_TYPE i)
458 {
459   DFP_C_TYPE f;
460   IEEE_TYPE s;
461   char buf[BUFMAX];
462   decContext context;
463
464   decContextDefault (&context, CONTEXT_INIT);
465   context.round = CONTEXT_ROUND;
466
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);
474   return f;
475 }
476 #endif
477
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)
482 BFP_TYPE
483 DFP_TO_BFP (DFP_C_TYPE f)
484 {
485   IEEE_TYPE s;
486   char buf[BUFMAX];
487
488   HOST_TO_IEEE (f, &s);
489   /* Write the value to a string.  */
490   TO_STRING (&s, buf);
491   /* Read it as the binary floating point type and return that.  */
492   return STR_TO_BFP (buf, NULL);
493 }
494 #endif
495                                                                                 
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)
500 DFP_C_TYPE
501 BFP_TO_DFP (BFP_TYPE x)
502 {
503   DFP_C_TYPE f;
504   IEEE_TYPE s;
505   char buf[BUFMAX];
506   decContext context;
507
508   decContextDefault (&context, CONTEXT_INIT);
509   context.round = CONTEXT_ROUND;
510
511   /* Use a C library function to write the floating point value to a string.  */
512 #ifdef BFP_VIA_TYPE
513   /* FIXME: Is there a better way to output an XFmode variable in C?  */
514   sprintf (buf, BFP_FMT, (BFP_VIA_TYPE) x);
515 #else
516   sprintf (buf, BFP_FMT, x);
517 #endif
518
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);
524   return f;
525 }
526 #endif
527
528 #if defined (L_unord_sd) || defined (L_unord_dd) || defined (L_unord_td)
529 CMPtype
530 DFP_UNORD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
531 {
532   decNumber arg1, arg2;
533   IEEE_TYPE a, b;
534
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));
540 }
541 #endif /* L_unord_sd || L_unord_dd || L_unord_td */