]>
Commit | Line | Data |
---|---|---|
99dee823 | 1 | /* Copyright (C) 2007-2021 Free Software Foundation, Inc. |
200359e8 L |
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 | |
748086b7 | 7 | Software Foundation; either version 3, or (at your option) any later |
200359e8 L |
8 | version. |
9 | ||
200359e8 L |
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 | ||
748086b7 JJ |
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/>. */ | |
200359e8 L |
23 | |
24 | #define BID_128RES | |
25 | #include "bid_internal.h" | |
26 | ||
b2a00c89 | 27 | /* |
200359e8 L |
28 | * Takes a BID32 as input and converts it to a BID128 and returns it. |
29 | */ | |
b2a00c89 L |
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); | |
200359e8 | 47 | |
200359e8 | 48 | BID_RETURN (res); |
b2a00c89 L |
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 | |
200359e8 L |
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 | |
b2a00c89 | 67 | bid128_to_bid32 (UINT32 * pres, |
200359e8 L |
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 | |
b2a00c89 | 75 | bid128_to_bid32 (UINT128 x _RND_MODE_PARAM _EXC_FLAGS_PARAM |
200359e8 L |
76 | _EXC_MASKS_PARAM _EXC_INFO_PARAM) { |
77 | #endif | |
b2a00c89 | 78 | UINT128 CX, T128, TP128, Qh, Ql, Qh1, Stemp, Tmp, Tmp1, CX1; |
200359e8 L |
79 | UINT64 sign_x, carry, cy; |
80 | SINT64 D; | |
81 | UINT32 res; | |
82 | int_float f64, fx; | |
b2a00c89 | 83 | int exponent_x, extra_digits, amount, bin_expon_cx, uf_check = 0; |
200359e8 L |
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 | ||
b2a00c89 | 92 | BID_SWAP128 (x); |
200359e8 | 93 | // unpack arguments, check for NaN or Infinity or 0 |
b2a00c89 | 94 | if (!unpack_BID128_value (&sign_x, &exponent_x, &CX, x)) { |
200359e8 | 95 | if (((x.w[1]) & 0x7800000000000000ull) == 0x7800000000000000ull) { |
b2a00c89 L |
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 | |
200359e8 L |
106 | BID_RETURN_VAL (res); |
107 | } | |
108 | // x is 0 | |
b2a00c89 | 109 | exponent_x = |
200359e8 | 110 | exponent_x - DECIMAL_EXPONENT_BIAS_128 + DECIMAL_EXPONENT_BIAS_32; |
b2a00c89 L |
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 | ||
200359e8 L |
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; | |
b2a00c89 L |
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])) | |
200359e8 L |
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 | |
b2a00c89 L |
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]; | |
200359e8 L |
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 | ||
b2a00c89 | 175 | TP128 = reciprocals10_128[extra_digits]; |
200359e8 | 176 | __mul_128x128_full (Qh, Ql, CX, TP128); |
b2a00c89 | 177 | amount = recip_scale[extra_digits]; |
200359e8 L |
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] | |
b2a00c89 L |
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]))) { | |
200359e8 L |
200 | CX.w[0]--; |
201 | } | |
202 | } | |
203 | #endif | |
204 | ||
200359e8 L |
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]) | |
b2a00c89 L |
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]))) | |
200359e8 L |
219 | status = EXACT_STATUS; |
220 | break; | |
221 | case ROUNDING_DOWN: | |
222 | case ROUNDING_TO_ZERO: | |
223 | if ((!Qh1.w[1]) && (!Qh1.w[0]) | |
b2a00c89 L |
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]))) | |
200359e8 L |
227 | status = EXACT_STATUS; |
228 | break; | |
229 | default: | |
230 | // round up | |
231 | __add_carry_out (Stemp.w[0], cy, Ql.w[0], | |
b2a00c89 | 232 | reciprocals10_128[extra_digits].w[0]); |
200359e8 | 233 | __add_carry_in_out (Stemp.w[1], carry, Ql.w[1], |
b2a00c89 | 234 | reciprocals10_128[extra_digits].w[1], cy); |
200359e8 L |
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 | ||
b2a00c89 L |
246 | if (status != EXACT_STATUS) { |
247 | if (uf_check) { | |
248 | status |= UNDERFLOW_EXCEPTION; | |
249 | } | |
250 | #ifdef SET_STATUS_FLAGS | |
200359e8 | 251 | __set_status_flags (pfpsf, status); |
200359e8 | 252 | #endif |
b2a00c89 L |
253 | } |
254 | } | |
200359e8 L |
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 | } |