1 /* Copyright (C) 2007-2020 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