OSDN Git Service

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