xref: /netbsd-src/external/gpl3/gcc/dist/libgcc/dfp-bit.c (revision b1e838363e3c6fc78a55519254d99869742dd33c)
148fb7bfaSmrg /* This is a software decimal floating point library.
2*b1e83836Smrg    Copyright (C) 2005-2022 Free Software Foundation, Inc.
348fb7bfaSmrg 
448fb7bfaSmrg This file is part of GCC.
548fb7bfaSmrg 
648fb7bfaSmrg GCC is free software; you can redistribute it and/or modify it under
748fb7bfaSmrg the terms of the GNU General Public License as published by the Free
848fb7bfaSmrg Software Foundation; either version 3, or (at your option) any later
948fb7bfaSmrg version.
1048fb7bfaSmrg 
1148fb7bfaSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1248fb7bfaSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
1348fb7bfaSmrg FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1448fb7bfaSmrg for more details.
1548fb7bfaSmrg 
1648fb7bfaSmrg Under Section 7 of GPL version 3, you are granted additional
1748fb7bfaSmrg permissions described in the GCC Runtime Library Exception, version
1848fb7bfaSmrg 3.1, as published by the Free Software Foundation.
1948fb7bfaSmrg 
2048fb7bfaSmrg You should have received a copy of the GNU General Public License and
2148fb7bfaSmrg a copy of the GCC Runtime Library Exception along with this program;
2248fb7bfaSmrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
2348fb7bfaSmrg <http://www.gnu.org/licenses/>.  */
2448fb7bfaSmrg 
2548fb7bfaSmrg /* This implements IEEE 754 decimal floating point arithmetic, but
2648fb7bfaSmrg    does not provide a mechanism for setting the rounding mode, or for
2748fb7bfaSmrg    generating or handling exceptions.  Conversions between decimal
2848fb7bfaSmrg    floating point types and other types depend on C library functions.
2948fb7bfaSmrg 
3048fb7bfaSmrg    Contributed by Ben Elliston  <bje@au.ibm.com>.  */
3148fb7bfaSmrg 
3248fb7bfaSmrg #include <stdio.h>
3348fb7bfaSmrg #include <stdlib.h>
3448fb7bfaSmrg /* FIXME: compile with -std=gnu99 to get these from stdlib.h */
3548fb7bfaSmrg extern float strtof (const char *, char **);
3648fb7bfaSmrg extern long double strtold (const char *, char **);
3748fb7bfaSmrg #include <string.h>
3848fb7bfaSmrg #include <limits.h>
3948fb7bfaSmrg 
4048fb7bfaSmrg #include "dfp-bit.h"
4148fb7bfaSmrg 
4248fb7bfaSmrg /* Forward declarations.  */
4348fb7bfaSmrg #if WIDTH == 32 || WIDTH_TO == 32
4448fb7bfaSmrg void __host_to_ieee_32 (_Decimal32 in, decimal32 *out);
4548fb7bfaSmrg void __ieee_to_host_32 (decimal32 in, _Decimal32 *out);
4648fb7bfaSmrg #endif
4748fb7bfaSmrg #if WIDTH == 64 || WIDTH_TO == 64
4848fb7bfaSmrg void __host_to_ieee_64 (_Decimal64 in, decimal64 *out);
4948fb7bfaSmrg void __ieee_to_host_64 (decimal64 in, _Decimal64 *out);
5048fb7bfaSmrg #endif
5148fb7bfaSmrg #if WIDTH == 128 || WIDTH_TO == 128
5248fb7bfaSmrg void __host_to_ieee_128 (_Decimal128 in, decimal128 *out);
5348fb7bfaSmrg void __ieee_to_host_128 (decimal128 in, _Decimal128 *out);
5448fb7bfaSmrg #endif
5548fb7bfaSmrg 
5648fb7bfaSmrg /* A pointer to a binary decFloat operation.  */
5748fb7bfaSmrg typedef decFloat* (*dfp_binary_func)
5848fb7bfaSmrg      (decFloat *, const decFloat *, const decFloat *, decContext *);
5948fb7bfaSmrg 
6048fb7bfaSmrg /* Binary operations.  */
6148fb7bfaSmrg 
6248fb7bfaSmrg /* Use a decFloat (decDouble or decQuad) function to perform a DFP
6348fb7bfaSmrg    binary operation.  */
6448fb7bfaSmrg static inline decFloat
dfp_binary_op(dfp_binary_func op,decFloat arg_a,decFloat arg_b)6548fb7bfaSmrg dfp_binary_op (dfp_binary_func op, decFloat arg_a, decFloat arg_b)
6648fb7bfaSmrg {
6748fb7bfaSmrg   decFloat result;
6848fb7bfaSmrg   decContext context;
6948fb7bfaSmrg 
7048fb7bfaSmrg   decContextDefault (&context, CONTEXT_INIT);
7148fb7bfaSmrg   DFP_INIT_ROUNDMODE (context.round);
7248fb7bfaSmrg 
7348fb7bfaSmrg   /* Perform the operation.  */
7448fb7bfaSmrg   op (&result, &arg_a, &arg_b, &context);
7548fb7bfaSmrg 
7648fb7bfaSmrg   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
7748fb7bfaSmrg     {
7848fb7bfaSmrg       /* decNumber exception flags we care about here.  */
7948fb7bfaSmrg       int ieee_flags;
8048fb7bfaSmrg       int dec_flags = DEC_IEEE_854_Division_by_zero | DEC_IEEE_854_Inexact
8148fb7bfaSmrg 		      | DEC_IEEE_854_Invalid_operation | DEC_IEEE_854_Overflow
8248fb7bfaSmrg 		      | DEC_IEEE_854_Underflow;
8348fb7bfaSmrg       dec_flags &= context.status;
8448fb7bfaSmrg       ieee_flags = DFP_IEEE_FLAGS (dec_flags);
8548fb7bfaSmrg       if (ieee_flags != 0)
8648fb7bfaSmrg         DFP_HANDLE_EXCEPTIONS (ieee_flags);
8748fb7bfaSmrg     }
8848fb7bfaSmrg 
8948fb7bfaSmrg   return result;
9048fb7bfaSmrg }
9148fb7bfaSmrg 
9248fb7bfaSmrg #if WIDTH == 32
9348fb7bfaSmrg /* The decNumber package doesn't provide arithmetic for decSingle (32 bits);
9448fb7bfaSmrg    convert to decDouble, use the operation for that, and convert back.  */
9548fb7bfaSmrg static inline _Decimal32
d32_binary_op(dfp_binary_func op,_Decimal32 arg_a,_Decimal32 arg_b)9648fb7bfaSmrg d32_binary_op (dfp_binary_func op, _Decimal32 arg_a, _Decimal32 arg_b)
9748fb7bfaSmrg {
9848fb7bfaSmrg   union { _Decimal32 c; decSingle f; } a32, b32, res32;
9948fb7bfaSmrg   decDouble a, b, res;
10048fb7bfaSmrg   decContext context;
10148fb7bfaSmrg 
10248fb7bfaSmrg   /* Widen the operands and perform the operation.  */
10348fb7bfaSmrg   a32.c = arg_a;
10448fb7bfaSmrg   b32.c = arg_b;
10548fb7bfaSmrg   decSingleToWider (&a32.f, &a);
10648fb7bfaSmrg   decSingleToWider (&b32.f, &b);
10748fb7bfaSmrg   res = dfp_binary_op (op, a, b);
10848fb7bfaSmrg 
10948fb7bfaSmrg   /* Narrow the result, which might result in an underflow or overflow.  */
11048fb7bfaSmrg   decContextDefault (&context, CONTEXT_INIT);
11148fb7bfaSmrg   DFP_INIT_ROUNDMODE (context.round);
11248fb7bfaSmrg   decSingleFromWider (&res32.f, &res, &context);
11348fb7bfaSmrg   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
11448fb7bfaSmrg     {
11548fb7bfaSmrg       /* decNumber exception flags we care about here.  */
11648fb7bfaSmrg       int ieee_flags;
11748fb7bfaSmrg       int dec_flags = DEC_IEEE_854_Inexact | DEC_IEEE_854_Overflow
11848fb7bfaSmrg 		      | DEC_IEEE_854_Underflow;
11948fb7bfaSmrg       dec_flags &= context.status;
12048fb7bfaSmrg       ieee_flags = DFP_IEEE_FLAGS (dec_flags);
12148fb7bfaSmrg       if (ieee_flags != 0)
12248fb7bfaSmrg         DFP_HANDLE_EXCEPTIONS (ieee_flags);
12348fb7bfaSmrg     }
12448fb7bfaSmrg 
12548fb7bfaSmrg   return res32.c;
12648fb7bfaSmrg }
12748fb7bfaSmrg #else
12848fb7bfaSmrg /* decFloat operations are supported for decDouble (64 bits) and
12948fb7bfaSmrg    decQuad (128 bits).  The bit patterns for the types are the same.  */
13048fb7bfaSmrg static inline DFP_C_TYPE
dnn_binary_op(dfp_binary_func op,DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)13148fb7bfaSmrg dnn_binary_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
13248fb7bfaSmrg {
13348fb7bfaSmrg   union { DFP_C_TYPE c; decFloat f; } a, b, result;
13448fb7bfaSmrg 
13548fb7bfaSmrg   a.c = arg_a;
13648fb7bfaSmrg   b.c = arg_b;
13748fb7bfaSmrg   result.f = dfp_binary_op (op, a.f, b.f);
13848fb7bfaSmrg   return result.c;
13948fb7bfaSmrg }
14048fb7bfaSmrg #endif
14148fb7bfaSmrg 
14248fb7bfaSmrg /* Comparison operations.  */
14348fb7bfaSmrg 
14448fb7bfaSmrg /* Use a decFloat (decDouble or decQuad) function to perform a DFP
14548fb7bfaSmrg    comparison.  */
14648fb7bfaSmrg static inline CMPtype
dfp_compare_op(dfp_binary_func op,decFloat arg_a,decFloat arg_b)14748fb7bfaSmrg dfp_compare_op (dfp_binary_func op, decFloat arg_a, decFloat arg_b)
14848fb7bfaSmrg {
14948fb7bfaSmrg   decContext context;
15048fb7bfaSmrg   decFloat res;
15148fb7bfaSmrg   int result;
15248fb7bfaSmrg 
15348fb7bfaSmrg   decContextDefault (&context, CONTEXT_INIT);
15448fb7bfaSmrg   DFP_INIT_ROUNDMODE (context.round);
15548fb7bfaSmrg 
15648fb7bfaSmrg   /* Perform the comparison.  */
15748fb7bfaSmrg   op (&res, &arg_a, &arg_b, &context);
15848fb7bfaSmrg 
15948fb7bfaSmrg   if (DEC_FLOAT_IS_SIGNED (&res))
16048fb7bfaSmrg     result = -1;
16148fb7bfaSmrg   else if (DEC_FLOAT_IS_ZERO (&res))
16248fb7bfaSmrg     result = 0;
16348fb7bfaSmrg   else if (DEC_FLOAT_IS_NAN (&res))
16448fb7bfaSmrg     result = -2;
16548fb7bfaSmrg   else
16648fb7bfaSmrg     result = 1;
16748fb7bfaSmrg 
16848fb7bfaSmrg   return (CMPtype) result;
16948fb7bfaSmrg }
17048fb7bfaSmrg 
17148fb7bfaSmrg #if WIDTH == 32
17248fb7bfaSmrg /* The decNumber package doesn't provide comparisons for decSingle (32 bits);
17348fb7bfaSmrg    convert to decDouble, use the operation for that, and convert back.  */
17448fb7bfaSmrg static inline CMPtype
d32_compare_op(dfp_binary_func op,_Decimal32 arg_a,_Decimal32 arg_b)17548fb7bfaSmrg d32_compare_op (dfp_binary_func op, _Decimal32 arg_a, _Decimal32 arg_b)
17648fb7bfaSmrg {
17748fb7bfaSmrg   union { _Decimal32 c; decSingle f; } a32, b32;
17848fb7bfaSmrg   decDouble a, b;
17948fb7bfaSmrg 
18048fb7bfaSmrg   a32.c = arg_a;
18148fb7bfaSmrg   b32.c = arg_b;
18248fb7bfaSmrg   decSingleToWider (&a32.f, &a);
18348fb7bfaSmrg   decSingleToWider (&b32.f, &b);
18448fb7bfaSmrg   return dfp_compare_op (op, a, b);
18548fb7bfaSmrg }
18648fb7bfaSmrg #else
18748fb7bfaSmrg /* decFloat comparisons are supported for decDouble (64 bits) and
18848fb7bfaSmrg    decQuad (128 bits).  The bit patterns for the types are the same.  */
18948fb7bfaSmrg static inline CMPtype
dnn_compare_op(dfp_binary_func op,DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)19048fb7bfaSmrg dnn_compare_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
19148fb7bfaSmrg {
19248fb7bfaSmrg   union { DFP_C_TYPE c; decFloat f; } a, b;
19348fb7bfaSmrg 
19448fb7bfaSmrg   a.c = arg_a;
19548fb7bfaSmrg   b.c = arg_b;
19648fb7bfaSmrg   return dfp_compare_op (op, a.f, b.f);
19748fb7bfaSmrg }
19848fb7bfaSmrg #endif
19948fb7bfaSmrg 
20048fb7bfaSmrg #if defined(L_conv_sd)
20148fb7bfaSmrg void
__host_to_ieee_32(_Decimal32 in,decimal32 * out)20248fb7bfaSmrg __host_to_ieee_32 (_Decimal32 in, decimal32 *out)
20348fb7bfaSmrg {
20448fb7bfaSmrg   memcpy (out, &in, 4);
20548fb7bfaSmrg }
20648fb7bfaSmrg 
20748fb7bfaSmrg void
__ieee_to_host_32(decimal32 in,_Decimal32 * out)20848fb7bfaSmrg __ieee_to_host_32 (decimal32 in, _Decimal32 *out)
20948fb7bfaSmrg {
21048fb7bfaSmrg   memcpy (out, &in, 4);
21148fb7bfaSmrg }
21248fb7bfaSmrg #endif /* L_conv_sd */
21348fb7bfaSmrg 
21448fb7bfaSmrg #if defined(L_conv_dd)
21548fb7bfaSmrg void
__host_to_ieee_64(_Decimal64 in,decimal64 * out)21648fb7bfaSmrg __host_to_ieee_64 (_Decimal64 in, decimal64 *out)
21748fb7bfaSmrg {
21848fb7bfaSmrg   memcpy (out, &in, 8);
21948fb7bfaSmrg }
22048fb7bfaSmrg 
22148fb7bfaSmrg void
__ieee_to_host_64(decimal64 in,_Decimal64 * out)22248fb7bfaSmrg __ieee_to_host_64 (decimal64 in, _Decimal64 *out)
22348fb7bfaSmrg {
22448fb7bfaSmrg   memcpy (out, &in, 8);
22548fb7bfaSmrg }
22648fb7bfaSmrg #endif /* L_conv_dd */
22748fb7bfaSmrg 
22848fb7bfaSmrg #if defined(L_conv_td)
22948fb7bfaSmrg void
__host_to_ieee_128(_Decimal128 in,decimal128 * out)23048fb7bfaSmrg __host_to_ieee_128 (_Decimal128 in, decimal128 *out)
23148fb7bfaSmrg {
23248fb7bfaSmrg   memcpy (out, &in, 16);
23348fb7bfaSmrg }
23448fb7bfaSmrg 
23548fb7bfaSmrg void
__ieee_to_host_128(decimal128 in,_Decimal128 * out)23648fb7bfaSmrg __ieee_to_host_128 (decimal128 in, _Decimal128 *out)
23748fb7bfaSmrg {
23848fb7bfaSmrg   memcpy (out, &in, 16);
23948fb7bfaSmrg }
24048fb7bfaSmrg #endif /* L_conv_td */
24148fb7bfaSmrg 
24248fb7bfaSmrg #if defined(L_addsub_sd) || defined(L_addsub_dd) || defined(L_addsub_td)
24348fb7bfaSmrg DFP_C_TYPE
DFP_ADD(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)24448fb7bfaSmrg DFP_ADD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
24548fb7bfaSmrg {
24648fb7bfaSmrg   return DFP_BINARY_OP (DEC_FLOAT_ADD, arg_a, arg_b);
24748fb7bfaSmrg }
24848fb7bfaSmrg 
24948fb7bfaSmrg DFP_C_TYPE
DFP_SUB(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)25048fb7bfaSmrg DFP_SUB (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
25148fb7bfaSmrg {
25248fb7bfaSmrg   return DFP_BINARY_OP (DEC_FLOAT_SUBTRACT, arg_a, arg_b);
25348fb7bfaSmrg }
25448fb7bfaSmrg #endif /* L_addsub */
25548fb7bfaSmrg 
25648fb7bfaSmrg #if defined(L_mul_sd) || defined(L_mul_dd) || defined(L_mul_td)
25748fb7bfaSmrg DFP_C_TYPE
DFP_MULTIPLY(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)25848fb7bfaSmrg DFP_MULTIPLY (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
25948fb7bfaSmrg {
26048fb7bfaSmrg   return DFP_BINARY_OP (DEC_FLOAT_MULTIPLY, arg_a, arg_b);
26148fb7bfaSmrg }
26248fb7bfaSmrg #endif /* L_mul */
26348fb7bfaSmrg 
26448fb7bfaSmrg #if defined(L_div_sd) || defined(L_div_dd) || defined(L_div_td)
26548fb7bfaSmrg DFP_C_TYPE
DFP_DIVIDE(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)26648fb7bfaSmrg DFP_DIVIDE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
26748fb7bfaSmrg {
26848fb7bfaSmrg   return DFP_BINARY_OP (DEC_FLOAT_DIVIDE, arg_a, arg_b);
26948fb7bfaSmrg }
27048fb7bfaSmrg #endif /* L_div */
27148fb7bfaSmrg 
27248fb7bfaSmrg #if defined (L_eq_sd) || defined (L_eq_dd) || defined (L_eq_td)
27348fb7bfaSmrg CMPtype
DFP_EQ(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)27448fb7bfaSmrg DFP_EQ (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
27548fb7bfaSmrg {
27648fb7bfaSmrg   CMPtype stat;
27748fb7bfaSmrg   stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
27848fb7bfaSmrg   /* For EQ return zero for true, nonzero for false.  */
27948fb7bfaSmrg   return stat != 0;
28048fb7bfaSmrg }
28148fb7bfaSmrg #endif /* L_eq */
28248fb7bfaSmrg 
28348fb7bfaSmrg #if defined (L_ne_sd) || defined (L_ne_dd) || defined (L_ne_td)
28448fb7bfaSmrg CMPtype
DFP_NE(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)28548fb7bfaSmrg DFP_NE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
28648fb7bfaSmrg {
28748fb7bfaSmrg   int stat;
28848fb7bfaSmrg   stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
28948fb7bfaSmrg   /* For NE return zero for true, nonzero for false.  */
29048fb7bfaSmrg   if (__builtin_expect (stat == -2, 0))  /* An operand is NaN.  */
29148fb7bfaSmrg     return 1;
29248fb7bfaSmrg   return stat != 0;
29348fb7bfaSmrg }
29448fb7bfaSmrg #endif /* L_ne */
29548fb7bfaSmrg 
29648fb7bfaSmrg #if defined (L_lt_sd) || defined (L_lt_dd) || defined (L_lt_td)
29748fb7bfaSmrg CMPtype
DFP_LT(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)29848fb7bfaSmrg DFP_LT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
29948fb7bfaSmrg {
30048fb7bfaSmrg   int stat;
30148fb7bfaSmrg   stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
30248fb7bfaSmrg   /* For LT return -1 (<0) for true, 1 for false.  */
30348fb7bfaSmrg   return (stat == -1) ? -1 : 1;
30448fb7bfaSmrg }
30548fb7bfaSmrg #endif /* L_lt */
30648fb7bfaSmrg 
30748fb7bfaSmrg #if defined (L_gt_sd) || defined (L_gt_dd) || defined (L_gt_td)
30848fb7bfaSmrg CMPtype
DFP_GT(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)30948fb7bfaSmrg DFP_GT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
31048fb7bfaSmrg {
31148fb7bfaSmrg   int stat;
31248fb7bfaSmrg   stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
31348fb7bfaSmrg   /* For GT return 1 (>0) for true, -1 for false.  */
31448fb7bfaSmrg   return (stat == 1) ? 1 : -1;
31548fb7bfaSmrg }
31648fb7bfaSmrg #endif
31748fb7bfaSmrg 
31848fb7bfaSmrg #if defined (L_le_sd) || defined (L_le_dd) || defined (L_le_td)
31948fb7bfaSmrg CMPtype
DFP_LE(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)32048fb7bfaSmrg DFP_LE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
32148fb7bfaSmrg {
32248fb7bfaSmrg   int stat;
32348fb7bfaSmrg   stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
32448fb7bfaSmrg   /* For LE return 0 (<= 0) for true, 1 for false.  */
32548fb7bfaSmrg   if (__builtin_expect (stat == -2, 0))  /* An operand is NaN.  */
32648fb7bfaSmrg     return 1;
32748fb7bfaSmrg   return stat == 1;
32848fb7bfaSmrg }
32948fb7bfaSmrg #endif /* L_le */
33048fb7bfaSmrg 
33148fb7bfaSmrg #if defined (L_ge_sd) || defined (L_ge_dd) || defined (L_ge_td)
33248fb7bfaSmrg CMPtype
DFP_GE(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)33348fb7bfaSmrg DFP_GE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
33448fb7bfaSmrg {
33548fb7bfaSmrg   int stat;
33648fb7bfaSmrg   stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
33748fb7bfaSmrg   /* For GE return 1 (>=0) for true, -1 for false.  */
33848fb7bfaSmrg   if (__builtin_expect (stat == -2, 0))  /* An operand is NaN.  */
33948fb7bfaSmrg     return -1;
34048fb7bfaSmrg   return (stat != -1) ? 1 : -1;
34148fb7bfaSmrg }
34248fb7bfaSmrg #endif /* L_ge */
34348fb7bfaSmrg 
34448fb7bfaSmrg #define BUFMAX 128
34548fb7bfaSmrg 
34648fb7bfaSmrg /* Check for floating point exceptions that are relevant for conversions
34748fb7bfaSmrg    between decimal float values and handle them.  */
34848fb7bfaSmrg static inline void
dfp_conversion_exceptions(const int status)34948fb7bfaSmrg dfp_conversion_exceptions (const int status)
35048fb7bfaSmrg {
35148fb7bfaSmrg   /* decNumber exception flags we care about here.  */
35248fb7bfaSmrg   int ieee_flags;
35348fb7bfaSmrg   int dec_flags = DEC_IEEE_854_Inexact | DEC_IEEE_854_Invalid_operation
35448fb7bfaSmrg 		  | DEC_IEEE_854_Overflow;
35548fb7bfaSmrg   dec_flags &= status;
35648fb7bfaSmrg   ieee_flags = DFP_IEEE_FLAGS (dec_flags);
35748fb7bfaSmrg   if (ieee_flags != 0)
35848fb7bfaSmrg     DFP_HANDLE_EXCEPTIONS (ieee_flags);
35948fb7bfaSmrg }
36048fb7bfaSmrg 
36148fb7bfaSmrg #if defined (L_sd_to_dd)
36248fb7bfaSmrg /* Use decNumber to convert directly from _Decimal32 to _Decimal64.  */
36348fb7bfaSmrg _Decimal64
DFP_TO_DFP(_Decimal32 f_from)36448fb7bfaSmrg DFP_TO_DFP (_Decimal32 f_from)
36548fb7bfaSmrg {
36648fb7bfaSmrg   union { _Decimal32 c; decSingle f; } from;
36748fb7bfaSmrg   union { _Decimal64 c; decDouble f; } to;
36848fb7bfaSmrg 
36948fb7bfaSmrg   from.c = f_from;
37048fb7bfaSmrg   to.f = *decSingleToWider (&from.f, &to.f);
37148fb7bfaSmrg   return to.c;
37248fb7bfaSmrg }
37348fb7bfaSmrg #endif
37448fb7bfaSmrg 
37548fb7bfaSmrg #if defined (L_sd_to_td)
37648fb7bfaSmrg /* Use decNumber to convert directly from _Decimal32 to _Decimal128.  */
37748fb7bfaSmrg _Decimal128
DFP_TO_DFP(_Decimal32 f_from)37848fb7bfaSmrg DFP_TO_DFP (_Decimal32 f_from)
37948fb7bfaSmrg {
38048fb7bfaSmrg   union { _Decimal32 c; decSingle f; } from;
38148fb7bfaSmrg   union { _Decimal128 c; decQuad f; } to;
38248fb7bfaSmrg   decDouble temp;
38348fb7bfaSmrg 
38448fb7bfaSmrg   from.c = f_from;
38548fb7bfaSmrg   temp = *decSingleToWider (&from.f, &temp);
38648fb7bfaSmrg   to.f = *decDoubleToWider (&temp, &to.f);
38748fb7bfaSmrg   return to.c;
38848fb7bfaSmrg }
38948fb7bfaSmrg #endif
39048fb7bfaSmrg 
39148fb7bfaSmrg #if defined (L_dd_to_td)
39248fb7bfaSmrg /* Use decNumber to convert directly from _Decimal64 to _Decimal128.  */
39348fb7bfaSmrg _Decimal128
DFP_TO_DFP(_Decimal64 f_from)39448fb7bfaSmrg DFP_TO_DFP (_Decimal64 f_from)
39548fb7bfaSmrg {
39648fb7bfaSmrg   union { _Decimal64 c; decDouble f; } from;
39748fb7bfaSmrg   union { _Decimal128 c; decQuad f; } to;
39848fb7bfaSmrg 
39948fb7bfaSmrg   from.c = f_from;
40048fb7bfaSmrg   to.f = *decDoubleToWider (&from.f, &to.f);
40148fb7bfaSmrg   return to.c;
40248fb7bfaSmrg }
40348fb7bfaSmrg #endif
40448fb7bfaSmrg 
40548fb7bfaSmrg #if defined (L_dd_to_sd)
40648fb7bfaSmrg /* Use decNumber to convert directly from _Decimal64 to _Decimal32.  */
40748fb7bfaSmrg _Decimal32
DFP_TO_DFP(_Decimal64 f_from)40848fb7bfaSmrg DFP_TO_DFP (_Decimal64 f_from)
40948fb7bfaSmrg {
41048fb7bfaSmrg   union { _Decimal32 c; decSingle f; } to;
41148fb7bfaSmrg   union { _Decimal64 c; decDouble f; } from;
41248fb7bfaSmrg   decContext context;
41348fb7bfaSmrg 
41448fb7bfaSmrg   decContextDefault (&context, CONTEXT_INIT);
41548fb7bfaSmrg   DFP_INIT_ROUNDMODE (context.round);
41648fb7bfaSmrg   from.c = f_from;
41748fb7bfaSmrg   to.f = *decSingleFromWider (&to.f, &from.f, &context);
41848fb7bfaSmrg   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
41948fb7bfaSmrg     dfp_conversion_exceptions (context.status);
42048fb7bfaSmrg   return to.c;
42148fb7bfaSmrg }
42248fb7bfaSmrg #endif
42348fb7bfaSmrg 
42448fb7bfaSmrg #if defined (L_td_to_sd)
42548fb7bfaSmrg /* Use decNumber to convert directly from _Decimal128 to _Decimal32.  */
42648fb7bfaSmrg _Decimal32
DFP_TO_DFP(_Decimal128 f_from)42748fb7bfaSmrg DFP_TO_DFP (_Decimal128 f_from)
42848fb7bfaSmrg {
42948fb7bfaSmrg   union { _Decimal32 c; decSingle f; } to;
43048fb7bfaSmrg   union { _Decimal128 c; decQuad f; } from;
43148fb7bfaSmrg   decDouble temp;
43248fb7bfaSmrg   decContext context;
43348fb7bfaSmrg 
43448fb7bfaSmrg   decContextDefault (&context, CONTEXT_INIT);
43548fb7bfaSmrg   DFP_INIT_ROUNDMODE (context.round);
43648fb7bfaSmrg   from.c = f_from;
43748fb7bfaSmrg   temp = *decDoubleFromWider (&temp, &from.f, &context);
43848fb7bfaSmrg   to.f = *decSingleFromWider (&to.f, &temp, &context);
43948fb7bfaSmrg   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
44048fb7bfaSmrg     dfp_conversion_exceptions (context.status);
44148fb7bfaSmrg   return to.c;
44248fb7bfaSmrg }
44348fb7bfaSmrg #endif
44448fb7bfaSmrg 
44548fb7bfaSmrg #if defined (L_td_to_dd)
44648fb7bfaSmrg /* Use decNumber to convert directly from _Decimal128 to _Decimal64.  */
44748fb7bfaSmrg _Decimal64
DFP_TO_DFP(_Decimal128 f_from)44848fb7bfaSmrg DFP_TO_DFP (_Decimal128 f_from)
44948fb7bfaSmrg {
45048fb7bfaSmrg   union { _Decimal64 c; decDouble f; } to;
45148fb7bfaSmrg   union { _Decimal128 c; decQuad f; } from;
45248fb7bfaSmrg   decContext context;
45348fb7bfaSmrg 
45448fb7bfaSmrg   decContextDefault (&context, CONTEXT_INIT);
45548fb7bfaSmrg   DFP_INIT_ROUNDMODE (context.round);
45648fb7bfaSmrg   from.c = f_from;
45748fb7bfaSmrg   to.f = *decDoubleFromWider (&to.f, &from.f, &context);
45848fb7bfaSmrg   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
45948fb7bfaSmrg     dfp_conversion_exceptions (context.status);
46048fb7bfaSmrg   return to.c;
46148fb7bfaSmrg }
46248fb7bfaSmrg #endif
46348fb7bfaSmrg 
46448fb7bfaSmrg #if defined (L_dd_to_si) || defined (L_td_to_si) \
46548fb7bfaSmrg   || defined (L_dd_to_usi) || defined (L_td_to_usi)
46648fb7bfaSmrg /* Use decNumber to convert directly from decimal float to integer types.  */
46748fb7bfaSmrg INT_TYPE
DFP_TO_INT(DFP_C_TYPE x)46848fb7bfaSmrg DFP_TO_INT (DFP_C_TYPE x)
46948fb7bfaSmrg {
47048fb7bfaSmrg   union { DFP_C_TYPE c; decFloat f; } u;
47148fb7bfaSmrg   decContext context;
47248fb7bfaSmrg   INT_TYPE i;
47348fb7bfaSmrg 
47448fb7bfaSmrg   decContextDefault (&context, DEC_INIT_DECIMAL128);
47548fb7bfaSmrg   context.round = DEC_ROUND_DOWN;
47648fb7bfaSmrg   u.c = x;
47748fb7bfaSmrg   i = DEC_FLOAT_TO_INT (&u.f, &context, context.round);
47848fb7bfaSmrg   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
47948fb7bfaSmrg     dfp_conversion_exceptions (context.status);
48048fb7bfaSmrg   return i;
48148fb7bfaSmrg }
48248fb7bfaSmrg #endif
48348fb7bfaSmrg 
48448fb7bfaSmrg #if defined (L_sd_to_si) || (L_sd_to_usi)
48548fb7bfaSmrg /* Use decNumber to convert directly from decimal float to integer types.  */
48648fb7bfaSmrg INT_TYPE
DFP_TO_INT(_Decimal32 x)48748fb7bfaSmrg DFP_TO_INT (_Decimal32 x)
48848fb7bfaSmrg {
48948fb7bfaSmrg   union { _Decimal32 c; decSingle f; } u32;
49048fb7bfaSmrg   decDouble f64;
49148fb7bfaSmrg   decContext context;
49248fb7bfaSmrg   INT_TYPE i;
49348fb7bfaSmrg 
49448fb7bfaSmrg   decContextDefault (&context, DEC_INIT_DECIMAL128);
49548fb7bfaSmrg   context.round = DEC_ROUND_DOWN;
49648fb7bfaSmrg   u32.c = x;
49748fb7bfaSmrg   f64 = *decSingleToWider (&u32.f, &f64);
49848fb7bfaSmrg   i = DEC_FLOAT_TO_INT (&f64, &context, context.round);
49948fb7bfaSmrg   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
50048fb7bfaSmrg     dfp_conversion_exceptions (context.status);
50148fb7bfaSmrg   return i;
50248fb7bfaSmrg }
50348fb7bfaSmrg #endif
50448fb7bfaSmrg 
50548fb7bfaSmrg #if defined (L_sd_to_di) || defined (L_dd_to_di) || defined (L_td_to_di) \
50648fb7bfaSmrg   || defined (L_sd_to_udi) || defined (L_dd_to_udi) || defined (L_td_to_udi)
50748fb7bfaSmrg /* decNumber doesn't provide support for conversions to 64-bit integer
50848fb7bfaSmrg    types, so do it the hard way.  */
50948fb7bfaSmrg INT_TYPE
DFP_TO_INT(DFP_C_TYPE x)51048fb7bfaSmrg DFP_TO_INT (DFP_C_TYPE x)
51148fb7bfaSmrg {
51248fb7bfaSmrg   /* decNumber's decimal* types have the same format as C's _Decimal*
51348fb7bfaSmrg      types, but they have different calling conventions.  */
51448fb7bfaSmrg 
51548fb7bfaSmrg   /* TODO: Decimal float to integer conversions should raise FE_INVALID
51648fb7bfaSmrg      if the result value does not fit into the result type.  */
51748fb7bfaSmrg 
51848fb7bfaSmrg   IEEE_TYPE s;
51948fb7bfaSmrg   char buf[BUFMAX];
52048fb7bfaSmrg   char *pos;
52148fb7bfaSmrg   decNumber qval, n1, n2;
52248fb7bfaSmrg   decContext context;
52348fb7bfaSmrg 
52448fb7bfaSmrg   /* Use a large context to avoid losing precision.  */
52548fb7bfaSmrg   decContextDefault (&context, DEC_INIT_DECIMAL128);
52648fb7bfaSmrg   /* Need non-default rounding mode here.  */
52748fb7bfaSmrg   context.round = DEC_ROUND_DOWN;
52848fb7bfaSmrg 
52948fb7bfaSmrg   HOST_TO_IEEE (x, &s);
53048fb7bfaSmrg   TO_INTERNAL (&s, &n1);
53148fb7bfaSmrg   /* Rescale if the exponent is less than zero.  */
53248fb7bfaSmrg   decNumberToIntegralValue (&n2, &n1, &context);
53348fb7bfaSmrg   /* Get a value to use for the quantize call.  */
53448fb7bfaSmrg   decNumberFromString (&qval, "1.", &context);
53548fb7bfaSmrg   /* Force the exponent to zero.  */
53648fb7bfaSmrg   decNumberQuantize (&n1, &n2, &qval, &context);
53748fb7bfaSmrg   /* Get a string, which at this point will not include an exponent.  */
53848fb7bfaSmrg   decNumberToString (&n1, buf);
53948fb7bfaSmrg   /* Ignore the fractional part.  */
54048fb7bfaSmrg   pos = strchr (buf, '.');
54148fb7bfaSmrg   if (pos)
54248fb7bfaSmrg     *pos = 0;
54348fb7bfaSmrg   /* Use a C library function to convert to the integral type.  */
54448fb7bfaSmrg   return STR_TO_INT (buf, NULL, 10);
54548fb7bfaSmrg }
54648fb7bfaSmrg #endif
54748fb7bfaSmrg 
54848fb7bfaSmrg #if defined (L_si_to_dd) || defined (L_si_to_td) \
54948fb7bfaSmrg   || defined (L_usi_to_dd) || defined (L_usi_to_td)
55048fb7bfaSmrg /* Use decNumber to convert directly from integer to decimal float types.  */
55148fb7bfaSmrg DFP_C_TYPE
INT_TO_DFP(INT_TYPE i)55248fb7bfaSmrg INT_TO_DFP (INT_TYPE i)
55348fb7bfaSmrg {
55448fb7bfaSmrg   union { DFP_C_TYPE c; decFloat f; } u;
55548fb7bfaSmrg 
55648fb7bfaSmrg   u.f = *DEC_FLOAT_FROM_INT (&u.f, i);
55748fb7bfaSmrg   return u.c;
55848fb7bfaSmrg }
55948fb7bfaSmrg #endif
56048fb7bfaSmrg 
56148fb7bfaSmrg #if defined (L_si_to_sd) || defined (L_usi_to_sd)
56248fb7bfaSmrg _Decimal32
56348fb7bfaSmrg /* Use decNumber to convert directly from integer to decimal float types.  */
INT_TO_DFP(INT_TYPE i)56448fb7bfaSmrg INT_TO_DFP (INT_TYPE i)
56548fb7bfaSmrg {
56648fb7bfaSmrg   union { _Decimal32 c; decSingle f; } u32;
56748fb7bfaSmrg   decDouble f64;
56848fb7bfaSmrg   decContext context;
56948fb7bfaSmrg 
57048fb7bfaSmrg   decContextDefault (&context, DEC_INIT_DECIMAL128);
57148fb7bfaSmrg   f64 = *DEC_FLOAT_FROM_INT (&f64, i);
57248fb7bfaSmrg   u32.f = *decSingleFromWider (&u32.f, &f64, &context);
57348fb7bfaSmrg   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
57448fb7bfaSmrg     dfp_conversion_exceptions (context.status);
57548fb7bfaSmrg   return u32.c;
57648fb7bfaSmrg }
57748fb7bfaSmrg #endif
57848fb7bfaSmrg 
57948fb7bfaSmrg #if defined (L_di_to_sd) || defined (L_di_to_dd) || defined (L_di_to_td) \
58048fb7bfaSmrg   || defined (L_udi_to_sd) || defined (L_udi_to_dd) || defined (L_udi_to_td)
58148fb7bfaSmrg /* decNumber doesn't provide support for conversions from 64-bit integer
58248fb7bfaSmrg    types, so do it the hard way.  */
58348fb7bfaSmrg DFP_C_TYPE
INT_TO_DFP(INT_TYPE i)58448fb7bfaSmrg INT_TO_DFP (INT_TYPE i)
58548fb7bfaSmrg {
58648fb7bfaSmrg   DFP_C_TYPE f;
58748fb7bfaSmrg   IEEE_TYPE s;
58848fb7bfaSmrg   char buf[BUFMAX];
58948fb7bfaSmrg   decContext context;
59048fb7bfaSmrg 
59148fb7bfaSmrg   decContextDefault (&context, CONTEXT_INIT);
59248fb7bfaSmrg   DFP_INIT_ROUNDMODE (context.round);
59348fb7bfaSmrg 
59448fb7bfaSmrg   /* Use a C library function to get a floating point string.  */
59548fb7bfaSmrg   sprintf (buf, INT_FMT ".", CAST_FOR_FMT(i));
59648fb7bfaSmrg   /* Convert from the floating point string to a decimal* type.  */
59748fb7bfaSmrg   FROM_STRING (&s, buf, &context);
59848fb7bfaSmrg   IEEE_TO_HOST (s, &f);
59948fb7bfaSmrg 
60048fb7bfaSmrg   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
60148fb7bfaSmrg     dfp_conversion_exceptions (context.status);
60248fb7bfaSmrg 
60348fb7bfaSmrg   return f;
60448fb7bfaSmrg }
60548fb7bfaSmrg #endif
60648fb7bfaSmrg 
60748fb7bfaSmrg #if defined (L_sd_to_sf) || defined (L_dd_to_sf) || defined (L_td_to_sf) \
60848fb7bfaSmrg  || defined (L_sd_to_df) || defined (L_dd_to_df) || defined (L_td_to_df) \
609*b1e83836Smrg  || defined (L_sd_to_kf) || defined (L_dd_to_kf) || defined (L_td_to_kf) \
61048fb7bfaSmrg  || ((defined (L_sd_to_xf) || defined (L_dd_to_xf) || defined (L_td_to_xf)) \
61148fb7bfaSmrg      && LONG_DOUBLE_HAS_XF_MODE) \
61248fb7bfaSmrg  || ((defined (L_sd_to_tf) || defined (L_dd_to_tf) || defined (L_td_to_tf)) \
61348fb7bfaSmrg      && LONG_DOUBLE_HAS_TF_MODE)
61448fb7bfaSmrg BFP_TYPE
DFP_TO_BFP(DFP_C_TYPE f)61548fb7bfaSmrg DFP_TO_BFP (DFP_C_TYPE f)
61648fb7bfaSmrg {
61748fb7bfaSmrg   IEEE_TYPE s;
61848fb7bfaSmrg   char buf[BUFMAX];
61948fb7bfaSmrg 
62048fb7bfaSmrg   HOST_TO_IEEE (f, &s);
62148fb7bfaSmrg   /* Write the value to a string.  */
62248fb7bfaSmrg   TO_STRING (&s, buf);
62348fb7bfaSmrg   /* Read it as the binary floating point type and return that.  */
62448fb7bfaSmrg   return STR_TO_BFP (buf, NULL);
62548fb7bfaSmrg }
62648fb7bfaSmrg #endif
62748fb7bfaSmrg 
62848fb7bfaSmrg #if defined (L_sf_to_sd) || defined (L_sf_to_dd) || defined (L_sf_to_td) \
62948fb7bfaSmrg  || defined (L_df_to_sd) || defined (L_df_to_dd) || defined (L_df_to_td) \
630*b1e83836Smrg  || defined (L_kf_to_sd) || defined (L_kf_to_dd) || defined (L_kf_to_td) \
63148fb7bfaSmrg  || ((defined (L_xf_to_sd) || defined (L_xf_to_dd) || defined (L_xf_to_td)) \
63248fb7bfaSmrg      && LONG_DOUBLE_HAS_XF_MODE) \
63348fb7bfaSmrg  || ((defined (L_tf_to_sd) || defined (L_tf_to_dd) || defined (L_tf_to_td)) \
63448fb7bfaSmrg      && LONG_DOUBLE_HAS_TF_MODE)
63548fb7bfaSmrg DFP_C_TYPE
BFP_TO_DFP(BFP_TYPE x)63648fb7bfaSmrg BFP_TO_DFP (BFP_TYPE x)
63748fb7bfaSmrg {
63848fb7bfaSmrg   DFP_C_TYPE f;
63948fb7bfaSmrg   IEEE_TYPE s;
64048fb7bfaSmrg   char buf[BUFMAX];
64148fb7bfaSmrg   decContext context;
64248fb7bfaSmrg 
64348fb7bfaSmrg   decContextDefault (&context, CONTEXT_INIT);
64448fb7bfaSmrg   DFP_INIT_ROUNDMODE (context.round);
64548fb7bfaSmrg 
646*b1e83836Smrg   /* Use the sprintf library function to write the floating point value to a
647*b1e83836Smrg      string.
648*b1e83836Smrg 
649*b1e83836Smrg      If we are handling the IEEE 128-bit floating point on PowerPC, use the
650*b1e83836Smrg      special function __sprintfkf instead of sprintf.  This function allows us
651*b1e83836Smrg      to use __sprintfieee128 if we have a new enough GLIBC, and it can fall back
652*b1e83836Smrg      to using the traditional sprintf via conversion to IBM 128-bit if the glibc
653*b1e83836Smrg      is older.  */
654*b1e83836Smrg   BFP_SPRINTF (buf, BFP_FMT, (BFP_VIA_TYPE) x);
65548fb7bfaSmrg 
65648fb7bfaSmrg   /* Convert from the floating point string to a decimal* type.  */
65748fb7bfaSmrg   FROM_STRING (&s, buf, &context);
65848fb7bfaSmrg   IEEE_TO_HOST (s, &f);
65948fb7bfaSmrg 
66048fb7bfaSmrg   if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
66148fb7bfaSmrg     {
66248fb7bfaSmrg       /* decNumber exception flags we care about here.  */
66348fb7bfaSmrg       int ieee_flags;
66448fb7bfaSmrg       int dec_flags = DEC_IEEE_854_Inexact | DEC_IEEE_854_Invalid_operation
66548fb7bfaSmrg 		      | DEC_IEEE_854_Overflow | DEC_IEEE_854_Underflow;
66648fb7bfaSmrg       dec_flags &= context.status;
66748fb7bfaSmrg       ieee_flags = DFP_IEEE_FLAGS (dec_flags);
66848fb7bfaSmrg       if (ieee_flags != 0)
66948fb7bfaSmrg         DFP_HANDLE_EXCEPTIONS (ieee_flags);
67048fb7bfaSmrg     }
67148fb7bfaSmrg 
67248fb7bfaSmrg   return f;
67348fb7bfaSmrg }
67448fb7bfaSmrg #endif
67548fb7bfaSmrg 
67648fb7bfaSmrg #if defined (L_unord_sd) || defined (L_unord_dd) || defined (L_unord_td)
67748fb7bfaSmrg CMPtype
DFP_UNORD(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)67848fb7bfaSmrg DFP_UNORD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
67948fb7bfaSmrg {
68048fb7bfaSmrg   decNumber arg1, arg2;
68148fb7bfaSmrg   IEEE_TYPE a, b;
68248fb7bfaSmrg 
68348fb7bfaSmrg   HOST_TO_IEEE (arg_a, &a);
68448fb7bfaSmrg   HOST_TO_IEEE (arg_b, &b);
68548fb7bfaSmrg   TO_INTERNAL (&a, &arg1);
68648fb7bfaSmrg   TO_INTERNAL (&b, &arg2);
68748fb7bfaSmrg   return (decNumberIsNaN (&arg1) || decNumberIsNaN (&arg2));
68848fb7bfaSmrg }
68948fb7bfaSmrg #endif /* L_unord_sd || L_unord_dd || L_unord_td */
690