1169689Skan/* This is a software decimal floating point library.
2169689Skan   Copyright (C) 2005, 2006 Free Software Foundation, Inc.
3169689Skan
4169689SkanThis file is part of GCC.
5169689Skan
6169689SkanGCC is free software; you can redistribute it and/or modify it under
7169689Skanthe terms of the GNU General Public License as published by the Free
8169689SkanSoftware Foundation; either version 2, or (at your option) any later
9169689Skanversion.
10169689Skan
11169689SkanIn addition to the permissions in the GNU General Public License, the
12169689SkanFree Software Foundation gives you unlimited permission to link the
13169689Skancompiled version of this file into combinations with other programs,
14169689Skanand to distribute those combinations without any restriction coming
15169689Skanfrom the use of this file.  (The General Public License restrictions
16169689Skando apply in other respects; for example, they cover modification of
17169689Skanthe file, and distribution when not linked into a combine
18169689Skanexecutable.)
19169689Skan
20169689SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY
21169689SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or
22169689SkanFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
23169689Skanfor more details.
24169689Skan
25169689SkanYou should have received a copy of the GNU General Public License
26169689Skanalong with GCC; see the file COPYING.  If not, write to the Free
27169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
28169689Skan02110-1301, USA.  */
29169689Skan
30169689Skan/* This implements IEEE 754R decimal floating point arithmetic, but
31169689Skan   does not provide a mechanism for setting the rounding mode, or for
32169689Skan   generating or handling exceptions.  Conversions between decimal
33169689Skan   floating point types and other types depend on C library functions.
34169689Skan
35169689Skan   Contributed by Ben Elliston  <bje@au.ibm.com>.  */
36169689Skan
37169689Skan/* The intended way to use this file is to make two copies, add `#define '
38169689Skan   to one copy, then compile both copies and add them to libgcc.a.  */
39169689Skan
40169689Skan#include <stdio.h>
41169689Skan#include <stdlib.h>
42169689Skan#include <string.h>
43169689Skan#include <limits.h>
44169689Skan
45169689Skan#include "config/dfp-bit.h"
46169689Skan
47169689Skan/* Forward declarations.  */
48169689Skan#if WIDTH == 32 || WIDTH_TO == 32
49169689Skanvoid __host_to_ieee_32 (_Decimal32 in, decimal32 *out);
50169689Skanvoid __ieee_to_host_32 (decimal32 in, _Decimal32 *out);
51169689Skan#endif
52169689Skan#if WIDTH == 64 || WIDTH_TO == 64
53169689Skanvoid __host_to_ieee_64 (_Decimal64 in, decimal64 *out);
54169689Skanvoid __ieee_to_host_64 (decimal64 in, _Decimal64 *out);
55169689Skan#endif
56169689Skan#if WIDTH == 128 || WIDTH_TO == 128
57169689Skanvoid __host_to_ieee_128 (_Decimal128 in, decimal128 *out);
58169689Skanvoid __ieee_to_host_128 (decimal128 in, _Decimal128 *out);
59169689Skan#endif
60169689Skan
61169689Skan/* A pointer to a unary decNumber operation.  */
62169689Skantypedef decNumber* (*dfp_unary_func)
63169689Skan     (decNumber *, decNumber *, decContext *);
64169689Skan
65169689Skan/* A pointer to a binary decNumber operation.  */
66169689Skantypedef decNumber* (*dfp_binary_func)
67169689Skan     (decNumber *, decNumber *, decNumber *, decContext *);
68169689Skan
69169689Skanextern unsigned long __dec_byte_swap (unsigned long);
70169689Skan
71169689Skan/* Unary operations.  */
72169689Skan
73169689Skanstatic inline DFP_C_TYPE
74169689Skandfp_unary_op (dfp_unary_func op, DFP_C_TYPE arg)
75169689Skan{
76169689Skan  DFP_C_TYPE result;
77169689Skan  decContext context;
78169689Skan  decNumber arg1, res;
79169689Skan  IEEE_TYPE a, encoded_result;
80169689Skan
81169689Skan  HOST_TO_IEEE (arg, &a);
82169689Skan
83169689Skan  decContextDefault (&context, CONTEXT_INIT);
84169689Skan  context.round = CONTEXT_ROUND;
85169689Skan
86169689Skan  TO_INTERNAL (&a, &arg1);
87169689Skan
88169689Skan  /* Perform the operation.  */
89169689Skan  op (&res, &arg1, &context);
90169689Skan
91169689Skan  if (CONTEXT_TRAPS && CONTEXT_ERRORS (context))
92169689Skan    DFP_RAISE (0);
93169689Skan
94169689Skan  TO_ENCODED (&encoded_result, &res, &context);
95169689Skan  IEEE_TO_HOST (encoded_result, &result);
96169689Skan  return result;
97169689Skan}
98169689Skan
99169689Skan/* Binary operations.  */
100169689Skan
101169689Skanstatic inline DFP_C_TYPE
102169689Skandfp_binary_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
103169689Skan{
104169689Skan  DFP_C_TYPE result;
105169689Skan  decContext context;
106169689Skan  decNumber arg1, arg2, res;
107169689Skan  IEEE_TYPE a, b, encoded_result;
108169689Skan
109169689Skan  HOST_TO_IEEE (arg_a, &a);
110169689Skan  HOST_TO_IEEE (arg_b, &b);
111169689Skan
112169689Skan  decContextDefault (&context, CONTEXT_INIT);
113169689Skan  context.round = CONTEXT_ROUND;
114169689Skan
115169689Skan  TO_INTERNAL (&a, &arg1);
116169689Skan  TO_INTERNAL (&b, &arg2);
117169689Skan
118169689Skan  /* Perform the operation.  */
119169689Skan  op (&res, &arg1, &arg2, &context);
120169689Skan
121169689Skan  if (CONTEXT_TRAPS && CONTEXT_ERRORS (context))
122169689Skan    DFP_RAISE (0);
123169689Skan
124169689Skan  TO_ENCODED (&encoded_result, &res, &context);
125169689Skan  IEEE_TO_HOST (encoded_result, &result);
126169689Skan  return result;
127169689Skan}
128169689Skan
129169689Skan/* Comparison operations.  */
130169689Skan
131169689Skanstatic inline int
132169689Skandfp_compare_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
133169689Skan{
134169689Skan  IEEE_TYPE a, b;
135169689Skan  decContext context;
136169689Skan  decNumber arg1, arg2, res;
137169689Skan  int result;
138169689Skan
139169689Skan  HOST_TO_IEEE (arg_a, &a);
140169689Skan  HOST_TO_IEEE (arg_b, &b);
141169689Skan
142169689Skan  decContextDefault (&context, CONTEXT_INIT);
143169689Skan  context.round = CONTEXT_ROUND;
144169689Skan
145169689Skan  TO_INTERNAL (&a, &arg1);
146169689Skan  TO_INTERNAL (&b, &arg2);
147169689Skan
148169689Skan  /* Perform the comparison.  */
149169689Skan  op (&res, &arg1, &arg2, &context);
150169689Skan
151169689Skan  if (CONTEXT_TRAPS && CONTEXT_ERRORS (context))
152169689Skan    DFP_RAISE (0);
153169689Skan
154169689Skan  if (decNumberIsNegative (&res))
155169689Skan    result = -1;
156169689Skan  else if (decNumberIsZero (&res))
157169689Skan    result = 0;
158169689Skan  else
159169689Skan    result = 1;
160169689Skan
161169689Skan  return result;
162169689Skan}
163169689Skan
164169689Skan
165169689Skan#if defined(L_conv_sd)
166169689Skanvoid
167169689Skan__host_to_ieee_32 (_Decimal32 in, decimal32 *out)
168169689Skan{
169169689Skan  uint32_t t;
170169689Skan
171169689Skan  if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
172169689Skan    {
173169689Skan      memcpy (&t, &in, 4);
174169689Skan      t = __dec_byte_swap (t);
175169689Skan      memcpy (out, &t, 4);
176169689Skan    }
177169689Skan  else
178169689Skan    memcpy (out, &in, 4);
179169689Skan}
180169689Skan
181169689Skanvoid
182169689Skan__ieee_to_host_32 (decimal32 in, _Decimal32 *out)
183169689Skan{
184169689Skan  uint32_t t;
185169689Skan
186169689Skan  if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
187169689Skan    {
188169689Skan      memcpy (&t, &in, 4);
189169689Skan      t = __dec_byte_swap (t);
190169689Skan      memcpy (out, &t, 4);
191169689Skan    }
192169689Skan  else
193169689Skan    memcpy (out, &in, 4);
194169689Skan}
195169689Skan#endif /* L_conv_sd */
196169689Skan
197169689Skan#if defined(L_conv_dd)
198169689Skanstatic void
199169689Skan__swap64 (char *src, char *dst)
200169689Skan{
201169689Skan  uint32_t t1, t2;
202169689Skan
203169689Skan  if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
204169689Skan    {
205169689Skan      memcpy (&t1, src, 4);
206169689Skan      memcpy (&t2, src + 4, 4);
207169689Skan      t1 = __dec_byte_swap (t1);
208169689Skan      t2 = __dec_byte_swap (t2);
209169689Skan      memcpy (dst, &t2, 4);
210169689Skan      memcpy (dst + 4, &t1, 4);
211169689Skan    }
212169689Skan  else
213169689Skan    memcpy (dst, src, 8);
214169689Skan}
215169689Skan
216169689Skanvoid
217169689Skan__host_to_ieee_64 (_Decimal64 in, decimal64 *out)
218169689Skan{
219169689Skan  __swap64 ((char *) &in, (char *) out);
220169689Skan}
221169689Skan
222169689Skanvoid
223169689Skan__ieee_to_host_64 (decimal64 in, _Decimal64 *out)
224169689Skan{
225169689Skan  __swap64 ((char *) &in, (char *) out);
226169689Skan}
227169689Skan#endif /* L_conv_dd */
228169689Skan
229169689Skan#if defined(L_conv_td)
230169689Skanstatic void
231169689Skan__swap128 (char *src, char *dst)
232169689Skan{
233169689Skan  uint32_t t1, t2, t3, t4;
234169689Skan
235169689Skan  if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
236169689Skan    {
237169689Skan      memcpy (&t1, src, 4);
238169689Skan      memcpy (&t2, src + 4, 4);
239169689Skan      memcpy (&t3, src + 8, 4);
240169689Skan      memcpy (&t4, src + 12, 4);
241169689Skan      t1 = __dec_byte_swap (t1);
242169689Skan      t2 = __dec_byte_swap (t2);
243169689Skan      t3 = __dec_byte_swap (t3);
244169689Skan      t4 = __dec_byte_swap (t4);
245169689Skan      memcpy (dst, &t4, 4);
246169689Skan      memcpy (dst + 4, &t3, 4);
247169689Skan      memcpy (dst + 8, &t2, 4);
248169689Skan      memcpy (dst + 12, &t1, 4);
249169689Skan    }
250169689Skan  else
251169689Skan    memcpy (dst, src, 16);
252169689Skan}
253169689Skan
254169689Skanvoid
255169689Skan__host_to_ieee_128 (_Decimal128 in, decimal128 *out)
256169689Skan{
257169689Skan  __swap128 ((char *) &in, (char *) out);
258169689Skan}
259169689Skan
260169689Skanvoid
261169689Skan__ieee_to_host_128 (decimal128 in, _Decimal128 *out)
262169689Skan{
263169689Skan  __swap128 ((char *) &in, (char *) out);
264169689Skan}
265169689Skan#endif /* L_conv_td */
266169689Skan
267169689Skan#if defined(L_addsub_sd) || defined(L_addsub_dd) || defined(L_addsub_td)
268169689SkanDFP_C_TYPE
269169689SkanDFP_ADD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
270169689Skan{
271169689Skan  return dfp_binary_op (decNumberAdd, arg_a, arg_b);
272169689Skan}
273169689Skan
274169689SkanDFP_C_TYPE
275169689SkanDFP_SUB (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
276169689Skan{
277169689Skan  return dfp_binary_op (decNumberSubtract, arg_a, arg_b);
278169689Skan}
279169689Skan#endif /* L_addsub */
280169689Skan
281169689Skan#if defined(L_mul_sd) || defined(L_mul_dd) || defined(L_mul_td)
282169689SkanDFP_C_TYPE
283169689SkanDFP_MULTIPLY (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
284169689Skan{
285169689Skan  return dfp_binary_op (decNumberMultiply, arg_a, arg_b);
286169689Skan}
287169689Skan#endif /* L_mul */
288169689Skan
289169689Skan#if defined(L_div_sd) || defined(L_div_dd) || defined(L_div_td)
290169689SkanDFP_C_TYPE
291169689SkanDFP_DIVIDE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
292169689Skan{
293169689Skan  return dfp_binary_op (decNumberDivide, arg_a, arg_b);
294169689Skan}
295169689Skan#endif /* L_div */
296169689Skan
297169689Skan#if defined (L_eq_sd) || defined (L_eq_dd) || defined (L_eq_td)
298169689SkanCMPtype
299169689SkanDFP_EQ (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
300169689Skan{
301169689Skan  int stat;
302169689Skan  stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
303169689Skan  /* For EQ return zero for true, nonzero for false.  */
304169689Skan  return stat != 0;
305169689Skan}
306169689Skan#endif /* L_eq */
307169689Skan
308169689Skan#if defined (L_ne_sd) || defined (L_ne_dd) || defined (L_ne_td)
309169689SkanCMPtype
310169689SkanDFP_NE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
311169689Skan{
312169689Skan  int stat;
313169689Skan  stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
314169689Skan  /* For NE return nonzero for true, zero for false.  */
315169689Skan  return stat != 0;
316169689Skan}
317169689Skan#endif /* L_ne */
318169689Skan
319169689Skan#if defined (L_lt_sd) || defined (L_lt_dd) || defined (L_lt_td)
320169689SkanCMPtype
321169689SkanDFP_LT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
322169689Skan{
323169689Skan  int stat;
324169689Skan  stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
325169689Skan  /* For LT return -1 (<0) for true, 1 for false.  */
326169689Skan  return (stat == -1) ? -1 : 1;
327169689Skan}
328169689Skan#endif /* L_lt */
329169689Skan
330169689Skan#if defined (L_gt_sd) || defined (L_gt_dd) || defined (L_gt_td)
331169689SkanCMPtype
332169689SkanDFP_GT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
333169689Skan{
334169689Skan  int stat;
335169689Skan  stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
336169689Skan  /* For GT return 1 (>0) for true, -1 for false.  */
337169689Skan  return (stat == 1) ? 1 : -1;
338169689Skan}
339169689Skan#endif
340169689Skan
341169689Skan#if defined (L_le_sd) || defined (L_le_dd) || defined (L_le_td)
342169689SkanCMPtype
343169689SkanDFP_LE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
344169689Skan{
345169689Skan  int stat;
346169689Skan  stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
347169689Skan  /* For LE return 0 (<= 0) for true, 1 for false.  */
348169689Skan  return stat == 1;
349169689Skan}
350169689Skan#endif /* L_le */
351169689Skan
352169689Skan#if defined (L_ge_sd) || defined (L_ge_dd) || defined (L_ge_td)
353169689SkanCMPtype
354169689SkanDFP_GE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
355169689Skan{
356169689Skan  int stat;
357169689Skan  stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
358169689Skan  /* For GE return 1 (>=0) for true, -1 for false.  */
359169689Skan  return (stat != -1) ? 1 : -1;
360169689Skan}
361169689Skan#endif /* L_ge */
362169689Skan
363169689Skan#define BUFMAX 128
364169689Skan
365169689Skan#if defined (L_sd_to_dd) || defined (L_sd_to_td) || defined (L_dd_to_sd) \
366169689Skan || defined (L_dd_to_td) || defined (L_td_to_sd) || defined (L_td_to_dd)
367169689SkanDFP_C_TYPE_TO
368169689SkanDFP_TO_DFP (DFP_C_TYPE f_from)
369169689Skan{
370169689Skan  DFP_C_TYPE_TO f_to;
371169689Skan  IEEE_TYPE s_from;
372169689Skan  IEEE_TYPE_TO s_to;
373169689Skan  decNumber d;
374169689Skan  decContext context;
375169689Skan
376169689Skan  decContextDefault (&context, CONTEXT_INIT);
377169689Skan  context.round = CONTEXT_ROUND;
378169689Skan
379169689Skan  HOST_TO_IEEE (f_from, &s_from);
380169689Skan  TO_INTERNAL (&s_from, &d);
381169689Skan  TO_ENCODED_TO (&s_to, &d, &context);
382169689Skan  if (CONTEXT_TRAPS && (context.status & DEC_Inexact) != 0)
383169689Skan    DFP_RAISE (DEC_Inexact);
384169689Skan
385169689Skan  IEEE_TO_HOST_TO (s_to, &f_to);
386169689Skan  return f_to;
387169689Skan}
388169689Skan#endif
389169689Skan
390169689Skan#if defined (L_sd_to_si) || defined (L_dd_to_si) || defined (L_td_to_si) \
391169689Skan  || defined (L_sd_to_di) || defined (L_dd_to_di) || defined (L_td_to_di) \
392169689Skan  || defined (L_sd_to_usi) || defined (L_dd_to_usi) || defined (L_td_to_usi) \
393169689Skan  || defined (L_sd_to_udi) || defined (L_dd_to_udi) || defined (L_td_to_udi)
394169689SkanINT_TYPE
395169689SkanDFP_TO_INT (DFP_C_TYPE x)
396169689Skan{
397169689Skan  /* decNumber's decimal* types have the same format as C's _Decimal*
398169689Skan     types, but they have different calling conventions.  */
399169689Skan
400169689Skan  IEEE_TYPE s;
401169689Skan  char buf[BUFMAX];
402169689Skan  char *pos;
403169689Skan  decNumber qval, n1, n2;
404169689Skan  decContext context;
405169689Skan
406169689Skan  decContextDefault (&context, CONTEXT_INIT);
407169689Skan  /* Need non-default rounding mode here.  */
408169689Skan  context.round = DEC_ROUND_DOWN;
409169689Skan
410169689Skan  HOST_TO_IEEE (x, &s);
411169689Skan  TO_INTERNAL (&s, &n1);
412169689Skan  /* Rescale if the exponent is less than zero.  */
413169689Skan  decNumberToIntegralValue (&n2, &n1, &context);
414169689Skan  /* Get a value to use for the quantize call.  */
415169689Skan  decNumberFromString (&qval, (char *) "1.0", &context);
416169689Skan  /* Force the exponent to zero.  */
417169689Skan  decNumberQuantize (&n1, &n2, &qval, &context);
418169689Skan  /* This is based on text in N1107 section 5.1; it might turn out to be
419169689Skan     undefined behavior instead.  */
420169689Skan  if (context.status & DEC_Invalid_operation)
421169689Skan    {
422169689Skan#if defined (L_sd_to_si) || defined (L_dd_to_si) || defined (L_td_to_si)
423169689Skan      if (decNumberIsNegative(&n2))
424169689Skan        return INT_MIN;
425169689Skan      else
426169689Skan        return INT_MAX;
427169689Skan#elif defined (L_sd_to_di) || defined (L_dd_to_di) || defined (L_td_to_di)
428169689Skan      if (decNumberIsNegative(&n2))
429169689Skan        /* Find a defined constant that will work here.  */
430169689Skan        return (-9223372036854775807LL - 1LL);
431169689Skan      else
432169689Skan        /* Find a defined constant that will work here.  */
433169689Skan        return 9223372036854775807LL;
434169689Skan#elif defined (L_sd_to_usi) || defined (L_dd_to_usi) || defined (L_td_to_usi)
435169689Skan      return UINT_MAX;
436169689Skan#elif defined (L_sd_to_udi) || defined (L_dd_to_udi) || defined (L_td_to_udi)
437169689Skan        /* Find a defined constant that will work here.  */
438169689Skan      return 18446744073709551615ULL;
439169689Skan#endif
440169689Skan    }
441169689Skan  /* Get a string, which at this point will not include an exponent.  */
442169689Skan  decNumberToString (&n1, buf);
443169689Skan  /* Ignore the fractional part.  */
444169689Skan  pos = strchr (buf, '.');
445169689Skan  if (pos)
446169689Skan    *pos = 0;
447169689Skan  /* Use a C library function to convert to the integral type.  */
448169689Skan  return STR_TO_INT (buf, NULL, 10);
449169689Skan}
450169689Skan#endif
451169689Skan
452169689Skan#if defined (L_si_to_sd) || defined (L_si_to_dd) || defined (L_si_to_td) \
453169689Skan  || defined (L_di_to_sd) || defined (L_di_to_dd) || defined (L_di_to_td) \
454169689Skan  || defined (L_usi_to_sd) || defined (L_usi_to_dd) || defined (L_usi_to_td) \
455169689Skan  || defined (L_udi_to_sd) || defined (L_udi_to_dd) || defined (L_udi_to_td)
456169689SkanDFP_C_TYPE
457169689SkanINT_TO_DFP (INT_TYPE i)
458169689Skan{
459169689Skan  DFP_C_TYPE f;
460169689Skan  IEEE_TYPE s;
461169689Skan  char buf[BUFMAX];
462169689Skan  decContext context;
463169689Skan
464169689Skan  decContextDefault (&context, CONTEXT_INIT);
465169689Skan  context.round = CONTEXT_ROUND;
466169689Skan
467169689Skan  /* Use a C library function to get a floating point string.  */
468169689Skan  sprintf (buf, INT_FMT ".0", CAST_FOR_FMT(i));
469169689Skan  /* Convert from the floating point string to a decimal* type.  */
470169689Skan  FROM_STRING (&s, buf, &context);
471169689Skan  IEEE_TO_HOST (s, &f);
472169689Skan  if (CONTEXT_TRAPS && (context.status & DEC_Inexact) != 0)
473169689Skan    DFP_RAISE (DEC_Inexact);
474169689Skan  return f;
475169689Skan}
476169689Skan#endif
477169689Skan
478169689Skan#if defined (L_sd_to_sf) || defined (L_dd_to_sf) || defined (L_td_to_sf) \
479169689Skan || defined (L_sd_to_df) || defined (L_dd_to_df) || defined (L_td_to_df) \
480169689Skan || ((defined (L_sd_to_xf) || defined (L_dd_to_xf) || defined (L_td_to_xf)) \
481169689Skan     && LIBGCC2_HAS_XF_MODE)
482169689SkanBFP_TYPE
483169689SkanDFP_TO_BFP (DFP_C_TYPE f)
484169689Skan{
485169689Skan  IEEE_TYPE s;
486169689Skan  char buf[BUFMAX];
487169689Skan
488169689Skan  HOST_TO_IEEE (f, &s);
489169689Skan  /* Write the value to a string.  */
490169689Skan  TO_STRING (&s, buf);
491169689Skan  /* Read it as the binary floating point type and return that.  */
492169689Skan  return STR_TO_BFP (buf, NULL);
493169689Skan}
494169689Skan#endif
495169689Skan
496169689Skan#if defined (L_sf_to_sd) || defined (L_sf_to_dd) || defined (L_sf_to_td) \
497169689Skan || defined (L_df_to_sd) || defined (L_df_to_dd) || defined (L_df_to_td) \
498169689Skan || ((defined (L_xf_to_sd) || defined (L_xf_to_dd) || defined (L_xf_to_td)) \
499169689Skan     && LIBGCC2_HAS_XF_MODE)
500169689SkanDFP_C_TYPE
501169689SkanBFP_TO_DFP (BFP_TYPE x)
502169689Skan{
503169689Skan  DFP_C_TYPE f;
504169689Skan  IEEE_TYPE s;
505169689Skan  char buf[BUFMAX];
506169689Skan  decContext context;
507169689Skan
508169689Skan  decContextDefault (&context, CONTEXT_INIT);
509169689Skan  context.round = CONTEXT_ROUND;
510169689Skan
511169689Skan  /* Use a C library function to write the floating point value to a string.  */
512169689Skan#ifdef BFP_VIA_TYPE
513169689Skan  /* FIXME: Is there a better way to output an XFmode variable in C?  */
514169689Skan  sprintf (buf, BFP_FMT, (BFP_VIA_TYPE) x);
515169689Skan#else
516169689Skan  sprintf (buf, BFP_FMT, x);
517169689Skan#endif
518169689Skan
519169689Skan  /* Convert from the floating point string to a decimal* type.  */
520169689Skan  FROM_STRING (&s, buf, &context);
521169689Skan  IEEE_TO_HOST (s, &f);
522169689Skan  if (CONTEXT_TRAPS && (context.status & DEC_Inexact) != 0)
523169689Skan    DFP_RAISE (DEC_Inexact);
524169689Skan  return f;
525169689Skan}
526169689Skan#endif
527169689Skan
528169689Skan#if defined (L_unord_sd) || defined (L_unord_dd) || defined (L_unord_td)
529169689SkanCMPtype
530169689SkanDFP_UNORD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
531169689Skan{
532169689Skan  decNumber arg1, arg2;
533169689Skan  IEEE_TYPE a, b;
534169689Skan
535169689Skan  HOST_TO_IEEE (arg_a, &a);
536169689Skan  HOST_TO_IEEE (arg_b, &b);
537169689Skan  TO_INTERNAL (&a, &arg1);
538169689Skan  TO_INTERNAL (&b, &arg2);
539169689Skan  return (decNumberIsNaN (&arg1) || decNumberIsNaN (&arg2));
540169689Skan}
541169689Skan#endif /* L_unord_sd || L_unord_dd || L_unord_td */
542