OSDN Git Service

* config/rs6000/rs6000.c (rs6000_emit_vector_compare): Fix build
[pf3gnuchains/gcc-fork.git] / 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 *, const decNumber *, const 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   DFP_INIT_ROUNDMODE (context.round);
85
86   TO_INTERNAL (&a, &arg1);
87
88   /* Perform the operation.  */
89   op (&res, &arg1, &context);
90
91   TO_ENCODED (&encoded_result, &res, &context);
92   IEEE_TO_HOST (encoded_result, &result);
93   return result;
94 }
95
96 /* Binary operations.  */
97
98 static inline DFP_C_TYPE
99 dfp_binary_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
100 {
101   DFP_C_TYPE result;
102   decContext context;
103   decNumber arg1, arg2, res;
104   IEEE_TYPE a, b, encoded_result;
105
106   HOST_TO_IEEE (arg_a, &a);
107   HOST_TO_IEEE (arg_b, &b);
108
109   decContextDefault (&context, CONTEXT_INIT);
110   DFP_INIT_ROUNDMODE (context.round);
111
112   TO_INTERNAL (&a, &arg1);
113   TO_INTERNAL (&b, &arg2);
114
115   /* Perform the operation.  */
116   op (&res, &arg1, &arg2, &context);
117
118   TO_ENCODED (&encoded_result, &res, &context);
119   IEEE_TO_HOST (encoded_result, &result);
120   return result;
121 }
122
123 /* Comparison operations.  */
124
125 static inline int
126 dfp_compare_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
127 {
128   IEEE_TYPE a, b;
129   decContext context;
130   decNumber arg1, arg2, res;
131   int result;
132
133   HOST_TO_IEEE (arg_a, &a);
134   HOST_TO_IEEE (arg_b, &b);
135
136   decContextDefault (&context, CONTEXT_INIT);
137   DFP_INIT_ROUNDMODE (context.round);
138
139   TO_INTERNAL (&a, &arg1);
140   TO_INTERNAL (&b, &arg2);
141
142   /* Perform the comparison.  */
143   op (&res, &arg1, &arg2, &context);
144
145   if (decNumberIsNegative (&res))
146     result = -1;
147   else if (decNumberIsZero (&res))
148     result = 0;
149   else if (decNumberIsNaN (&res))
150     result = -2;
151   else
152     result = 1;
153
154   return result;
155 }
156
157 \f
158 #if defined(L_conv_sd)
159 void
160 __host_to_ieee_32 (_Decimal32 in, decimal32 *out)
161 {
162   uint32_t t;
163
164   if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
165     {
166       memcpy (&t, &in, 4);
167       t = __dec_byte_swap (t);
168       memcpy (out, &t, 4);
169     }
170   else
171     memcpy (out, &in, 4);
172 }
173
174 void
175 __ieee_to_host_32 (decimal32 in, _Decimal32 *out)
176 {
177   uint32_t t;
178
179   if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
180     {
181       memcpy (&t, &in, 4);
182       t = __dec_byte_swap (t);
183       memcpy (out, &t, 4);
184     }
185   else
186     memcpy (out, &in, 4);
187 }
188 #endif /* L_conv_sd */
189
190 #if defined(L_conv_dd)
191 static void
192 __swap64 (char *src, char *dst)
193 {
194   uint32_t t1, t2;
195
196   if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN) 
197     {
198       memcpy (&t1, src, 4);
199       memcpy (&t2, src + 4, 4);
200       t1 = __dec_byte_swap (t1);
201       t2 = __dec_byte_swap (t2);
202       memcpy (dst, &t2, 4);
203       memcpy (dst + 4, &t1, 4);
204     }
205   else
206     memcpy (dst, src, 8);
207 }
208
209 void
210 __host_to_ieee_64 (_Decimal64 in, decimal64 *out)
211 {
212   __swap64 ((char *) &in, (char *) out);
213 }
214
215 void
216 __ieee_to_host_64 (decimal64 in, _Decimal64 *out)
217 {
218   __swap64 ((char *) &in, (char *) out);
219 }
220 #endif /* L_conv_dd */
221
222 #if defined(L_conv_td)
223 static void
224 __swap128 (char *src, char *dst)
225 {
226   uint32_t t1, t2, t3, t4;
227
228   if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
229     {
230       memcpy (&t1, src, 4);
231       memcpy (&t2, src + 4, 4);
232       memcpy (&t3, src + 8, 4);
233       memcpy (&t4, src + 12, 4);
234       t1 = __dec_byte_swap (t1);
235       t2 = __dec_byte_swap (t2);
236       t3 = __dec_byte_swap (t3);
237       t4 = __dec_byte_swap (t4);
238       memcpy (dst, &t4, 4);
239       memcpy (dst + 4, &t3, 4);
240       memcpy (dst + 8, &t2, 4);
241       memcpy (dst + 12, &t1, 4);
242     }
243   else
244     memcpy (dst, src, 16);
245 }
246
247 void
248 __host_to_ieee_128 (_Decimal128 in, decimal128 *out)
249 {
250   __swap128 ((char *) &in, (char *) out);
251 }
252
253 void
254 __ieee_to_host_128 (decimal128 in, _Decimal128 *out)
255 {
256   __swap128 ((char *) &in, (char *) out);
257 }
258 #endif /* L_conv_td */
259
260 #if defined(L_addsub_sd) || defined(L_addsub_dd) || defined(L_addsub_td)
261 DFP_C_TYPE
262 DFP_ADD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
263 {
264   return dfp_binary_op (decNumberAdd, arg_a, arg_b);
265 }
266
267 DFP_C_TYPE
268 DFP_SUB (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
269 {
270   return dfp_binary_op (decNumberSubtract, arg_a, arg_b);
271 }
272 #endif /* L_addsub */
273
274 #if defined(L_mul_sd) || defined(L_mul_dd) || defined(L_mul_td)
275 DFP_C_TYPE
276 DFP_MULTIPLY (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
277 {
278   return dfp_binary_op (decNumberMultiply, arg_a, arg_b);
279 }
280 #endif /* L_mul */
281
282 #if defined(L_div_sd) || defined(L_div_dd) || defined(L_div_td)
283 DFP_C_TYPE
284 DFP_DIVIDE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
285 {
286   return dfp_binary_op (decNumberDivide, arg_a, arg_b);
287 }
288 #endif /* L_div */
289
290 #if defined (L_eq_sd) || defined (L_eq_dd) || defined (L_eq_td)
291 CMPtype
292 DFP_EQ (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
293 {
294   int stat;
295   stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
296   /* For EQ return zero for true, nonzero for false.  */
297   return stat != 0;
298 }
299 #endif /* L_eq */
300
301 #if defined (L_ne_sd) || defined (L_ne_dd) || defined (L_ne_td)
302 CMPtype
303 DFP_NE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
304 {
305   int stat;
306   stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
307   /* For NE return zero for true, nonzero for false.  */
308   if (__builtin_expect (stat == -2, 0))  /* An operand is NaN.  */
309     return 1;
310   return stat != 0;
311 }
312 #endif /* L_ne */
313
314 #if defined (L_lt_sd) || defined (L_lt_dd) || defined (L_lt_td)
315 CMPtype
316 DFP_LT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
317 {
318   int stat;
319   stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
320   /* For LT return -1 (<0) for true, 1 for false.  */
321   return (stat == -1) ? -1 : 1;
322 }
323 #endif /* L_lt */
324
325 #if defined (L_gt_sd) || defined (L_gt_dd) || defined (L_gt_td)
326 CMPtype
327 DFP_GT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
328 {
329   int stat;
330   stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
331   /* For GT return 1 (>0) for true, -1 for false.  */
332   return (stat == 1) ? 1 : -1;
333 }
334 #endif
335
336 #if defined (L_le_sd) || defined (L_le_dd) || defined (L_le_td)
337 CMPtype
338 DFP_LE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
339 {
340   int stat;
341   stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
342   /* For LE return 0 (<= 0) for true, 1 for false.  */
343   if (__builtin_expect (stat == -2, 0))  /* An operand is NaN.  */
344     return 1;
345   return stat == 1;
346 }
347 #endif /* L_le */
348
349 #if defined (L_ge_sd) || defined (L_ge_dd) || defined (L_ge_td)
350 CMPtype
351 DFP_GE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
352 {
353   int stat;
354   stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
355   /* For GE return 1 (>=0) for true, -1 for false.  */
356   if (__builtin_expect (stat == -2, 0))  /* An operand is NaN.  */
357     return -1;
358   return (stat != -1) ? 1 : -1;
359 }
360 #endif /* L_ge */
361
362 #define BUFMAX 128
363
364 #if defined (L_sd_to_dd) || defined (L_sd_to_td) || defined (L_dd_to_sd) \
365  || defined (L_dd_to_td) || defined (L_td_to_sd) || defined (L_td_to_dd)
366 DFP_C_TYPE_TO
367 DFP_TO_DFP (DFP_C_TYPE f_from)
368 {
369   DFP_C_TYPE_TO f_to;
370   IEEE_TYPE s_from;
371   IEEE_TYPE_TO s_to;
372   decNumber d;
373   decContext context;
374
375   decContextDefault (&context, CONTEXT_INIT);
376   DFP_INIT_ROUNDMODE (context.round);
377
378   HOST_TO_IEEE (f_from, &s_from);
379   TO_INTERNAL (&s_from, &d);
380   TO_ENCODED_TO (&s_to, &d, &context);
381
382   IEEE_TO_HOST_TO (s_to, &f_to);
383   return f_to;
384 }
385 #endif
386
387 #if defined (L_sd_to_si) || defined (L_dd_to_si) || defined (L_td_to_si) \
388   || defined (L_sd_to_di) || defined (L_dd_to_di) || defined (L_td_to_di) \
389   || defined (L_sd_to_usi) || defined (L_dd_to_usi) || defined (L_td_to_usi) \
390   || defined (L_sd_to_udi) || defined (L_dd_to_udi) || defined (L_td_to_udi)
391 INT_TYPE
392 DFP_TO_INT (DFP_C_TYPE x)
393 {
394   /* decNumber's decimal* types have the same format as C's _Decimal*
395      types, but they have different calling conventions.  */
396
397   IEEE_TYPE s;
398   char buf[BUFMAX];
399   char *pos;
400   decNumber qval, n1, n2;
401   decContext context;
402
403   /* Use a large context to avoid losing precision.  */
404   decContextDefault (&context, DEC_INIT_DECIMAL128);
405   /* Need non-default rounding mode here.  */
406   context.round = DEC_ROUND_DOWN;
407
408   HOST_TO_IEEE (x, &s);
409   TO_INTERNAL (&s, &n1);
410   /* Rescale if the exponent is less than zero.  */
411   decNumberToIntegralValue (&n2, &n1, &context);
412   /* Get a value to use for the quantize call.  */
413   decNumberFromString (&qval, (char *) "1.0", &context);
414   /* Force the exponent to zero.  */
415   decNumberQuantize (&n1, &n2, &qval, &context);
416   /* Get a string, which at this point will not include an exponent.  */
417   decNumberToString (&n1, buf);
418   /* Ignore the fractional part.  */
419   pos = strchr (buf, '.');
420   if (pos)
421     *pos = 0;
422   /* Use a C library function to convert to the integral type.  */
423   return STR_TO_INT (buf, NULL, 10);
424 }
425 #endif
426
427 #if defined (L_si_to_sd) || defined (L_si_to_dd) || defined (L_si_to_td) \
428   || defined (L_di_to_sd) || defined (L_di_to_dd) || defined (L_di_to_td) \
429   || defined (L_usi_to_sd) || defined (L_usi_to_dd) || defined (L_usi_to_td) \
430   || defined (L_udi_to_sd) || defined (L_udi_to_dd) || defined (L_udi_to_td)
431 DFP_C_TYPE
432 INT_TO_DFP (INT_TYPE i)
433 {
434   DFP_C_TYPE f;
435   IEEE_TYPE s;
436   char buf[BUFMAX];
437   decContext context;
438
439   decContextDefault (&context, CONTEXT_INIT);
440   DFP_INIT_ROUNDMODE (context.round);
441
442   /* Use a C library function to get a floating point string.  */
443   sprintf (buf, INT_FMT ".0", CAST_FOR_FMT(i));
444   /* Convert from the floating point string to a decimal* type.  */
445   FROM_STRING (&s, buf, &context);
446   IEEE_TO_HOST (s, &f);
447   return f;
448 }
449 #endif
450
451 #if defined (L_sd_to_sf) || defined (L_dd_to_sf) || defined (L_td_to_sf) \
452  || defined (L_sd_to_df) || defined (L_dd_to_df) || defined (L_td_to_df) \
453  || ((defined (L_sd_to_xf) || defined (L_dd_to_xf) || defined (L_td_to_xf)) \
454      && LIBGCC2_HAS_XF_MODE)
455 BFP_TYPE
456 DFP_TO_BFP (DFP_C_TYPE f)
457 {
458   IEEE_TYPE s;
459   char buf[BUFMAX];
460
461   HOST_TO_IEEE (f, &s);
462   /* Write the value to a string.  */
463   TO_STRING (&s, buf);
464   /* Read it as the binary floating point type and return that.  */
465   return STR_TO_BFP (buf, NULL);
466 }
467 #endif
468                                                                                 
469 #if defined (L_sf_to_sd) || defined (L_sf_to_dd) || defined (L_sf_to_td) \
470  || defined (L_df_to_sd) || defined (L_df_to_dd) || defined (L_df_to_td) \
471  || ((defined (L_xf_to_sd) || defined (L_xf_to_dd) || defined (L_xf_to_td)) \
472      && LIBGCC2_HAS_XF_MODE)
473 DFP_C_TYPE
474 BFP_TO_DFP (BFP_TYPE x)
475 {
476   DFP_C_TYPE f;
477   IEEE_TYPE s;
478   char buf[BUFMAX];
479   decContext context;
480
481   decContextDefault (&context, CONTEXT_INIT);
482   DFP_INIT_ROUNDMODE (context.round);
483
484   /* Use a C library function to write the floating point value to a string.  */
485 #ifdef BFP_VIA_TYPE
486   /* FIXME: Is there a better way to output an XFmode variable in C?  */
487   sprintf (buf, BFP_FMT, (BFP_VIA_TYPE) x);
488 #else
489   sprintf (buf, BFP_FMT, x);
490 #endif
491
492   /* Convert from the floating point string to a decimal* type.  */
493   FROM_STRING (&s, buf, &context);
494   IEEE_TO_HOST (s, &f);
495   return f;
496 }
497 #endif
498
499 #if defined (L_unord_sd) || defined (L_unord_dd) || defined (L_unord_td)
500 CMPtype
501 DFP_UNORD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
502 {
503   decNumber arg1, arg2;
504   IEEE_TYPE a, b;
505
506   HOST_TO_IEEE (arg_a, &a);
507   HOST_TO_IEEE (arg_b, &b);
508   TO_INTERNAL (&a, &arg1);
509   TO_INTERNAL (&b, &arg2);
510   return (decNumberIsNaN (&arg1) || decNumberIsNaN (&arg2));
511 }
512 #endif /* L_unord_sd || L_unord_dd || L_unord_td */