xref: /dragonfly/contrib/gcc-4.7/libgcc/dfp-bit.c (revision e4b17023)
1 /* This is a software decimal floating point library.
2    Copyright (C) 2005, 2006, 2007, 2008, 2009, 2011
3    Free Software Foundation, Inc.
4 
5 This file is part of GCC.
6 
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
11 
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16 
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
20 
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24 <http://www.gnu.org/licenses/>.  */
25 
26 /* This implements IEEE 754 decimal floating point arithmetic, but
27    does not provide a mechanism for setting the rounding mode, or for
28    generating or handling exceptions.  Conversions between decimal
29    floating point types and other types depend on C library functions.
30 
31    Contributed by Ben Elliston  <bje@au.ibm.com>.  */
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 /* FIXME: compile with -std=gnu99 to get these from stdlib.h */
36 extern float strtof (const char *, char **);
37 extern long double strtold (const char *, char **);
38 #include <string.h>
39 #include <limits.h>
40 
41 #include "dfp-bit.h"
42 
43 /* Forward declarations.  */
44 #if WIDTH == 32 || WIDTH_TO == 32
45 void __host_to_ieee_32 (_Decimal32 in, decimal32 *out);
46 void __ieee_to_host_32 (decimal32 in, _Decimal32 *out);
47 #endif
48 #if WIDTH == 64 || WIDTH_TO == 64
49 void __host_to_ieee_64 (_Decimal64 in, decimal64 *out);
50 void __ieee_to_host_64 (decimal64 in, _Decimal64 *out);
51 #endif
52 #if WIDTH == 128 || WIDTH_TO == 128
53 void __host_to_ieee_128 (_Decimal128 in, decimal128 *out);
54 void __ieee_to_host_128 (decimal128 in, _Decimal128 *out);
55 #endif
56 
57 /* A pointer to a binary decFloat operation.  */
58 typedef decFloat* (*dfp_binary_func)
59      (decFloat *, const decFloat *, const decFloat *, decContext *);
60 
61 /* Binary operations.  */
62 
63 /* Use a decFloat (decDouble or decQuad) function to perform a DFP
64    binary operation.  */
65 static inline decFloat
dfp_binary_op(dfp_binary_func op,decFloat arg_a,decFloat arg_b)66 dfp_binary_op (dfp_binary_func op, decFloat arg_a, decFloat arg_b)
67 {
68   decFloat result;
69   decContext context;
70 
71   decContextDefault (&context, CONTEXT_INIT);
72   DFP_INIT_ROUNDMODE (context.round);
73 
74   /* Perform the operation.  */
75   op (&result, &arg_a, &arg_b, &context);
76 
77   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
78     {
79       /* decNumber exception flags we care about here.  */
80       int ieee_flags;
81       int dec_flags = DEC_IEEE_854_Division_by_zero | DEC_IEEE_854_Inexact
82 		      | DEC_IEEE_854_Invalid_operation | DEC_IEEE_854_Overflow
83 		      | DEC_IEEE_854_Underflow;
84       dec_flags &= context.status;
85       ieee_flags = DFP_IEEE_FLAGS (dec_flags);
86       if (ieee_flags != 0)
87         DFP_HANDLE_EXCEPTIONS (ieee_flags);
88     }
89 
90   return result;
91 }
92 
93 #if WIDTH == 32
94 /* The decNumber package doesn't provide arithmetic for decSingle (32 bits);
95    convert to decDouble, use the operation for that, and convert back.  */
96 static inline _Decimal32
d32_binary_op(dfp_binary_func op,_Decimal32 arg_a,_Decimal32 arg_b)97 d32_binary_op (dfp_binary_func op, _Decimal32 arg_a, _Decimal32 arg_b)
98 {
99   union { _Decimal32 c; decSingle f; } a32, b32, res32;
100   decDouble a, b, res;
101   decContext context;
102 
103   /* Widen the operands and perform the operation.  */
104   a32.c = arg_a;
105   b32.c = arg_b;
106   decSingleToWider (&a32.f, &a);
107   decSingleToWider (&b32.f, &b);
108   res = dfp_binary_op (op, a, b);
109 
110   /* Narrow the result, which might result in an underflow or overflow.  */
111   decContextDefault (&context, CONTEXT_INIT);
112   DFP_INIT_ROUNDMODE (context.round);
113   decSingleFromWider (&res32.f, &res, &context);
114   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
115     {
116       /* decNumber exception flags we care about here.  */
117       int ieee_flags;
118       int dec_flags = DEC_IEEE_854_Inexact | DEC_IEEE_854_Overflow
119 		      | DEC_IEEE_854_Underflow;
120       dec_flags &= context.status;
121       ieee_flags = DFP_IEEE_FLAGS (dec_flags);
122       if (ieee_flags != 0)
123         DFP_HANDLE_EXCEPTIONS (ieee_flags);
124     }
125 
126   return res32.c;
127 }
128 #else
129 /* decFloat operations are supported for decDouble (64 bits) and
130    decQuad (128 bits).  The bit patterns for the types are the same.  */
131 static inline DFP_C_TYPE
dnn_binary_op(dfp_binary_func op,DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)132 dnn_binary_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
133 {
134   union { DFP_C_TYPE c; decFloat f; } a, b, result;
135 
136   a.c = arg_a;
137   b.c = arg_b;
138   result.f = dfp_binary_op (op, a.f, b.f);
139   return result.c;
140 }
141 #endif
142 
143 /* Comparison operations.  */
144 
145 /* Use a decFloat (decDouble or decQuad) function to perform a DFP
146    comparison.  */
147 static inline CMPtype
dfp_compare_op(dfp_binary_func op,decFloat arg_a,decFloat arg_b)148 dfp_compare_op (dfp_binary_func op, decFloat arg_a, decFloat arg_b)
149 {
150   decContext context;
151   decFloat res;
152   int result;
153 
154   decContextDefault (&context, CONTEXT_INIT);
155   DFP_INIT_ROUNDMODE (context.round);
156 
157   /* Perform the comparison.  */
158   op (&res, &arg_a, &arg_b, &context);
159 
160   if (DEC_FLOAT_IS_SIGNED (&res))
161     result = -1;
162   else if (DEC_FLOAT_IS_ZERO (&res))
163     result = 0;
164   else if (DEC_FLOAT_IS_NAN (&res))
165     result = -2;
166   else
167     result = 1;
168 
169   return (CMPtype) result;
170 }
171 
172 #if WIDTH == 32
173 /* The decNumber package doesn't provide comparisons for decSingle (32 bits);
174    convert to decDouble, use the operation for that, and convert back.  */
175 static inline CMPtype
d32_compare_op(dfp_binary_func op,_Decimal32 arg_a,_Decimal32 arg_b)176 d32_compare_op (dfp_binary_func op, _Decimal32 arg_a, _Decimal32 arg_b)
177 {
178   union { _Decimal32 c; decSingle f; } a32, b32;
179   decDouble a, b;
180 
181   a32.c = arg_a;
182   b32.c = arg_b;
183   decSingleToWider (&a32.f, &a);
184   decSingleToWider (&b32.f, &b);
185   return dfp_compare_op (op, a, b);
186 }
187 #else
188 /* decFloat comparisons are supported for decDouble (64 bits) and
189    decQuad (128 bits).  The bit patterns for the types are the same.  */
190 static inline CMPtype
dnn_compare_op(dfp_binary_func op,DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)191 dnn_compare_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
192 {
193   union { DFP_C_TYPE c; decFloat f; } a, b;
194 
195   a.c = arg_a;
196   b.c = arg_b;
197   return dfp_compare_op (op, a.f, b.f);
198 }
199 #endif
200 
201 #if defined(L_conv_sd)
202 void
__host_to_ieee_32(_Decimal32 in,decimal32 * out)203 __host_to_ieee_32 (_Decimal32 in, decimal32 *out)
204 {
205   memcpy (out, &in, 4);
206 }
207 
208 void
__ieee_to_host_32(decimal32 in,_Decimal32 * out)209 __ieee_to_host_32 (decimal32 in, _Decimal32 *out)
210 {
211   memcpy (out, &in, 4);
212 }
213 #endif /* L_conv_sd */
214 
215 #if defined(L_conv_dd)
216 void
__host_to_ieee_64(_Decimal64 in,decimal64 * out)217 __host_to_ieee_64 (_Decimal64 in, decimal64 *out)
218 {
219   memcpy (out, &in, 8);
220 }
221 
222 void
__ieee_to_host_64(decimal64 in,_Decimal64 * out)223 __ieee_to_host_64 (decimal64 in, _Decimal64 *out)
224 {
225   memcpy (out, &in, 8);
226 }
227 #endif /* L_conv_dd */
228 
229 #if defined(L_conv_td)
230 void
__host_to_ieee_128(_Decimal128 in,decimal128 * out)231 __host_to_ieee_128 (_Decimal128 in, decimal128 *out)
232 {
233   memcpy (out, &in, 16);
234 }
235 
236 void
__ieee_to_host_128(decimal128 in,_Decimal128 * out)237 __ieee_to_host_128 (decimal128 in, _Decimal128 *out)
238 {
239   memcpy (out, &in, 16);
240 }
241 #endif /* L_conv_td */
242 
243 #if defined(L_addsub_sd) || defined(L_addsub_dd) || defined(L_addsub_td)
244 DFP_C_TYPE
DFP_ADD(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)245 DFP_ADD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
246 {
247   return DFP_BINARY_OP (DEC_FLOAT_ADD, arg_a, arg_b);
248 }
249 
250 DFP_C_TYPE
DFP_SUB(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)251 DFP_SUB (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
252 {
253   return DFP_BINARY_OP (DEC_FLOAT_SUBTRACT, arg_a, arg_b);
254 }
255 #endif /* L_addsub */
256 
257 #if defined(L_mul_sd) || defined(L_mul_dd) || defined(L_mul_td)
258 DFP_C_TYPE
DFP_MULTIPLY(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)259 DFP_MULTIPLY (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
260 {
261   return DFP_BINARY_OP (DEC_FLOAT_MULTIPLY, arg_a, arg_b);
262 }
263 #endif /* L_mul */
264 
265 #if defined(L_div_sd) || defined(L_div_dd) || defined(L_div_td)
266 DFP_C_TYPE
DFP_DIVIDE(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)267 DFP_DIVIDE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
268 {
269   return DFP_BINARY_OP (DEC_FLOAT_DIVIDE, arg_a, arg_b);
270 }
271 #endif /* L_div */
272 
273 #if defined (L_eq_sd) || defined (L_eq_dd) || defined (L_eq_td)
274 CMPtype
DFP_EQ(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)275 DFP_EQ (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
276 {
277   CMPtype stat;
278   stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
279   /* For EQ return zero for true, nonzero for false.  */
280   return stat != 0;
281 }
282 #endif /* L_eq */
283 
284 #if defined (L_ne_sd) || defined (L_ne_dd) || defined (L_ne_td)
285 CMPtype
DFP_NE(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)286 DFP_NE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
287 {
288   int stat;
289   stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
290   /* For NE return zero for true, nonzero for false.  */
291   if (__builtin_expect (stat == -2, 0))  /* An operand is NaN.  */
292     return 1;
293   return stat != 0;
294 }
295 #endif /* L_ne */
296 
297 #if defined (L_lt_sd) || defined (L_lt_dd) || defined (L_lt_td)
298 CMPtype
DFP_LT(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)299 DFP_LT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
300 {
301   int stat;
302   stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
303   /* For LT return -1 (<0) for true, 1 for false.  */
304   return (stat == -1) ? -1 : 1;
305 }
306 #endif /* L_lt */
307 
308 #if defined (L_gt_sd) || defined (L_gt_dd) || defined (L_gt_td)
309 CMPtype
DFP_GT(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)310 DFP_GT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
311 {
312   int stat;
313   stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
314   /* For GT return 1 (>0) for true, -1 for false.  */
315   return (stat == 1) ? 1 : -1;
316 }
317 #endif
318 
319 #if defined (L_le_sd) || defined (L_le_dd) || defined (L_le_td)
320 CMPtype
DFP_LE(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)321 DFP_LE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
322 {
323   int stat;
324   stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
325   /* For LE return 0 (<= 0) for true, 1 for false.  */
326   if (__builtin_expect (stat == -2, 0))  /* An operand is NaN.  */
327     return 1;
328   return stat == 1;
329 }
330 #endif /* L_le */
331 
332 #if defined (L_ge_sd) || defined (L_ge_dd) || defined (L_ge_td)
333 CMPtype
DFP_GE(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)334 DFP_GE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
335 {
336   int stat;
337   stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
338   /* For GE return 1 (>=0) for true, -1 for false.  */
339   if (__builtin_expect (stat == -2, 0))  /* An operand is NaN.  */
340     return -1;
341   return (stat != -1) ? 1 : -1;
342 }
343 #endif /* L_ge */
344 
345 #define BUFMAX 128
346 
347 /* Check for floating point exceptions that are relevant for conversions
348    between decimal float values and handle them.  */
349 static inline void
dfp_conversion_exceptions(const int status)350 dfp_conversion_exceptions (const int status)
351 {
352   /* decNumber exception flags we care about here.  */
353   int ieee_flags;
354   int dec_flags = DEC_IEEE_854_Inexact | DEC_IEEE_854_Invalid_operation
355 		  | DEC_IEEE_854_Overflow;
356   dec_flags &= status;
357   ieee_flags = DFP_IEEE_FLAGS (dec_flags);
358   if (ieee_flags != 0)
359     DFP_HANDLE_EXCEPTIONS (ieee_flags);
360 }
361 
362 #if defined (L_sd_to_dd)
363 /* Use decNumber to convert directly from _Decimal32 to _Decimal64.  */
364 _Decimal64
DFP_TO_DFP(_Decimal32 f_from)365 DFP_TO_DFP (_Decimal32 f_from)
366 {
367   union { _Decimal32 c; decSingle f; } from;
368   union { _Decimal64 c; decDouble f; } to;
369 
370   from.c = f_from;
371   to.f = *decSingleToWider (&from.f, &to.f);
372   return to.c;
373 }
374 #endif
375 
376 #if defined (L_sd_to_td)
377 /* Use decNumber to convert directly from _Decimal32 to _Decimal128.  */
378 _Decimal128
DFP_TO_DFP(_Decimal32 f_from)379 DFP_TO_DFP (_Decimal32 f_from)
380 {
381   union { _Decimal32 c; decSingle f; } from;
382   union { _Decimal128 c; decQuad f; } to;
383   decDouble temp;
384 
385   from.c = f_from;
386   temp = *decSingleToWider (&from.f, &temp);
387   to.f = *decDoubleToWider (&temp, &to.f);
388   return to.c;
389 }
390 #endif
391 
392 #if defined (L_dd_to_td)
393 /* Use decNumber to convert directly from _Decimal64 to _Decimal128.  */
394 _Decimal128
DFP_TO_DFP(_Decimal64 f_from)395 DFP_TO_DFP (_Decimal64 f_from)
396 {
397   union { _Decimal64 c; decDouble f; } from;
398   union { _Decimal128 c; decQuad f; } to;
399 
400   from.c = f_from;
401   to.f = *decDoubleToWider (&from.f, &to.f);
402   return to.c;
403 }
404 #endif
405 
406 #if defined (L_dd_to_sd)
407 /* Use decNumber to convert directly from _Decimal64 to _Decimal32.  */
408 _Decimal32
DFP_TO_DFP(_Decimal64 f_from)409 DFP_TO_DFP (_Decimal64 f_from)
410 {
411   union { _Decimal32 c; decSingle f; } to;
412   union { _Decimal64 c; decDouble f; } from;
413   decContext context;
414 
415   decContextDefault (&context, CONTEXT_INIT);
416   DFP_INIT_ROUNDMODE (context.round);
417   from.c = f_from;
418   to.f = *decSingleFromWider (&to.f, &from.f, &context);
419   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
420     dfp_conversion_exceptions (context.status);
421   return to.c;
422 }
423 #endif
424 
425 #if defined (L_td_to_sd)
426 /* Use decNumber to convert directly from _Decimal128 to _Decimal32.  */
427 _Decimal32
DFP_TO_DFP(_Decimal128 f_from)428 DFP_TO_DFP (_Decimal128 f_from)
429 {
430   union { _Decimal32 c; decSingle f; } to;
431   union { _Decimal128 c; decQuad f; } from;
432   decDouble temp;
433   decContext context;
434 
435   decContextDefault (&context, CONTEXT_INIT);
436   DFP_INIT_ROUNDMODE (context.round);
437   from.c = f_from;
438   temp = *decDoubleFromWider (&temp, &from.f, &context);
439   to.f = *decSingleFromWider (&to.f, &temp, &context);
440   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
441     dfp_conversion_exceptions (context.status);
442   return to.c;
443 }
444 #endif
445 
446 #if defined (L_td_to_dd)
447 /* Use decNumber to convert directly from _Decimal128 to _Decimal64.  */
448 _Decimal64
DFP_TO_DFP(_Decimal128 f_from)449 DFP_TO_DFP (_Decimal128 f_from)
450 {
451   union { _Decimal64 c; decDouble f; } to;
452   union { _Decimal128 c; decQuad f; } from;
453   decContext context;
454 
455   decContextDefault (&context, CONTEXT_INIT);
456   DFP_INIT_ROUNDMODE (context.round);
457   from.c = f_from;
458   to.f = *decDoubleFromWider (&to.f, &from.f, &context);
459   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
460     dfp_conversion_exceptions (context.status);
461   return to.c;
462 }
463 #endif
464 
465 #if defined (L_dd_to_si) || defined (L_td_to_si) \
466   || defined (L_dd_to_usi) || defined (L_td_to_usi)
467 /* Use decNumber to convert directly from decimal float to integer types.  */
468 INT_TYPE
DFP_TO_INT(DFP_C_TYPE x)469 DFP_TO_INT (DFP_C_TYPE x)
470 {
471   union { DFP_C_TYPE c; decFloat f; } u;
472   decContext context;
473   INT_TYPE i;
474 
475   decContextDefault (&context, DEC_INIT_DECIMAL128);
476   context.round = DEC_ROUND_DOWN;
477   u.c = x;
478   i = DEC_FLOAT_TO_INT (&u.f, &context, context.round);
479   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
480     dfp_conversion_exceptions (context.status);
481   return i;
482 }
483 #endif
484 
485 #if defined (L_sd_to_si) || (L_sd_to_usi)
486 /* Use decNumber to convert directly from decimal float to integer types.  */
487 INT_TYPE
DFP_TO_INT(_Decimal32 x)488 DFP_TO_INT (_Decimal32 x)
489 {
490   union { _Decimal32 c; decSingle f; } u32;
491   decDouble f64;
492   decContext context;
493   INT_TYPE i;
494 
495   decContextDefault (&context, DEC_INIT_DECIMAL128);
496   context.round = DEC_ROUND_DOWN;
497   u32.c = x;
498   f64 = *decSingleToWider (&u32.f, &f64);
499   i = DEC_FLOAT_TO_INT (&f64, &context, context.round);
500   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
501     dfp_conversion_exceptions (context.status);
502   return i;
503 }
504 #endif
505 
506 #if defined (L_sd_to_di) || defined (L_dd_to_di) || defined (L_td_to_di) \
507   || defined (L_sd_to_udi) || defined (L_dd_to_udi) || defined (L_td_to_udi)
508 /* decNumber doesn't provide support for conversions to 64-bit integer
509    types, so do it the hard way.  */
510 INT_TYPE
DFP_TO_INT(DFP_C_TYPE x)511 DFP_TO_INT (DFP_C_TYPE x)
512 {
513   /* decNumber's decimal* types have the same format as C's _Decimal*
514      types, but they have different calling conventions.  */
515 
516   /* TODO: Decimal float to integer conversions should raise FE_INVALID
517      if the result value does not fit into the result type.  */
518 
519   IEEE_TYPE s;
520   char buf[BUFMAX];
521   char *pos;
522   decNumber qval, n1, n2;
523   decContext context;
524 
525   /* Use a large context to avoid losing precision.  */
526   decContextDefault (&context, DEC_INIT_DECIMAL128);
527   /* Need non-default rounding mode here.  */
528   context.round = DEC_ROUND_DOWN;
529 
530   HOST_TO_IEEE (x, &s);
531   TO_INTERNAL (&s, &n1);
532   /* Rescale if the exponent is less than zero.  */
533   decNumberToIntegralValue (&n2, &n1, &context);
534   /* Get a value to use for the quantize call.  */
535   decNumberFromString (&qval, "1.", &context);
536   /* Force the exponent to zero.  */
537   decNumberQuantize (&n1, &n2, &qval, &context);
538   /* Get a string, which at this point will not include an exponent.  */
539   decNumberToString (&n1, buf);
540   /* Ignore the fractional part.  */
541   pos = strchr (buf, '.');
542   if (pos)
543     *pos = 0;
544   /* Use a C library function to convert to the integral type.  */
545   return STR_TO_INT (buf, NULL, 10);
546 }
547 #endif
548 
549 #if defined (L_si_to_dd) || defined (L_si_to_td) \
550   || defined (L_usi_to_dd) || defined (L_usi_to_td)
551 /* Use decNumber to convert directly from integer to decimal float types.  */
552 DFP_C_TYPE
INT_TO_DFP(INT_TYPE i)553 INT_TO_DFP (INT_TYPE i)
554 {
555   union { DFP_C_TYPE c; decFloat f; } u;
556 
557   u.f = *DEC_FLOAT_FROM_INT (&u.f, i);
558   return u.c;
559 }
560 #endif
561 
562 #if defined (L_si_to_sd) || defined (L_usi_to_sd)
563 _Decimal32
564 /* Use decNumber to convert directly from integer to decimal float types.  */
INT_TO_DFP(INT_TYPE i)565 INT_TO_DFP (INT_TYPE i)
566 {
567   union { _Decimal32 c; decSingle f; } u32;
568   decDouble f64;
569   decContext context;
570 
571   decContextDefault (&context, DEC_INIT_DECIMAL128);
572   f64 = *DEC_FLOAT_FROM_INT (&f64, i);
573   u32.f = *decSingleFromWider (&u32.f, &f64, &context);
574   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
575     dfp_conversion_exceptions (context.status);
576   return u32.c;
577 }
578 #endif
579 
580 #if defined (L_di_to_sd) || defined (L_di_to_dd) || defined (L_di_to_td) \
581   || defined (L_udi_to_sd) || defined (L_udi_to_dd) || defined (L_udi_to_td)
582 /* decNumber doesn't provide support for conversions from 64-bit integer
583    types, so do it the hard way.  */
584 DFP_C_TYPE
INT_TO_DFP(INT_TYPE i)585 INT_TO_DFP (INT_TYPE i)
586 {
587   DFP_C_TYPE f;
588   IEEE_TYPE s;
589   char buf[BUFMAX];
590   decContext context;
591 
592   decContextDefault (&context, CONTEXT_INIT);
593   DFP_INIT_ROUNDMODE (context.round);
594 
595   /* Use a C library function to get a floating point string.  */
596   sprintf (buf, INT_FMT ".", CAST_FOR_FMT(i));
597   /* Convert from the floating point string to a decimal* type.  */
598   FROM_STRING (&s, buf, &context);
599   IEEE_TO_HOST (s, &f);
600 
601   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
602     dfp_conversion_exceptions (context.status);
603 
604   return f;
605 }
606 #endif
607 
608 #if defined (L_sd_to_sf) || defined (L_dd_to_sf) || defined (L_td_to_sf) \
609  || defined (L_sd_to_df) || defined (L_dd_to_df) || defined (L_td_to_df) \
610  || ((defined (L_sd_to_xf) || defined (L_dd_to_xf) || defined (L_td_to_xf)) \
611      && LONG_DOUBLE_HAS_XF_MODE) \
612  || ((defined (L_sd_to_tf) || defined (L_dd_to_tf) || defined (L_td_to_tf)) \
613      && LONG_DOUBLE_HAS_TF_MODE)
614 BFP_TYPE
DFP_TO_BFP(DFP_C_TYPE f)615 DFP_TO_BFP (DFP_C_TYPE f)
616 {
617   IEEE_TYPE s;
618   char buf[BUFMAX];
619 
620   HOST_TO_IEEE (f, &s);
621   /* Write the value to a string.  */
622   TO_STRING (&s, buf);
623   /* Read it as the binary floating point type and return that.  */
624   return STR_TO_BFP (buf, NULL);
625 }
626 #endif
627 
628 #if defined (L_sf_to_sd) || defined (L_sf_to_dd) || defined (L_sf_to_td) \
629  || defined (L_df_to_sd) || defined (L_df_to_dd) || defined (L_df_to_td) \
630  || ((defined (L_xf_to_sd) || defined (L_xf_to_dd) || defined (L_xf_to_td)) \
631      && LONG_DOUBLE_HAS_XF_MODE) \
632  || ((defined (L_tf_to_sd) || defined (L_tf_to_dd) || defined (L_tf_to_td)) \
633      && LONG_DOUBLE_HAS_TF_MODE)
634 DFP_C_TYPE
BFP_TO_DFP(BFP_TYPE x)635 BFP_TO_DFP (BFP_TYPE x)
636 {
637   DFP_C_TYPE f;
638   IEEE_TYPE s;
639   char buf[BUFMAX];
640   decContext context;
641 
642   decContextDefault (&context, CONTEXT_INIT);
643   DFP_INIT_ROUNDMODE (context.round);
644 
645   /* Use a C library function to write the floating point value to a string.  */
646   sprintf (buf, BFP_FMT, (BFP_VIA_TYPE) x);
647 
648   /* Convert from the floating point string to a decimal* type.  */
649   FROM_STRING (&s, buf, &context);
650   IEEE_TO_HOST (s, &f);
651 
652   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
653     {
654       /* decNumber exception flags we care about here.  */
655       int ieee_flags;
656       int dec_flags = DEC_IEEE_854_Inexact | DEC_IEEE_854_Invalid_operation
657 		      | DEC_IEEE_854_Overflow | DEC_IEEE_854_Underflow;
658       dec_flags &= context.status;
659       ieee_flags = DFP_IEEE_FLAGS (dec_flags);
660       if (ieee_flags != 0)
661         DFP_HANDLE_EXCEPTIONS (ieee_flags);
662     }
663 
664   return f;
665 }
666 #endif
667 
668 #if defined (L_unord_sd) || defined (L_unord_dd) || defined (L_unord_td)
669 CMPtype
DFP_UNORD(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)670 DFP_UNORD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
671 {
672   decNumber arg1, arg2;
673   IEEE_TYPE a, b;
674 
675   HOST_TO_IEEE (arg_a, &a);
676   HOST_TO_IEEE (arg_b, &b);
677   TO_INTERNAL (&a, &arg1);
678   TO_INTERNAL (&b, &arg2);
679   return (decNumberIsNaN (&arg1) || decNumberIsNaN (&arg2));
680 }
681 #endif /* L_unord_sd || L_unord_dd || L_unord_td */
682