1 /* Copyright (C) 2007-2022 Free Software Foundation, Inc.
2 
3 This file is part of GCC.
4 
5 GCC is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free
7 Software Foundation; either version 3, or (at your option) any later
8 version.
9 
10 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13 for more details.
14 
15 Under Section 7 of GPL version 3, you are granted additional
16 permissions described in the GCC Runtime Library Exception, version
17 3.1, as published by the Free Software Foundation.
18 
19 You should have received a copy of the GNU General Public License and
20 a copy of the GCC Runtime Library Exception along with this program;
21 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
22 <http://www.gnu.org/licenses/>.  */
23 
24 #define BID_128RES
25 #include "bid_internal.h"
26 
27 /*
28  * Takes a BID32 as input and converts it to a BID128 and returns it.
29  */
TYPE0_FUNCTION_ARGTYPE1_NORND(UINT128,bid32_to_bid128,UINT32,x)30 TYPE0_FUNCTION_ARGTYPE1_NORND (UINT128, bid32_to_bid128, UINT32, x)
31 
32      UINT128 new_coeff, res;
33      UINT32 sign_x;
34      int exponent_x;
35      UINT32 coefficient_x;
36 
37 if (!unpack_BID32 (&sign_x, &exponent_x, &coefficient_x, x)) {
38 if (((x) & 0x78000000) == 0x78000000) {
39 #ifdef SET_STATUS_FLAGS
40   if (((x) & 0x7e000000) == 0x7e000000) // sNaN
41     __set_status_flags (pfpsf, INVALID_EXCEPTION);
42 #endif
43   res.w[0] = (coefficient_x & 0x000fffff);
44   __mul_64x128_low (res, res.w[0], power10_table_128[27]);
45   res.w[1] |=
46     ((((UINT64) coefficient_x) << 32) & 0xfc00000000000000ull);
47 
48   BID_RETURN (res);
49 }
50 }
51 
52 new_coeff.w[0] = coefficient_x;
53 new_coeff.w[1] = 0;
54 get_BID128_very_fast (&res, ((UINT64) sign_x) << 32,
55                           exponent_x + DECIMAL_EXPONENT_BIAS_128 -
56                           DECIMAL_EXPONENT_BIAS_32, new_coeff);
57 BID_RETURN (res);
58 }         // convert_bid32_to_bid128
59 
60 
61 /*
62  * Takes a BID128 as input and converts it to a BID32 and returns it.
63  */
64 #if DECIMAL_CALL_BY_REFERENCE
65 
66 void
67 bid128_to_bid32 (UINT32 * pres,
68                      UINT128 *
69                      px _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
70                      _EXC_INFO_PARAM) {
71   UINT128 x = *px;
72 #else
73 
74 UINT32
75 bid128_to_bid32 (UINT128 x _RND_MODE_PARAM _EXC_FLAGS_PARAM
76                      _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
77 #endif
78   UINT128 CX, T128, TP128, Qh, Ql, Qh1, Stemp, Tmp, Tmp1, CX1;
79   UINT64 sign_x, carry, cy;
80   SINT64 D;
81   UINT32 res;
82   int_float f64, fx;
83   int exponent_x, extra_digits, amount, bin_expon_cx, uf_check = 0;
84   unsigned rmode, status;
85 
86 #if DECIMAL_CALL_BY_REFERENCE
87 #if !DECIMAL_GLOBAL_ROUNDING
88   _IDEC_round rnd_mode = *prnd_mode;
89 #endif
90 #endif
91 
92   BID_SWAP128 (x);
93   // unpack arguments, check for NaN or Infinity or 0
94   if (!unpack_BID128_value (&sign_x, &exponent_x, &CX, x)) {
95     if (((x.w[1]) & 0x7800000000000000ull) == 0x7800000000000000ull) {
96       Tmp.w[1] = (CX.w[1] & 0x00003fffffffffffull);
97       Tmp.w[0] = CX.w[0];
98       TP128 = reciprocals10_128[27];
99       __mul_128x128_full (Qh, Ql, Tmp, TP128);
100       amount = recip_scale[27] - 64;
101       res = ((CX.w[1] >> 32) & 0xfc000000) | (Qh.w[1] >> amount);
102 #ifdef SET_STATUS_FLAGS
103       if ((x.w[1] & SNAN_MASK64) == SNAN_MASK64)  // sNaN
104           __set_status_flags (pfpsf, INVALID_EXCEPTION);
105 #endif
106       BID_RETURN_VAL (res);
107     }
108     // x is 0
109     exponent_x =
110       exponent_x - DECIMAL_EXPONENT_BIAS_128 + DECIMAL_EXPONENT_BIAS_32;
111     if (exponent_x < 0)
112       exponent_x = 0;
113     if (exponent_x > DECIMAL_MAX_EXPON_32)
114       exponent_x = DECIMAL_MAX_EXPON_32;
115     res = (sign_x >> 32) | (exponent_x << 23);
116     BID_RETURN_VAL (res);
117 
118   }
119 
120   if (CX.w[1] || (CX.w[0] >= 10000000)) {
121     // find number of digits in coefficient
122     // 2^64
123     f64.i = 0x5f800000;
124     // fx ~ CX
125     fx.d = (float) CX.w[1] * f64.d + (float) CX.w[0];
126     bin_expon_cx = ((fx.i >> 23) & 0xff) - 0x7f;
127     extra_digits = estimate_decimal_digits[bin_expon_cx] - 7;
128     // scale = 38-estimate_decimal_digits[bin_expon_cx];
129     D = CX.w[1] - power10_index_binexp_128[bin_expon_cx].w[1];
130     if (D > 0
131           || (!D
132               && CX.w[0] >= power10_index_binexp_128[bin_expon_cx].w[0]))
133       extra_digits++;
134 
135     exponent_x += extra_digits;
136 
137 #ifndef IEEE_ROUND_NEAREST_TIES_AWAY
138 #ifndef IEEE_ROUND_NEAREST
139     rmode = rnd_mode;
140     if (sign_x && (unsigned) (rmode - 1) < 2)
141       rmode = 3 - rmode;
142 #else
143     rmode = 0;
144 #endif
145 #else
146     rmode = 0;
147 #endif
148     if (exponent_x <
149           DECIMAL_EXPONENT_BIAS_128 - DECIMAL_EXPONENT_BIAS_32) {
150       uf_check = 1;
151       if (-extra_digits + exponent_x - DECIMAL_EXPONENT_BIAS_128 +
152             DECIMAL_EXPONENT_BIAS_32 + 35 >= 0) {
153           if (exponent_x ==
154               DECIMAL_EXPONENT_BIAS_128 - DECIMAL_EXPONENT_BIAS_32 - 1) {
155             T128 = round_const_table_128[rmode][extra_digits];
156             __add_carry_out (CX1.w[0], carry, T128.w[0], CX.w[0]);
157             CX1.w[1] = CX.w[1] + T128.w[1] + carry;
158             if (__unsigned_compare_ge_128
159                 (CX1, power10_table_128[extra_digits + 7]))
160               uf_check = 0;
161           }
162           extra_digits =
163             extra_digits + DECIMAL_EXPONENT_BIAS_128 -
164             DECIMAL_EXPONENT_BIAS_32 - exponent_x;
165           exponent_x =
166             DECIMAL_EXPONENT_BIAS_128 - DECIMAL_EXPONENT_BIAS_32;
167       } else
168           rmode = ROUNDING_TO_ZERO;
169     }
170 
171     T128 = round_const_table_128[rmode][extra_digits];
172     __add_carry_out (CX.w[0], carry, T128.w[0], CX.w[0]);
173     CX.w[1] = CX.w[1] + T128.w[1] + carry;
174 
175     TP128 = reciprocals10_128[extra_digits];
176     __mul_128x128_full (Qh, Ql, CX, TP128);
177     amount = recip_scale[extra_digits];
178 
179     if (amount >= 64) {
180       CX.w[0] = Qh.w[1] >> (amount - 64);
181       CX.w[1] = 0;
182     } else {
183       __shr_128 (CX, Qh, amount);
184     }
185 
186 #ifndef IEEE_ROUND_NEAREST_TIES_AWAY
187 #ifndef IEEE_ROUND_NEAREST
188     if (!(rnd_mode))
189 #endif
190       if (CX.w[0] & 1) {
191           // check whether fractional part of initial_P/10^ed1 is exactly .5
192 
193           // get remainder
194           __shl_128_long (Qh1, Qh, (128 - amount));
195 
196           if (!Qh1.w[1] && !Qh1.w[0]
197               && (Ql.w[1] < reciprocals10_128[extra_digits].w[1]
198                     || (Ql.w[1] == reciprocals10_128[extra_digits].w[1]
199                         && Ql.w[0] < reciprocals10_128[extra_digits].w[0]))) {
200             CX.w[0]--;
201           }
202       }
203 #endif
204 
205 
206     {
207       status = INEXACT_EXCEPTION;
208       // get remainder
209       __shl_128_long (Qh1, Qh, (128 - amount));
210 
211       switch (rmode) {
212       case ROUNDING_TO_NEAREST:
213       case ROUNDING_TIES_AWAY:
214           // test whether fractional part is 0
215           if (Qh1.w[1] == 0x8000000000000000ull && (!Qh1.w[0])
216               && (Ql.w[1] < reciprocals10_128[extra_digits].w[1]
217                     || (Ql.w[1] == reciprocals10_128[extra_digits].w[1]
218                         && Ql.w[0] < reciprocals10_128[extra_digits].w[0])))
219             status = EXACT_STATUS;
220           break;
221       case ROUNDING_DOWN:
222       case ROUNDING_TO_ZERO:
223           if ((!Qh1.w[1]) && (!Qh1.w[0])
224               && (Ql.w[1] < reciprocals10_128[extra_digits].w[1]
225                     || (Ql.w[1] == reciprocals10_128[extra_digits].w[1]
226                         && Ql.w[0] < reciprocals10_128[extra_digits].w[0])))
227             status = EXACT_STATUS;
228           break;
229       default:
230           // round up
231           __add_carry_out (Stemp.w[0], cy, Ql.w[0],
232                                reciprocals10_128[extra_digits].w[0]);
233           __add_carry_in_out (Stemp.w[1], carry, Ql.w[1],
234                                   reciprocals10_128[extra_digits].w[1], cy);
235           __shr_128_long (Qh, Qh1, (128 - amount));
236           Tmp.w[0] = 1;
237           Tmp.w[1] = 0;
238           __shl_128_long (Tmp1, Tmp, amount);
239           Qh.w[0] += carry;
240           if (Qh.w[0] < carry)
241             Qh.w[1]++;
242           if (__unsigned_compare_ge_128 (Qh, Tmp1))
243             status = EXACT_STATUS;
244       }
245 
246       if (status != EXACT_STATUS) {
247           if (uf_check) {
248             status |= UNDERFLOW_EXCEPTION;
249           }
250 #ifdef SET_STATUS_FLAGS
251           __set_status_flags (pfpsf, status);
252 #endif
253       }
254     }
255 
256   }
257 
258   res =
259     get_BID32 ((UINT32) (sign_x >> 32),
260                  exponent_x - DECIMAL_EXPONENT_BIAS_128 +
261                  DECIMAL_EXPONENT_BIAS_32, CX.w[0], rnd_mode, pfpsf);
262   BID_RETURN_VAL (res);
263 
264 }
265