]>
Commit | Line | Data |
---|---|---|
83ffe9cd | 1 | /* Copyright (C) 2007-2023 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 | ||
27 | /* | |
b2a00c89 | 28 | * Takes a BID64 as input and converts it to a BID128 and returns it. |
200359e8 | 29 | */ |
b2a00c89 | 30 | TYPE0_FUNCTION_ARGTYPE1_NORND (UINT128, bid64_to_bid128, UINT64, x) |
200359e8 | 31 | |
b2a00c89 L |
32 | UINT128 new_coeff, res; |
33 | UINT64 sign_x; | |
34 | int exponent_x; | |
35 | UINT64 coefficient_x; | |
36 | ||
37 | if (!unpack_BID64 (&sign_x, &exponent_x, &coefficient_x, x)) { | |
38 | if (((x) << 1) >= 0xf000000000000000ull) { | |
39 | #ifdef SET_STATUS_FLAGS | |
40 | if (((x) & SNAN_MASK64) == SNAN_MASK64) // sNaN | |
41 | __set_status_flags (pfpsf, INVALID_EXCEPTION); | |
42 | #endif | |
43 | res.w[0] = (coefficient_x & 0x0003ffffffffffffull); | |
44 | __mul_64x64_to_128 (res, res.w[0], power10_table_128[18].w[0]); | |
45 | res.w[1] |= ((coefficient_x) & 0xfc00000000000000ull); | |
200359e8 | 46 | BID_RETURN (res); |
b2a00c89 L |
47 | } |
48 | } | |
49 | ||
50 | new_coeff.w[0] = coefficient_x; | |
51 | new_coeff.w[1] = 0; | |
52 | get_BID128_very_fast (&res, sign_x, | |
53 | exponent_x + DECIMAL_EXPONENT_BIAS_128 - | |
54 | DECIMAL_EXPONENT_BIAS, new_coeff); | |
55 | BID_RETURN (res); | |
200359e8 L |
56 | } // convert_bid64_to_bid128 |
57 | ||
58 | ||
59 | ||
60 | /* | |
61 | * Takes a BID128 as input and converts it to a BID64 and returns it. | |
62 | */ | |
63 | #if DECIMAL_CALL_BY_REFERENCE | |
64 | ||
65 | void | |
b2a00c89 | 66 | bid128_to_bid64 (UINT64 * pres, |
200359e8 L |
67 | UINT128 * |
68 | px _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM | |
69 | _EXC_INFO_PARAM) { | |
70 | UINT128 x = *px; | |
71 | #else | |
72 | ||
73 | UINT64 | |
b2a00c89 | 74 | bid128_to_bid64 (UINT128 x _RND_MODE_PARAM _EXC_FLAGS_PARAM |
200359e8 L |
75 | _EXC_MASKS_PARAM _EXC_INFO_PARAM) { |
76 | #endif | |
b2a00c89 | 77 | UINT128 CX, T128, TP128, Qh, Ql, Qh1, Stemp, Tmp, Tmp1, CX1; |
200359e8 L |
78 | UINT64 sign_x, carry, cy, res; |
79 | SINT64 D; | |
80 | int_float f64, fx; | |
b2a00c89 | 81 | int exponent_x, extra_digits, amount, bin_expon_cx; |
200359e8 L |
82 | unsigned rmode, status, uf_check = 0; |
83 | ||
84 | #if DECIMAL_CALL_BY_REFERENCE | |
85 | #if !DECIMAL_GLOBAL_ROUNDING | |
86 | _IDEC_round rnd_mode = *prnd_mode; | |
87 | #endif | |
88 | #endif | |
89 | ||
b2a00c89 | 90 | BID_SWAP128 (x); |
200359e8 | 91 | // unpack arguments, check for NaN or Infinity or 0 |
b2a00c89 | 92 | if (!unpack_BID128_value (&sign_x, &exponent_x, &CX, x)) { |
200359e8 | 93 | if ((x.w[1] << 1) >= 0xf000000000000000ull) { |
b2a00c89 L |
94 | Tmp.w[1] = (CX.w[1] & 0x00003fffffffffffull); |
95 | Tmp.w[0] = CX.w[0]; | |
96 | TP128 = reciprocals10_128[18]; | |
97 | __mul_128x128_full (Qh, Ql, Tmp, TP128); | |
98 | amount = recip_scale[18]; | |
99 | __shr_128 (Tmp, Qh, amount); | |
100 | res = (CX.w[1] & 0xfc00000000000000ull) | Tmp.w[0]; | |
101 | #ifdef SET_STATUS_FLAGS | |
102 | if ((x.w[1] & SNAN_MASK64) == SNAN_MASK64) // sNaN | |
103 | __set_status_flags (pfpsf, INVALID_EXCEPTION); | |
104 | #endif | |
200359e8 L |
105 | BID_RETURN_VAL (res); |
106 | } | |
107 | exponent_x = | |
108 | exponent_x - DECIMAL_EXPONENT_BIAS_128 + DECIMAL_EXPONENT_BIAS; | |
109 | if (exponent_x < 0) { | |
110 | res = sign_x; | |
111 | BID_RETURN_VAL (res); | |
112 | } | |
113 | if (exponent_x > DECIMAL_MAX_EXPON_64) | |
114 | exponent_x = DECIMAL_MAX_EXPON_64; | |
115 | res = sign_x | (((UINT64) exponent_x) << 53); | |
116 | BID_RETURN_VAL (res); | |
117 | } | |
118 | ||
119 | if (CX.w[1] || (CX.w[0] >= 10000000000000000ull)) { | |
120 | // find number of digits in coefficient | |
121 | // 2^64 | |
122 | f64.i = 0x5f800000; | |
123 | // fx ~ CX | |
124 | fx.d = (float) CX.w[1] * f64.d + (float) CX.w[0]; | |
125 | bin_expon_cx = ((fx.i >> 23) & 0xff) - 0x7f; | |
b2a00c89 L |
126 | extra_digits = estimate_decimal_digits[bin_expon_cx] - 16; |
127 | // scale = 38-estimate_decimal_digits[bin_expon_cx]; | |
128 | D = CX.w[1] - power10_index_binexp_128[bin_expon_cx].w[1]; | |
200359e8 L |
129 | if (D > 0 |
130 | || (!D | |
b2a00c89 | 131 | && CX.w[0] >= power10_index_binexp_128[bin_expon_cx].w[0])) |
200359e8 L |
132 | extra_digits++; |
133 | ||
134 | exponent_x += extra_digits; | |
135 | ||
136 | #ifndef IEEE_ROUND_NEAREST_TIES_AWAY | |
137 | #ifndef IEEE_ROUND_NEAREST | |
138 | rmode = rnd_mode; | |
139 | if (sign_x && (unsigned) (rmode - 1) < 2) | |
140 | rmode = 3 - rmode; | |
141 | #else | |
142 | rmode = 0; | |
143 | #endif | |
144 | #else | |
145 | rmode = 0; | |
146 | #endif | |
147 | if (exponent_x < DECIMAL_EXPONENT_BIAS_128 - DECIMAL_EXPONENT_BIAS) { | |
148 | uf_check = 1; | |
b2a00c89 L |
149 | if (-extra_digits + exponent_x - DECIMAL_EXPONENT_BIAS_128 + |
150 | DECIMAL_EXPONENT_BIAS + 35 >= 0) { | |
151 | if (exponent_x == | |
152 | DECIMAL_EXPONENT_BIAS_128 - DECIMAL_EXPONENT_BIAS - 1) { | |
153 | T128 = round_const_table_128[rmode][extra_digits]; | |
154 | __add_carry_out (CX1.w[0], carry, T128.w[0], CX.w[0]); | |
155 | CX1.w[1] = CX.w[1] + T128.w[1] + carry; | |
156 | if (__unsigned_compare_ge_128 | |
157 | (CX1, power10_table_128[extra_digits + 16])) | |
158 | uf_check = 0; | |
159 | } | |
200359e8 | 160 | extra_digits = |
b2a00c89 L |
161 | extra_digits + DECIMAL_EXPONENT_BIAS_128 - |
162 | DECIMAL_EXPONENT_BIAS - exponent_x; | |
200359e8 | 163 | exponent_x = DECIMAL_EXPONENT_BIAS_128 - DECIMAL_EXPONENT_BIAS; |
b2a00c89 | 164 | //uf_check = 2; |
200359e8 L |
165 | } else |
166 | rmode = ROUNDING_TO_ZERO; | |
167 | } | |
168 | ||
b2a00c89 | 169 | T128 = round_const_table_128[rmode][extra_digits]; |
200359e8 L |
170 | __add_carry_out (CX.w[0], carry, T128.w[0], CX.w[0]); |
171 | CX.w[1] = CX.w[1] + T128.w[1] + carry; | |
172 | ||
b2a00c89 | 173 | TP128 = reciprocals10_128[extra_digits]; |
200359e8 | 174 | __mul_128x128_full (Qh, Ql, CX, TP128); |
b2a00c89 | 175 | amount = recip_scale[extra_digits]; |
200359e8 L |
176 | |
177 | if (amount >= 64) { | |
178 | CX.w[0] = Qh.w[1] >> (amount - 64); | |
179 | CX.w[1] = 0; | |
180 | } else { | |
181 | __shr_128 (CX, Qh, amount); | |
182 | } | |
183 | ||
184 | #ifndef IEEE_ROUND_NEAREST_TIES_AWAY | |
185 | #ifndef IEEE_ROUND_NEAREST | |
186 | if (!(rmode)) | |
187 | #endif | |
188 | if (CX.w[0] & 1) { | |
189 | // check whether fractional part of initial_P/10^ed1 is exactly .5 | |
190 | ||
191 | // get remainder | |
192 | __shl_128_long (Qh1, Qh, (128 - amount)); | |
193 | ||
194 | if (!Qh1.w[1] && !Qh1.w[0] | |
b2a00c89 L |
195 | && (Ql.w[1] < reciprocals10_128[extra_digits].w[1] |
196 | || (Ql.w[1] == reciprocals10_128[extra_digits].w[1] | |
197 | && Ql.w[0] < reciprocals10_128[extra_digits].w[0]))) { | |
200359e8 L |
198 | CX.w[0]--; |
199 | } | |
200 | } | |
201 | #endif | |
202 | ||
203 | { | |
204 | status = INEXACT_EXCEPTION; | |
205 | // get remainder | |
206 | __shl_128_long (Qh1, Qh, (128 - amount)); | |
207 | ||
208 | switch (rmode) { | |
209 | case ROUNDING_TO_NEAREST: | |
210 | case ROUNDING_TIES_AWAY: | |
211 | // test whether fractional part is 0 | |
212 | if (Qh1.w[1] == 0x8000000000000000ull && (!Qh1.w[0]) | |
b2a00c89 L |
213 | && (Ql.w[1] < reciprocals10_128[extra_digits].w[1] |
214 | || (Ql.w[1] == reciprocals10_128[extra_digits].w[1] | |
215 | && Ql.w[0] < reciprocals10_128[extra_digits].w[0]))) | |
200359e8 L |
216 | status = EXACT_STATUS; |
217 | break; | |
218 | case ROUNDING_DOWN: | |
219 | case ROUNDING_TO_ZERO: | |
220 | if ((!Qh1.w[1]) && (!Qh1.w[0]) | |
b2a00c89 L |
221 | && (Ql.w[1] < reciprocals10_128[extra_digits].w[1] |
222 | || (Ql.w[1] == reciprocals10_128[extra_digits].w[1] | |
223 | && Ql.w[0] < reciprocals10_128[extra_digits].w[0]))) | |
200359e8 L |
224 | status = EXACT_STATUS; |
225 | break; | |
226 | default: | |
227 | // round up | |
228 | __add_carry_out (Stemp.w[0], cy, Ql.w[0], | |
b2a00c89 | 229 | reciprocals10_128[extra_digits].w[0]); |
200359e8 | 230 | __add_carry_in_out (Stemp.w[1], carry, Ql.w[1], |
b2a00c89 | 231 | reciprocals10_128[extra_digits].w[1], cy); |
200359e8 L |
232 | __shr_128_long (Qh, Qh1, (128 - amount)); |
233 | Tmp.w[0] = 1; | |
234 | Tmp.w[1] = 0; | |
235 | __shl_128_long (Tmp1, Tmp, amount); | |
236 | Qh.w[0] += carry; | |
237 | if (Qh.w[0] < carry) | |
238 | Qh.w[1]++; | |
239 | if (__unsigned_compare_ge_128 (Qh, Tmp1)) | |
240 | status = EXACT_STATUS; | |
241 | } | |
242 | ||
243 | if (status != EXACT_STATUS) { | |
b2a00c89 L |
244 | if (uf_check) |
245 | status |= UNDERFLOW_EXCEPTION; | |
200359e8 L |
246 | #ifdef SET_STATUS_FLAGS |
247 | __set_status_flags (pfpsf, status); | |
248 | #endif | |
200359e8 | 249 | } |
b2a00c89 L |
250 | |
251 | ||
200359e8 L |
252 | } |
253 | ||
254 | } | |
255 | ||
256 | res = | |
257 | get_BID64 (sign_x, | |
258 | exponent_x - DECIMAL_EXPONENT_BIAS_128 + | |
259 | DECIMAL_EXPONENT_BIAS, CX.w[0], rnd_mode, pfpsf); | |
260 | BID_RETURN_VAL (res); | |
261 | ||
262 | } |