xref: /netbsd-src/external/gpl3/gcc.old/dist/libgcc/dfp-bit.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
11debfc3dSmrg /* This is a software decimal floating point library.
2*8feb0f0bSmrg    Copyright (C) 2005-2020 Free Software Foundation, Inc.
31debfc3dSmrg 
41debfc3dSmrg This file is part of GCC.
51debfc3dSmrg 
61debfc3dSmrg GCC is free software; you can redistribute it and/or modify it under
71debfc3dSmrg the terms of the GNU General Public License as published by the Free
81debfc3dSmrg Software Foundation; either version 3, or (at your option) any later
91debfc3dSmrg version.
101debfc3dSmrg 
111debfc3dSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
121debfc3dSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
131debfc3dSmrg FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
141debfc3dSmrg for more details.
151debfc3dSmrg 
161debfc3dSmrg Under Section 7 of GPL version 3, you are granted additional
171debfc3dSmrg permissions described in the GCC Runtime Library Exception, version
181debfc3dSmrg 3.1, as published by the Free Software Foundation.
191debfc3dSmrg 
201debfc3dSmrg You should have received a copy of the GNU General Public License and
211debfc3dSmrg a copy of the GCC Runtime Library Exception along with this program;
221debfc3dSmrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
231debfc3dSmrg <http://www.gnu.org/licenses/>.  */
241debfc3dSmrg 
251debfc3dSmrg /* This implements IEEE 754 decimal floating point arithmetic, but
261debfc3dSmrg    does not provide a mechanism for setting the rounding mode, or for
271debfc3dSmrg    generating or handling exceptions.  Conversions between decimal
281debfc3dSmrg    floating point types and other types depend on C library functions.
291debfc3dSmrg 
301debfc3dSmrg    Contributed by Ben Elliston  <bje@au.ibm.com>.  */
311debfc3dSmrg 
321debfc3dSmrg #include <stdio.h>
331debfc3dSmrg #include <stdlib.h>
341debfc3dSmrg /* FIXME: compile with -std=gnu99 to get these from stdlib.h */
351debfc3dSmrg extern float strtof (const char *, char **);
361debfc3dSmrg extern long double strtold (const char *, char **);
371debfc3dSmrg #include <string.h>
381debfc3dSmrg #include <limits.h>
391debfc3dSmrg 
401debfc3dSmrg #include "dfp-bit.h"
411debfc3dSmrg 
421debfc3dSmrg /* Forward declarations.  */
431debfc3dSmrg #if WIDTH == 32 || WIDTH_TO == 32
441debfc3dSmrg void __host_to_ieee_32 (_Decimal32 in, decimal32 *out);
451debfc3dSmrg void __ieee_to_host_32 (decimal32 in, _Decimal32 *out);
461debfc3dSmrg #endif
471debfc3dSmrg #if WIDTH == 64 || WIDTH_TO == 64
481debfc3dSmrg void __host_to_ieee_64 (_Decimal64 in, decimal64 *out);
491debfc3dSmrg void __ieee_to_host_64 (decimal64 in, _Decimal64 *out);
501debfc3dSmrg #endif
511debfc3dSmrg #if WIDTH == 128 || WIDTH_TO == 128
521debfc3dSmrg void __host_to_ieee_128 (_Decimal128 in, decimal128 *out);
531debfc3dSmrg void __ieee_to_host_128 (decimal128 in, _Decimal128 *out);
541debfc3dSmrg #endif
551debfc3dSmrg 
561debfc3dSmrg /* A pointer to a binary decFloat operation.  */
571debfc3dSmrg typedef decFloat* (*dfp_binary_func)
581debfc3dSmrg      (decFloat *, const decFloat *, const decFloat *, decContext *);
591debfc3dSmrg 
601debfc3dSmrg /* Binary operations.  */
611debfc3dSmrg 
621debfc3dSmrg /* Use a decFloat (decDouble or decQuad) function to perform a DFP
631debfc3dSmrg    binary operation.  */
641debfc3dSmrg static inline decFloat
dfp_binary_op(dfp_binary_func op,decFloat arg_a,decFloat arg_b)651debfc3dSmrg dfp_binary_op (dfp_binary_func op, decFloat arg_a, decFloat arg_b)
661debfc3dSmrg {
671debfc3dSmrg   decFloat result;
681debfc3dSmrg   decContext context;
691debfc3dSmrg 
701debfc3dSmrg   decContextDefault (&context, CONTEXT_INIT);
711debfc3dSmrg   DFP_INIT_ROUNDMODE (context.round);
721debfc3dSmrg 
731debfc3dSmrg   /* Perform the operation.  */
741debfc3dSmrg   op (&result, &arg_a, &arg_b, &context);
751debfc3dSmrg 
761debfc3dSmrg   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
771debfc3dSmrg     {
781debfc3dSmrg       /* decNumber exception flags we care about here.  */
791debfc3dSmrg       int ieee_flags;
801debfc3dSmrg       int dec_flags = DEC_IEEE_854_Division_by_zero | DEC_IEEE_854_Inexact
811debfc3dSmrg 		      | DEC_IEEE_854_Invalid_operation | DEC_IEEE_854_Overflow
821debfc3dSmrg 		      | DEC_IEEE_854_Underflow;
831debfc3dSmrg       dec_flags &= context.status;
841debfc3dSmrg       ieee_flags = DFP_IEEE_FLAGS (dec_flags);
851debfc3dSmrg       if (ieee_flags != 0)
861debfc3dSmrg         DFP_HANDLE_EXCEPTIONS (ieee_flags);
871debfc3dSmrg     }
881debfc3dSmrg 
891debfc3dSmrg   return result;
901debfc3dSmrg }
911debfc3dSmrg 
921debfc3dSmrg #if WIDTH == 32
931debfc3dSmrg /* The decNumber package doesn't provide arithmetic for decSingle (32 bits);
941debfc3dSmrg    convert to decDouble, use the operation for that, and convert back.  */
951debfc3dSmrg static inline _Decimal32
d32_binary_op(dfp_binary_func op,_Decimal32 arg_a,_Decimal32 arg_b)961debfc3dSmrg d32_binary_op (dfp_binary_func op, _Decimal32 arg_a, _Decimal32 arg_b)
971debfc3dSmrg {
981debfc3dSmrg   union { _Decimal32 c; decSingle f; } a32, b32, res32;
991debfc3dSmrg   decDouble a, b, res;
1001debfc3dSmrg   decContext context;
1011debfc3dSmrg 
1021debfc3dSmrg   /* Widen the operands and perform the operation.  */
1031debfc3dSmrg   a32.c = arg_a;
1041debfc3dSmrg   b32.c = arg_b;
1051debfc3dSmrg   decSingleToWider (&a32.f, &a);
1061debfc3dSmrg   decSingleToWider (&b32.f, &b);
1071debfc3dSmrg   res = dfp_binary_op (op, a, b);
1081debfc3dSmrg 
1091debfc3dSmrg   /* Narrow the result, which might result in an underflow or overflow.  */
1101debfc3dSmrg   decContextDefault (&context, CONTEXT_INIT);
1111debfc3dSmrg   DFP_INIT_ROUNDMODE (context.round);
1121debfc3dSmrg   decSingleFromWider (&res32.f, &res, &context);
1131debfc3dSmrg   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
1141debfc3dSmrg     {
1151debfc3dSmrg       /* decNumber exception flags we care about here.  */
1161debfc3dSmrg       int ieee_flags;
1171debfc3dSmrg       int dec_flags = DEC_IEEE_854_Inexact | DEC_IEEE_854_Overflow
1181debfc3dSmrg 		      | DEC_IEEE_854_Underflow;
1191debfc3dSmrg       dec_flags &= context.status;
1201debfc3dSmrg       ieee_flags = DFP_IEEE_FLAGS (dec_flags);
1211debfc3dSmrg       if (ieee_flags != 0)
1221debfc3dSmrg         DFP_HANDLE_EXCEPTIONS (ieee_flags);
1231debfc3dSmrg     }
1241debfc3dSmrg 
1251debfc3dSmrg   return res32.c;
1261debfc3dSmrg }
1271debfc3dSmrg #else
1281debfc3dSmrg /* decFloat operations are supported for decDouble (64 bits) and
1291debfc3dSmrg    decQuad (128 bits).  The bit patterns for the types are the same.  */
1301debfc3dSmrg static inline DFP_C_TYPE
dnn_binary_op(dfp_binary_func op,DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)1311debfc3dSmrg dnn_binary_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
1321debfc3dSmrg {
1331debfc3dSmrg   union { DFP_C_TYPE c; decFloat f; } a, b, result;
1341debfc3dSmrg 
1351debfc3dSmrg   a.c = arg_a;
1361debfc3dSmrg   b.c = arg_b;
1371debfc3dSmrg   result.f = dfp_binary_op (op, a.f, b.f);
1381debfc3dSmrg   return result.c;
1391debfc3dSmrg }
1401debfc3dSmrg #endif
1411debfc3dSmrg 
1421debfc3dSmrg /* Comparison operations.  */
1431debfc3dSmrg 
1441debfc3dSmrg /* Use a decFloat (decDouble or decQuad) function to perform a DFP
1451debfc3dSmrg    comparison.  */
1461debfc3dSmrg static inline CMPtype
dfp_compare_op(dfp_binary_func op,decFloat arg_a,decFloat arg_b)1471debfc3dSmrg dfp_compare_op (dfp_binary_func op, decFloat arg_a, decFloat arg_b)
1481debfc3dSmrg {
1491debfc3dSmrg   decContext context;
1501debfc3dSmrg   decFloat res;
1511debfc3dSmrg   int result;
1521debfc3dSmrg 
1531debfc3dSmrg   decContextDefault (&context, CONTEXT_INIT);
1541debfc3dSmrg   DFP_INIT_ROUNDMODE (context.round);
1551debfc3dSmrg 
1561debfc3dSmrg   /* Perform the comparison.  */
1571debfc3dSmrg   op (&res, &arg_a, &arg_b, &context);
1581debfc3dSmrg 
1591debfc3dSmrg   if (DEC_FLOAT_IS_SIGNED (&res))
1601debfc3dSmrg     result = -1;
1611debfc3dSmrg   else if (DEC_FLOAT_IS_ZERO (&res))
1621debfc3dSmrg     result = 0;
1631debfc3dSmrg   else if (DEC_FLOAT_IS_NAN (&res))
1641debfc3dSmrg     result = -2;
1651debfc3dSmrg   else
1661debfc3dSmrg     result = 1;
1671debfc3dSmrg 
1681debfc3dSmrg   return (CMPtype) result;
1691debfc3dSmrg }
1701debfc3dSmrg 
1711debfc3dSmrg #if WIDTH == 32
1721debfc3dSmrg /* The decNumber package doesn't provide comparisons for decSingle (32 bits);
1731debfc3dSmrg    convert to decDouble, use the operation for that, and convert back.  */
1741debfc3dSmrg static inline CMPtype
d32_compare_op(dfp_binary_func op,_Decimal32 arg_a,_Decimal32 arg_b)1751debfc3dSmrg d32_compare_op (dfp_binary_func op, _Decimal32 arg_a, _Decimal32 arg_b)
1761debfc3dSmrg {
1771debfc3dSmrg   union { _Decimal32 c; decSingle f; } a32, b32;
1781debfc3dSmrg   decDouble a, b;
1791debfc3dSmrg 
1801debfc3dSmrg   a32.c = arg_a;
1811debfc3dSmrg   b32.c = arg_b;
1821debfc3dSmrg   decSingleToWider (&a32.f, &a);
1831debfc3dSmrg   decSingleToWider (&b32.f, &b);
1841debfc3dSmrg   return dfp_compare_op (op, a, b);
1851debfc3dSmrg }
1861debfc3dSmrg #else
1871debfc3dSmrg /* decFloat comparisons are supported for decDouble (64 bits) and
1881debfc3dSmrg    decQuad (128 bits).  The bit patterns for the types are the same.  */
1891debfc3dSmrg static inline CMPtype
dnn_compare_op(dfp_binary_func op,DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)1901debfc3dSmrg dnn_compare_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
1911debfc3dSmrg {
1921debfc3dSmrg   union { DFP_C_TYPE c; decFloat f; } a, b;
1931debfc3dSmrg 
1941debfc3dSmrg   a.c = arg_a;
1951debfc3dSmrg   b.c = arg_b;
1961debfc3dSmrg   return dfp_compare_op (op, a.f, b.f);
1971debfc3dSmrg }
1981debfc3dSmrg #endif
1991debfc3dSmrg 
2001debfc3dSmrg #if defined(L_conv_sd)
2011debfc3dSmrg void
__host_to_ieee_32(_Decimal32 in,decimal32 * out)2021debfc3dSmrg __host_to_ieee_32 (_Decimal32 in, decimal32 *out)
2031debfc3dSmrg {
2041debfc3dSmrg   memcpy (out, &in, 4);
2051debfc3dSmrg }
2061debfc3dSmrg 
2071debfc3dSmrg void
__ieee_to_host_32(decimal32 in,_Decimal32 * out)2081debfc3dSmrg __ieee_to_host_32 (decimal32 in, _Decimal32 *out)
2091debfc3dSmrg {
2101debfc3dSmrg   memcpy (out, &in, 4);
2111debfc3dSmrg }
2121debfc3dSmrg #endif /* L_conv_sd */
2131debfc3dSmrg 
2141debfc3dSmrg #if defined(L_conv_dd)
2151debfc3dSmrg void
__host_to_ieee_64(_Decimal64 in,decimal64 * out)2161debfc3dSmrg __host_to_ieee_64 (_Decimal64 in, decimal64 *out)
2171debfc3dSmrg {
2181debfc3dSmrg   memcpy (out, &in, 8);
2191debfc3dSmrg }
2201debfc3dSmrg 
2211debfc3dSmrg void
__ieee_to_host_64(decimal64 in,_Decimal64 * out)2221debfc3dSmrg __ieee_to_host_64 (decimal64 in, _Decimal64 *out)
2231debfc3dSmrg {
2241debfc3dSmrg   memcpy (out, &in, 8);
2251debfc3dSmrg }
2261debfc3dSmrg #endif /* L_conv_dd */
2271debfc3dSmrg 
2281debfc3dSmrg #if defined(L_conv_td)
2291debfc3dSmrg void
__host_to_ieee_128(_Decimal128 in,decimal128 * out)2301debfc3dSmrg __host_to_ieee_128 (_Decimal128 in, decimal128 *out)
2311debfc3dSmrg {
2321debfc3dSmrg   memcpy (out, &in, 16);
2331debfc3dSmrg }
2341debfc3dSmrg 
2351debfc3dSmrg void
__ieee_to_host_128(decimal128 in,_Decimal128 * out)2361debfc3dSmrg __ieee_to_host_128 (decimal128 in, _Decimal128 *out)
2371debfc3dSmrg {
2381debfc3dSmrg   memcpy (out, &in, 16);
2391debfc3dSmrg }
2401debfc3dSmrg #endif /* L_conv_td */
2411debfc3dSmrg 
2421debfc3dSmrg #if defined(L_addsub_sd) || defined(L_addsub_dd) || defined(L_addsub_td)
2431debfc3dSmrg DFP_C_TYPE
DFP_ADD(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)2441debfc3dSmrg DFP_ADD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
2451debfc3dSmrg {
2461debfc3dSmrg   return DFP_BINARY_OP (DEC_FLOAT_ADD, arg_a, arg_b);
2471debfc3dSmrg }
2481debfc3dSmrg 
2491debfc3dSmrg DFP_C_TYPE
DFP_SUB(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)2501debfc3dSmrg DFP_SUB (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
2511debfc3dSmrg {
2521debfc3dSmrg   return DFP_BINARY_OP (DEC_FLOAT_SUBTRACT, arg_a, arg_b);
2531debfc3dSmrg }
2541debfc3dSmrg #endif /* L_addsub */
2551debfc3dSmrg 
2561debfc3dSmrg #if defined(L_mul_sd) || defined(L_mul_dd) || defined(L_mul_td)
2571debfc3dSmrg DFP_C_TYPE
DFP_MULTIPLY(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)2581debfc3dSmrg DFP_MULTIPLY (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
2591debfc3dSmrg {
2601debfc3dSmrg   return DFP_BINARY_OP (DEC_FLOAT_MULTIPLY, arg_a, arg_b);
2611debfc3dSmrg }
2621debfc3dSmrg #endif /* L_mul */
2631debfc3dSmrg 
2641debfc3dSmrg #if defined(L_div_sd) || defined(L_div_dd) || defined(L_div_td)
2651debfc3dSmrg DFP_C_TYPE
DFP_DIVIDE(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)2661debfc3dSmrg DFP_DIVIDE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
2671debfc3dSmrg {
2681debfc3dSmrg   return DFP_BINARY_OP (DEC_FLOAT_DIVIDE, arg_a, arg_b);
2691debfc3dSmrg }
2701debfc3dSmrg #endif /* L_div */
2711debfc3dSmrg 
2721debfc3dSmrg #if defined (L_eq_sd) || defined (L_eq_dd) || defined (L_eq_td)
2731debfc3dSmrg CMPtype
DFP_EQ(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)2741debfc3dSmrg DFP_EQ (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
2751debfc3dSmrg {
2761debfc3dSmrg   CMPtype stat;
2771debfc3dSmrg   stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
2781debfc3dSmrg   /* For EQ return zero for true, nonzero for false.  */
2791debfc3dSmrg   return stat != 0;
2801debfc3dSmrg }
2811debfc3dSmrg #endif /* L_eq */
2821debfc3dSmrg 
2831debfc3dSmrg #if defined (L_ne_sd) || defined (L_ne_dd) || defined (L_ne_td)
2841debfc3dSmrg CMPtype
DFP_NE(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)2851debfc3dSmrg DFP_NE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
2861debfc3dSmrg {
2871debfc3dSmrg   int stat;
2881debfc3dSmrg   stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
2891debfc3dSmrg   /* For NE return zero for true, nonzero for false.  */
2901debfc3dSmrg   if (__builtin_expect (stat == -2, 0))  /* An operand is NaN.  */
2911debfc3dSmrg     return 1;
2921debfc3dSmrg   return stat != 0;
2931debfc3dSmrg }
2941debfc3dSmrg #endif /* L_ne */
2951debfc3dSmrg 
2961debfc3dSmrg #if defined (L_lt_sd) || defined (L_lt_dd) || defined (L_lt_td)
2971debfc3dSmrg CMPtype
DFP_LT(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)2981debfc3dSmrg DFP_LT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
2991debfc3dSmrg {
3001debfc3dSmrg   int stat;
3011debfc3dSmrg   stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
3021debfc3dSmrg   /* For LT return -1 (<0) for true, 1 for false.  */
3031debfc3dSmrg   return (stat == -1) ? -1 : 1;
3041debfc3dSmrg }
3051debfc3dSmrg #endif /* L_lt */
3061debfc3dSmrg 
3071debfc3dSmrg #if defined (L_gt_sd) || defined (L_gt_dd) || defined (L_gt_td)
3081debfc3dSmrg CMPtype
DFP_GT(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)3091debfc3dSmrg DFP_GT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
3101debfc3dSmrg {
3111debfc3dSmrg   int stat;
3121debfc3dSmrg   stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
3131debfc3dSmrg   /* For GT return 1 (>0) for true, -1 for false.  */
3141debfc3dSmrg   return (stat == 1) ? 1 : -1;
3151debfc3dSmrg }
3161debfc3dSmrg #endif
3171debfc3dSmrg 
3181debfc3dSmrg #if defined (L_le_sd) || defined (L_le_dd) || defined (L_le_td)
3191debfc3dSmrg CMPtype
DFP_LE(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)3201debfc3dSmrg DFP_LE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
3211debfc3dSmrg {
3221debfc3dSmrg   int stat;
3231debfc3dSmrg   stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
3241debfc3dSmrg   /* For LE return 0 (<= 0) for true, 1 for false.  */
3251debfc3dSmrg   if (__builtin_expect (stat == -2, 0))  /* An operand is NaN.  */
3261debfc3dSmrg     return 1;
3271debfc3dSmrg   return stat == 1;
3281debfc3dSmrg }
3291debfc3dSmrg #endif /* L_le */
3301debfc3dSmrg 
3311debfc3dSmrg #if defined (L_ge_sd) || defined (L_ge_dd) || defined (L_ge_td)
3321debfc3dSmrg CMPtype
DFP_GE(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)3331debfc3dSmrg DFP_GE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
3341debfc3dSmrg {
3351debfc3dSmrg   int stat;
3361debfc3dSmrg   stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
3371debfc3dSmrg   /* For GE return 1 (>=0) for true, -1 for false.  */
3381debfc3dSmrg   if (__builtin_expect (stat == -2, 0))  /* An operand is NaN.  */
3391debfc3dSmrg     return -1;
3401debfc3dSmrg   return (stat != -1) ? 1 : -1;
3411debfc3dSmrg }
3421debfc3dSmrg #endif /* L_ge */
3431debfc3dSmrg 
3441debfc3dSmrg #define BUFMAX 128
3451debfc3dSmrg 
3461debfc3dSmrg /* Check for floating point exceptions that are relevant for conversions
3471debfc3dSmrg    between decimal float values and handle them.  */
3481debfc3dSmrg static inline void
dfp_conversion_exceptions(const int status)3491debfc3dSmrg dfp_conversion_exceptions (const int status)
3501debfc3dSmrg {
3511debfc3dSmrg   /* decNumber exception flags we care about here.  */
3521debfc3dSmrg   int ieee_flags;
3531debfc3dSmrg   int dec_flags = DEC_IEEE_854_Inexact | DEC_IEEE_854_Invalid_operation
3541debfc3dSmrg 		  | DEC_IEEE_854_Overflow;
3551debfc3dSmrg   dec_flags &= status;
3561debfc3dSmrg   ieee_flags = DFP_IEEE_FLAGS (dec_flags);
3571debfc3dSmrg   if (ieee_flags != 0)
3581debfc3dSmrg     DFP_HANDLE_EXCEPTIONS (ieee_flags);
3591debfc3dSmrg }
3601debfc3dSmrg 
3611debfc3dSmrg #if defined (L_sd_to_dd)
3621debfc3dSmrg /* Use decNumber to convert directly from _Decimal32 to _Decimal64.  */
3631debfc3dSmrg _Decimal64
DFP_TO_DFP(_Decimal32 f_from)3641debfc3dSmrg DFP_TO_DFP (_Decimal32 f_from)
3651debfc3dSmrg {
3661debfc3dSmrg   union { _Decimal32 c; decSingle f; } from;
3671debfc3dSmrg   union { _Decimal64 c; decDouble f; } to;
3681debfc3dSmrg 
3691debfc3dSmrg   from.c = f_from;
3701debfc3dSmrg   to.f = *decSingleToWider (&from.f, &to.f);
3711debfc3dSmrg   return to.c;
3721debfc3dSmrg }
3731debfc3dSmrg #endif
3741debfc3dSmrg 
3751debfc3dSmrg #if defined (L_sd_to_td)
3761debfc3dSmrg /* Use decNumber to convert directly from _Decimal32 to _Decimal128.  */
3771debfc3dSmrg _Decimal128
DFP_TO_DFP(_Decimal32 f_from)3781debfc3dSmrg DFP_TO_DFP (_Decimal32 f_from)
3791debfc3dSmrg {
3801debfc3dSmrg   union { _Decimal32 c; decSingle f; } from;
3811debfc3dSmrg   union { _Decimal128 c; decQuad f; } to;
3821debfc3dSmrg   decDouble temp;
3831debfc3dSmrg 
3841debfc3dSmrg   from.c = f_from;
3851debfc3dSmrg   temp = *decSingleToWider (&from.f, &temp);
3861debfc3dSmrg   to.f = *decDoubleToWider (&temp, &to.f);
3871debfc3dSmrg   return to.c;
3881debfc3dSmrg }
3891debfc3dSmrg #endif
3901debfc3dSmrg 
3911debfc3dSmrg #if defined (L_dd_to_td)
3921debfc3dSmrg /* Use decNumber to convert directly from _Decimal64 to _Decimal128.  */
3931debfc3dSmrg _Decimal128
DFP_TO_DFP(_Decimal64 f_from)3941debfc3dSmrg DFP_TO_DFP (_Decimal64 f_from)
3951debfc3dSmrg {
3961debfc3dSmrg   union { _Decimal64 c; decDouble f; } from;
3971debfc3dSmrg   union { _Decimal128 c; decQuad f; } to;
3981debfc3dSmrg 
3991debfc3dSmrg   from.c = f_from;
4001debfc3dSmrg   to.f = *decDoubleToWider (&from.f, &to.f);
4011debfc3dSmrg   return to.c;
4021debfc3dSmrg }
4031debfc3dSmrg #endif
4041debfc3dSmrg 
4051debfc3dSmrg #if defined (L_dd_to_sd)
4061debfc3dSmrg /* Use decNumber to convert directly from _Decimal64 to _Decimal32.  */
4071debfc3dSmrg _Decimal32
DFP_TO_DFP(_Decimal64 f_from)4081debfc3dSmrg DFP_TO_DFP (_Decimal64 f_from)
4091debfc3dSmrg {
4101debfc3dSmrg   union { _Decimal32 c; decSingle f; } to;
4111debfc3dSmrg   union { _Decimal64 c; decDouble f; } from;
4121debfc3dSmrg   decContext context;
4131debfc3dSmrg 
4141debfc3dSmrg   decContextDefault (&context, CONTEXT_INIT);
4151debfc3dSmrg   DFP_INIT_ROUNDMODE (context.round);
4161debfc3dSmrg   from.c = f_from;
4171debfc3dSmrg   to.f = *decSingleFromWider (&to.f, &from.f, &context);
4181debfc3dSmrg   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
4191debfc3dSmrg     dfp_conversion_exceptions (context.status);
4201debfc3dSmrg   return to.c;
4211debfc3dSmrg }
4221debfc3dSmrg #endif
4231debfc3dSmrg 
4241debfc3dSmrg #if defined (L_td_to_sd)
4251debfc3dSmrg /* Use decNumber to convert directly from _Decimal128 to _Decimal32.  */
4261debfc3dSmrg _Decimal32
DFP_TO_DFP(_Decimal128 f_from)4271debfc3dSmrg DFP_TO_DFP (_Decimal128 f_from)
4281debfc3dSmrg {
4291debfc3dSmrg   union { _Decimal32 c; decSingle f; } to;
4301debfc3dSmrg   union { _Decimal128 c; decQuad f; } from;
4311debfc3dSmrg   decDouble temp;
4321debfc3dSmrg   decContext context;
4331debfc3dSmrg 
4341debfc3dSmrg   decContextDefault (&context, CONTEXT_INIT);
4351debfc3dSmrg   DFP_INIT_ROUNDMODE (context.round);
4361debfc3dSmrg   from.c = f_from;
4371debfc3dSmrg   temp = *decDoubleFromWider (&temp, &from.f, &context);
4381debfc3dSmrg   to.f = *decSingleFromWider (&to.f, &temp, &context);
4391debfc3dSmrg   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
4401debfc3dSmrg     dfp_conversion_exceptions (context.status);
4411debfc3dSmrg   return to.c;
4421debfc3dSmrg }
4431debfc3dSmrg #endif
4441debfc3dSmrg 
4451debfc3dSmrg #if defined (L_td_to_dd)
4461debfc3dSmrg /* Use decNumber to convert directly from _Decimal128 to _Decimal64.  */
4471debfc3dSmrg _Decimal64
DFP_TO_DFP(_Decimal128 f_from)4481debfc3dSmrg DFP_TO_DFP (_Decimal128 f_from)
4491debfc3dSmrg {
4501debfc3dSmrg   union { _Decimal64 c; decDouble f; } to;
4511debfc3dSmrg   union { _Decimal128 c; decQuad f; } from;
4521debfc3dSmrg   decContext context;
4531debfc3dSmrg 
4541debfc3dSmrg   decContextDefault (&context, CONTEXT_INIT);
4551debfc3dSmrg   DFP_INIT_ROUNDMODE (context.round);
4561debfc3dSmrg   from.c = f_from;
4571debfc3dSmrg   to.f = *decDoubleFromWider (&to.f, &from.f, &context);
4581debfc3dSmrg   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
4591debfc3dSmrg     dfp_conversion_exceptions (context.status);
4601debfc3dSmrg   return to.c;
4611debfc3dSmrg }
4621debfc3dSmrg #endif
4631debfc3dSmrg 
4641debfc3dSmrg #if defined (L_dd_to_si) || defined (L_td_to_si) \
4651debfc3dSmrg   || defined (L_dd_to_usi) || defined (L_td_to_usi)
4661debfc3dSmrg /* Use decNumber to convert directly from decimal float to integer types.  */
4671debfc3dSmrg INT_TYPE
DFP_TO_INT(DFP_C_TYPE x)4681debfc3dSmrg DFP_TO_INT (DFP_C_TYPE x)
4691debfc3dSmrg {
4701debfc3dSmrg   union { DFP_C_TYPE c; decFloat f; } u;
4711debfc3dSmrg   decContext context;
4721debfc3dSmrg   INT_TYPE i;
4731debfc3dSmrg 
4741debfc3dSmrg   decContextDefault (&context, DEC_INIT_DECIMAL128);
4751debfc3dSmrg   context.round = DEC_ROUND_DOWN;
4761debfc3dSmrg   u.c = x;
4771debfc3dSmrg   i = DEC_FLOAT_TO_INT (&u.f, &context, context.round);
4781debfc3dSmrg   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
4791debfc3dSmrg     dfp_conversion_exceptions (context.status);
4801debfc3dSmrg   return i;
4811debfc3dSmrg }
4821debfc3dSmrg #endif
4831debfc3dSmrg 
4841debfc3dSmrg #if defined (L_sd_to_si) || (L_sd_to_usi)
4851debfc3dSmrg /* Use decNumber to convert directly from decimal float to integer types.  */
4861debfc3dSmrg INT_TYPE
DFP_TO_INT(_Decimal32 x)4871debfc3dSmrg DFP_TO_INT (_Decimal32 x)
4881debfc3dSmrg {
4891debfc3dSmrg   union { _Decimal32 c; decSingle f; } u32;
4901debfc3dSmrg   decDouble f64;
4911debfc3dSmrg   decContext context;
4921debfc3dSmrg   INT_TYPE i;
4931debfc3dSmrg 
4941debfc3dSmrg   decContextDefault (&context, DEC_INIT_DECIMAL128);
4951debfc3dSmrg   context.round = DEC_ROUND_DOWN;
4961debfc3dSmrg   u32.c = x;
4971debfc3dSmrg   f64 = *decSingleToWider (&u32.f, &f64);
4981debfc3dSmrg   i = DEC_FLOAT_TO_INT (&f64, &context, context.round);
4991debfc3dSmrg   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
5001debfc3dSmrg     dfp_conversion_exceptions (context.status);
5011debfc3dSmrg   return i;
5021debfc3dSmrg }
5031debfc3dSmrg #endif
5041debfc3dSmrg 
5051debfc3dSmrg #if defined (L_sd_to_di) || defined (L_dd_to_di) || defined (L_td_to_di) \
5061debfc3dSmrg   || defined (L_sd_to_udi) || defined (L_dd_to_udi) || defined (L_td_to_udi)
5071debfc3dSmrg /* decNumber doesn't provide support for conversions to 64-bit integer
5081debfc3dSmrg    types, so do it the hard way.  */
5091debfc3dSmrg INT_TYPE
DFP_TO_INT(DFP_C_TYPE x)5101debfc3dSmrg DFP_TO_INT (DFP_C_TYPE x)
5111debfc3dSmrg {
5121debfc3dSmrg   /* decNumber's decimal* types have the same format as C's _Decimal*
5131debfc3dSmrg      types, but they have different calling conventions.  */
5141debfc3dSmrg 
5151debfc3dSmrg   /* TODO: Decimal float to integer conversions should raise FE_INVALID
5161debfc3dSmrg      if the result value does not fit into the result type.  */
5171debfc3dSmrg 
5181debfc3dSmrg   IEEE_TYPE s;
5191debfc3dSmrg   char buf[BUFMAX];
5201debfc3dSmrg   char *pos;
5211debfc3dSmrg   decNumber qval, n1, n2;
5221debfc3dSmrg   decContext context;
5231debfc3dSmrg 
5241debfc3dSmrg   /* Use a large context to avoid losing precision.  */
5251debfc3dSmrg   decContextDefault (&context, DEC_INIT_DECIMAL128);
5261debfc3dSmrg   /* Need non-default rounding mode here.  */
5271debfc3dSmrg   context.round = DEC_ROUND_DOWN;
5281debfc3dSmrg 
5291debfc3dSmrg   HOST_TO_IEEE (x, &s);
5301debfc3dSmrg   TO_INTERNAL (&s, &n1);
5311debfc3dSmrg   /* Rescale if the exponent is less than zero.  */
5321debfc3dSmrg   decNumberToIntegralValue (&n2, &n1, &context);
5331debfc3dSmrg   /* Get a value to use for the quantize call.  */
5341debfc3dSmrg   decNumberFromString (&qval, "1.", &context);
5351debfc3dSmrg   /* Force the exponent to zero.  */
5361debfc3dSmrg   decNumberQuantize (&n1, &n2, &qval, &context);
5371debfc3dSmrg   /* Get a string, which at this point will not include an exponent.  */
5381debfc3dSmrg   decNumberToString (&n1, buf);
5391debfc3dSmrg   /* Ignore the fractional part.  */
5401debfc3dSmrg   pos = strchr (buf, '.');
5411debfc3dSmrg   if (pos)
5421debfc3dSmrg     *pos = 0;
5431debfc3dSmrg   /* Use a C library function to convert to the integral type.  */
5441debfc3dSmrg   return STR_TO_INT (buf, NULL, 10);
5451debfc3dSmrg }
5461debfc3dSmrg #endif
5471debfc3dSmrg 
5481debfc3dSmrg #if defined (L_si_to_dd) || defined (L_si_to_td) \
5491debfc3dSmrg   || defined (L_usi_to_dd) || defined (L_usi_to_td)
5501debfc3dSmrg /* Use decNumber to convert directly from integer to decimal float types.  */
5511debfc3dSmrg DFP_C_TYPE
INT_TO_DFP(INT_TYPE i)5521debfc3dSmrg INT_TO_DFP (INT_TYPE i)
5531debfc3dSmrg {
5541debfc3dSmrg   union { DFP_C_TYPE c; decFloat f; } u;
5551debfc3dSmrg 
5561debfc3dSmrg   u.f = *DEC_FLOAT_FROM_INT (&u.f, i);
5571debfc3dSmrg   return u.c;
5581debfc3dSmrg }
5591debfc3dSmrg #endif
5601debfc3dSmrg 
5611debfc3dSmrg #if defined (L_si_to_sd) || defined (L_usi_to_sd)
5621debfc3dSmrg _Decimal32
5631debfc3dSmrg /* Use decNumber to convert directly from integer to decimal float types.  */
INT_TO_DFP(INT_TYPE i)5641debfc3dSmrg INT_TO_DFP (INT_TYPE i)
5651debfc3dSmrg {
5661debfc3dSmrg   union { _Decimal32 c; decSingle f; } u32;
5671debfc3dSmrg   decDouble f64;
5681debfc3dSmrg   decContext context;
5691debfc3dSmrg 
5701debfc3dSmrg   decContextDefault (&context, DEC_INIT_DECIMAL128);
5711debfc3dSmrg   f64 = *DEC_FLOAT_FROM_INT (&f64, i);
5721debfc3dSmrg   u32.f = *decSingleFromWider (&u32.f, &f64, &context);
5731debfc3dSmrg   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
5741debfc3dSmrg     dfp_conversion_exceptions (context.status);
5751debfc3dSmrg   return u32.c;
5761debfc3dSmrg }
5771debfc3dSmrg #endif
5781debfc3dSmrg 
5791debfc3dSmrg #if defined (L_di_to_sd) || defined (L_di_to_dd) || defined (L_di_to_td) \
5801debfc3dSmrg   || defined (L_udi_to_sd) || defined (L_udi_to_dd) || defined (L_udi_to_td)
5811debfc3dSmrg /* decNumber doesn't provide support for conversions from 64-bit integer
5821debfc3dSmrg    types, so do it the hard way.  */
5831debfc3dSmrg DFP_C_TYPE
INT_TO_DFP(INT_TYPE i)5841debfc3dSmrg INT_TO_DFP (INT_TYPE i)
5851debfc3dSmrg {
5861debfc3dSmrg   DFP_C_TYPE f;
5871debfc3dSmrg   IEEE_TYPE s;
5881debfc3dSmrg   char buf[BUFMAX];
5891debfc3dSmrg   decContext context;
5901debfc3dSmrg 
5911debfc3dSmrg   decContextDefault (&context, CONTEXT_INIT);
5921debfc3dSmrg   DFP_INIT_ROUNDMODE (context.round);
5931debfc3dSmrg 
5941debfc3dSmrg   /* Use a C library function to get a floating point string.  */
5951debfc3dSmrg   sprintf (buf, INT_FMT ".", CAST_FOR_FMT(i));
5961debfc3dSmrg   /* Convert from the floating point string to a decimal* type.  */
5971debfc3dSmrg   FROM_STRING (&s, buf, &context);
5981debfc3dSmrg   IEEE_TO_HOST (s, &f);
5991debfc3dSmrg 
6001debfc3dSmrg   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
6011debfc3dSmrg     dfp_conversion_exceptions (context.status);
6021debfc3dSmrg 
6031debfc3dSmrg   return f;
6041debfc3dSmrg }
6051debfc3dSmrg #endif
6061debfc3dSmrg 
6071debfc3dSmrg #if defined (L_sd_to_sf) || defined (L_dd_to_sf) || defined (L_td_to_sf) \
6081debfc3dSmrg  || defined (L_sd_to_df) || defined (L_dd_to_df) || defined (L_td_to_df) \
6091debfc3dSmrg  || ((defined (L_sd_to_xf) || defined (L_dd_to_xf) || defined (L_td_to_xf)) \
6101debfc3dSmrg      && LONG_DOUBLE_HAS_XF_MODE) \
6111debfc3dSmrg  || ((defined (L_sd_to_tf) || defined (L_dd_to_tf) || defined (L_td_to_tf)) \
6121debfc3dSmrg      && LONG_DOUBLE_HAS_TF_MODE)
6131debfc3dSmrg BFP_TYPE
DFP_TO_BFP(DFP_C_TYPE f)6141debfc3dSmrg DFP_TO_BFP (DFP_C_TYPE f)
6151debfc3dSmrg {
6161debfc3dSmrg   IEEE_TYPE s;
6171debfc3dSmrg   char buf[BUFMAX];
6181debfc3dSmrg 
6191debfc3dSmrg   HOST_TO_IEEE (f, &s);
6201debfc3dSmrg   /* Write the value to a string.  */
6211debfc3dSmrg   TO_STRING (&s, buf);
6221debfc3dSmrg   /* Read it as the binary floating point type and return that.  */
6231debfc3dSmrg   return STR_TO_BFP (buf, NULL);
6241debfc3dSmrg }
6251debfc3dSmrg #endif
6261debfc3dSmrg 
6271debfc3dSmrg #if defined (L_sf_to_sd) || defined (L_sf_to_dd) || defined (L_sf_to_td) \
6281debfc3dSmrg  || defined (L_df_to_sd) || defined (L_df_to_dd) || defined (L_df_to_td) \
6291debfc3dSmrg  || ((defined (L_xf_to_sd) || defined (L_xf_to_dd) || defined (L_xf_to_td)) \
6301debfc3dSmrg      && LONG_DOUBLE_HAS_XF_MODE) \
6311debfc3dSmrg  || ((defined (L_tf_to_sd) || defined (L_tf_to_dd) || defined (L_tf_to_td)) \
6321debfc3dSmrg      && LONG_DOUBLE_HAS_TF_MODE)
6331debfc3dSmrg DFP_C_TYPE
BFP_TO_DFP(BFP_TYPE x)6341debfc3dSmrg BFP_TO_DFP (BFP_TYPE x)
6351debfc3dSmrg {
6361debfc3dSmrg   DFP_C_TYPE f;
6371debfc3dSmrg   IEEE_TYPE s;
6381debfc3dSmrg   char buf[BUFMAX];
6391debfc3dSmrg   decContext context;
6401debfc3dSmrg 
6411debfc3dSmrg   decContextDefault (&context, CONTEXT_INIT);
6421debfc3dSmrg   DFP_INIT_ROUNDMODE (context.round);
6431debfc3dSmrg 
6441debfc3dSmrg   /* Use a C library function to write the floating point value to a string.  */
6451debfc3dSmrg   sprintf (buf, BFP_FMT, (BFP_VIA_TYPE) x);
6461debfc3dSmrg 
6471debfc3dSmrg   /* Convert from the floating point string to a decimal* type.  */
6481debfc3dSmrg   FROM_STRING (&s, buf, &context);
6491debfc3dSmrg   IEEE_TO_HOST (s, &f);
6501debfc3dSmrg 
6511debfc3dSmrg   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
6521debfc3dSmrg     {
6531debfc3dSmrg       /* decNumber exception flags we care about here.  */
6541debfc3dSmrg       int ieee_flags;
6551debfc3dSmrg       int dec_flags = DEC_IEEE_854_Inexact | DEC_IEEE_854_Invalid_operation
6561debfc3dSmrg 		      | DEC_IEEE_854_Overflow | DEC_IEEE_854_Underflow;
6571debfc3dSmrg       dec_flags &= context.status;
6581debfc3dSmrg       ieee_flags = DFP_IEEE_FLAGS (dec_flags);
6591debfc3dSmrg       if (ieee_flags != 0)
6601debfc3dSmrg         DFP_HANDLE_EXCEPTIONS (ieee_flags);
6611debfc3dSmrg     }
6621debfc3dSmrg 
6631debfc3dSmrg   return f;
6641debfc3dSmrg }
6651debfc3dSmrg #endif
6661debfc3dSmrg 
6671debfc3dSmrg #if defined (L_unord_sd) || defined (L_unord_dd) || defined (L_unord_td)
6681debfc3dSmrg CMPtype
DFP_UNORD(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)6691debfc3dSmrg DFP_UNORD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
6701debfc3dSmrg {
6711debfc3dSmrg   decNumber arg1, arg2;
6721debfc3dSmrg   IEEE_TYPE a, b;
6731debfc3dSmrg 
6741debfc3dSmrg   HOST_TO_IEEE (arg_a, &a);
6751debfc3dSmrg   HOST_TO_IEEE (arg_b, &b);
6761debfc3dSmrg   TO_INTERNAL (&a, &arg1);
6771debfc3dSmrg   TO_INTERNAL (&b, &arg2);
6781debfc3dSmrg   return (decNumberIsNaN (&arg1) || decNumberIsNaN (&arg2));
6791debfc3dSmrg }
6801debfc3dSmrg #endif /* L_unord_sd || L_unord_dd || L_unord_td */
681