[NDS32] Support Linux target for nds32.
[official-gcc.git] / libgcc / config / libbid / bid_from_int.c
blob5424d4f339b7df263a23f4a4d647c64f4c00c6c7
1 /* Copyright (C) 2007-2018 Free Software Foundation, Inc.
3 This file is part of GCC.
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.
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.
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.
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/>. */
24 #include "bid_internal.h"
26 /*****************************************************************************
27 * BID64_round_integral_exact
28 ****************************************************************************/
30 #if DECIMAL_CALL_BY_REFERENCE
31 void
32 bid64_from_int32 (UINT64 * pres,
33 int *px _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
34 int x = *px;
35 #else
36 UINT64
37 bid64_from_int32 (int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
38 #endif
39 UINT64 res;
41 // if integer is negative, put the absolute value
42 // in the lowest 32bits of the result
43 if ((x & SIGNMASK32) == SIGNMASK32) {
44 // negative int32
45 x = ~x + 1; // 2's complement of x
46 res = (unsigned int) x | 0xb1c0000000000000ull;
47 // (exp << 53)) = biased exp. is 0
48 } else { // positive int32
49 res = x | 0x31c0000000000000ull; // (exp << 53)) = biased exp. is 0
51 BID_RETURN (res);
54 #if DECIMAL_CALL_BY_REFERENCE
55 void
56 bid64_from_uint32 (UINT64 * pres, unsigned int *px
57 _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
58 unsigned int x = *px;
59 #else
60 UINT64
61 bid64_from_uint32 (unsigned int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
62 #endif
63 UINT64 res;
65 res = x | 0x31c0000000000000ull; // (exp << 53)) = biased exp. is 0
66 BID_RETURN (res);
69 #if DECIMAL_CALL_BY_REFERENCE
70 void
71 bid64_from_int64 (UINT64 * pres, SINT64 * px
72 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
73 _EXC_INFO_PARAM) {
74 SINT64 x = *px;
75 #if !DECIMAL_GLOBAL_ROUNDING
76 unsigned int rnd_mode = *prnd_mode;
77 #endif
78 #else
79 UINT64
80 bid64_from_int64 (SINT64 x
81 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
82 _EXC_INFO_PARAM) {
83 #endif
85 UINT64 res;
86 UINT64 x_sign, C;
87 unsigned int q, ind;
88 int incr_exp = 0;
89 int is_midpoint_lt_even = 0, is_midpoint_gt_even = 0;
90 int is_inexact_lt_midpoint = 0, is_inexact_gt_midpoint = 0;
92 x_sign = x & 0x8000000000000000ull;
93 // if the integer is negative, use the absolute value
94 if (x_sign)
95 C = ~((UINT64) x) + 1;
96 else
97 C = x;
98 if (C <= BID64_SIG_MAX) { // |C| <= 10^16-1 and the result is exact
99 if (C < 0x0020000000000000ull) { // C < 2^53
100 res = x_sign | 0x31c0000000000000ull | C;
101 } else { // C >= 2^53
102 res =
103 x_sign | 0x6c70000000000000ull | (C & 0x0007ffffffffffffull);
105 } else { // |C| >= 10^16 and the result may be inexact
106 // the smallest |C| is 10^16 which has 17 decimal digits
107 // the largest |C| is 0x8000000000000000 = 9223372036854775808 w/ 19 digits
108 if (C < 0x16345785d8a0000ull) { // x < 10^17
109 q = 17;
110 ind = 1; // number of digits to remove for q = 17
111 } else if (C < 0xde0b6b3a7640000ull) { // C < 10^18
112 q = 18;
113 ind = 2; // number of digits to remove for q = 18
114 } else { // C < 10^19
115 q = 19;
116 ind = 3; // number of digits to remove for q = 19
118 // overflow and underflow are not possible
119 // Note: performace can be improved by inlining this call
120 round64_2_18 ( // will work for 19 digits too if C fits in 64 bits
121 q, ind, C, &res, &incr_exp,
122 &is_midpoint_lt_even, &is_midpoint_gt_even,
123 &is_inexact_lt_midpoint, &is_inexact_gt_midpoint);
124 if (incr_exp)
125 ind++;
126 // set the inexact flag
127 if (is_inexact_lt_midpoint || is_inexact_gt_midpoint ||
128 is_midpoint_lt_even || is_midpoint_gt_even)
129 *pfpsf |= INEXACT_EXCEPTION;
130 // general correction from RN to RA, RM, RP, RZ; result uses ind for exp
131 if (rnd_mode != ROUNDING_TO_NEAREST) {
132 if ((!x_sign
133 && ((rnd_mode == ROUNDING_UP && is_inexact_lt_midpoint)
135 ((rnd_mode == ROUNDING_TIES_AWAY
136 || rnd_mode == ROUNDING_UP) && is_midpoint_gt_even)))
137 || (x_sign
138 && ((rnd_mode == ROUNDING_DOWN && is_inexact_lt_midpoint)
140 ((rnd_mode == ROUNDING_TIES_AWAY
141 || rnd_mode == ROUNDING_DOWN)
142 && is_midpoint_gt_even)))) {
143 res = res + 1;
144 if (res == 0x002386f26fc10000ull) { // res = 10^16 => rounding overflow
145 res = 0x00038d7ea4c68000ull; // 10^15
146 ind = ind + 1;
148 } else if ((is_midpoint_lt_even || is_inexact_gt_midpoint) &&
149 ((x_sign && (rnd_mode == ROUNDING_UP ||
150 rnd_mode == ROUNDING_TO_ZERO)) ||
151 (!x_sign && (rnd_mode == ROUNDING_DOWN ||
152 rnd_mode == ROUNDING_TO_ZERO)))) {
153 res = res - 1;
154 // check if we crossed into the lower decade
155 if (res == 0x00038d7ea4c67fffull) { // 10^15 - 1
156 res = 0x002386f26fc0ffffull; // 10^16 - 1
157 ind = ind - 1;
159 } else {
160 ; // exact, the result is already correct
163 if (res < 0x0020000000000000ull) { // res < 2^53
164 res = x_sign | (((UINT64) ind + 398) << 53) | res;
165 } else { // res >= 2^53
166 res =
167 x_sign | 0x6000000000000000ull | (((UINT64) ind + 398) << 51) |
168 (res & 0x0007ffffffffffffull);
171 BID_RETURN (res);
174 #if DECIMAL_CALL_BY_REFERENCE
175 void
176 bid64_from_uint64 (UINT64 * pres, UINT64 * px
177 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
178 _EXC_INFO_PARAM) {
179 UINT64 x = *px;
180 #if !DECIMAL_GLOBAL_ROUNDING
181 unsigned int rnd_mode = *prnd_mode;
182 #endif
183 #else
184 UINT64
185 bid64_from_uint64 (UINT64 x
186 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
187 _EXC_INFO_PARAM) {
188 #endif
190 UINT64 res;
191 UINT128 x128, res128;
192 unsigned int q, ind;
193 int incr_exp = 0;
194 int is_midpoint_lt_even = 0, is_midpoint_gt_even = 0;
195 int is_inexact_lt_midpoint = 0, is_inexact_gt_midpoint = 0;
197 if (x <= BID64_SIG_MAX) { // x <= 10^16-1 and the result is exact
198 if (x < 0x0020000000000000ull) { // x < 2^53
199 res = 0x31c0000000000000ull | x;
200 } else { // x >= 2^53
201 res = 0x6c70000000000000ull | (x & 0x0007ffffffffffffull);
203 } else { // x >= 10^16 and the result may be inexact
204 // the smallest x is 10^16 which has 17 decimal digits
205 // the largest x is 0xffffffffffffffff = 18446744073709551615 w/ 20 digits
206 if (x < 0x16345785d8a0000ull) { // x < 10^17
207 q = 17;
208 ind = 1; // number of digits to remove for q = 17
209 } else if (x < 0xde0b6b3a7640000ull) { // x < 10^18
210 q = 18;
211 ind = 2; // number of digits to remove for q = 18
212 } else if (x < 0x8ac7230489e80000ull) { // x < 10^19
213 q = 19;
214 ind = 3; // number of digits to remove for q = 19
215 } else { // x < 10^20
216 q = 20;
217 ind = 4; // number of digits to remove for q = 20
219 // overflow and underflow are not possible
220 // Note: performace can be improved by inlining this call
221 if (q <= 19) {
222 round64_2_18 ( // will work for 20 digits too if x fits in 64 bits
223 q, ind, x, &res, &incr_exp,
224 &is_midpoint_lt_even, &is_midpoint_gt_even,
225 &is_inexact_lt_midpoint, &is_inexact_gt_midpoint);
226 } else { // q = 20
227 x128.w[1] = 0x0;
228 x128.w[0] = x;
229 round128_19_38 (q, ind, x128, &res128, &incr_exp,
230 &is_midpoint_lt_even, &is_midpoint_gt_even,
231 &is_inexact_lt_midpoint, &is_inexact_gt_midpoint);
232 res = res128.w[0]; // res.w[1] is 0
234 if (incr_exp)
235 ind++;
236 // set the inexact flag
237 if (is_inexact_lt_midpoint || is_inexact_gt_midpoint ||
238 is_midpoint_lt_even || is_midpoint_gt_even)
239 *pfpsf |= INEXACT_EXCEPTION;
240 // general correction from RN to RA, RM, RP, RZ; result uses ind for exp
241 if (rnd_mode != ROUNDING_TO_NEAREST) {
242 if ((rnd_mode == ROUNDING_UP && is_inexact_lt_midpoint) ||
243 ((rnd_mode == ROUNDING_TIES_AWAY || rnd_mode == ROUNDING_UP)
244 && is_midpoint_gt_even)) {
245 res = res + 1;
246 if (res == 0x002386f26fc10000ull) { // res = 10^16 => rounding overflow
247 res = 0x00038d7ea4c68000ull; // 10^15
248 ind = ind + 1;
250 } else if ((is_midpoint_lt_even || is_inexact_gt_midpoint) &&
251 (rnd_mode == ROUNDING_DOWN ||
252 rnd_mode == ROUNDING_TO_ZERO)) {
253 res = res - 1;
254 // check if we crossed into the lower decade
255 if (res == 0x00038d7ea4c67fffull) { // 10^15 - 1
256 res = 0x002386f26fc0ffffull; // 10^16 - 1
257 ind = ind - 1;
259 } else {
260 ; // exact, the result is already correct
263 if (res < 0x0020000000000000ull) { // res < 2^53
264 res = (((UINT64) ind + 398) << 53) | res;
265 } else { // res >= 2^53
266 res = 0x6000000000000000ull | (((UINT64) ind + 398) << 51) |
267 (res & 0x0007ffffffffffffull);
270 BID_RETURN (res);
273 #if DECIMAL_CALL_BY_REFERENCE
274 void
275 bid128_from_int32 (UINT128 * pres,
276 int *px _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
277 int x = *px;
278 #else
279 UINT128
280 bid128_from_int32 (int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
281 #endif
282 UINT128 res;
284 // if integer is negative, use the absolute value
285 if ((x & SIGNMASK32) == SIGNMASK32) {
286 res.w[HIGH_128W] = 0xb040000000000000ull;
287 res.w[LOW_128W] = ~((unsigned int) x) + 1; // 2's complement of x
288 } else {
289 res.w[HIGH_128W] = 0x3040000000000000ull;
290 res.w[LOW_128W] = (unsigned int) x;
292 BID_RETURN (res);
295 #if DECIMAL_CALL_BY_REFERENCE
296 void
297 bid128_from_uint32 (UINT128 * pres, unsigned int *px
298 _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
299 unsigned int x = *px;
300 #else
301 UINT128
302 bid128_from_uint32 (unsigned int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
303 #endif
304 UINT128 res;
306 res.w[HIGH_128W] = 0x3040000000000000ull;
307 res.w[LOW_128W] = x;
308 BID_RETURN (res);
311 #if DECIMAL_CALL_BY_REFERENCE
312 void
313 bid128_from_int64 (UINT128 * pres, SINT64 * px
314 _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
315 SINT64 x = *px;
316 #else
317 UINT128
318 bid128_from_int64 (SINT64 x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
319 #endif
321 UINT128 res;
323 // if integer is negative, use the absolute value
324 if ((x & SIGNMASK64) == SIGNMASK64) {
325 res.w[HIGH_128W] = 0xb040000000000000ull;
326 res.w[LOW_128W] = ~x + 1; // 2's complement of x
327 } else {
328 res.w[HIGH_128W] = 0x3040000000000000ull;
329 res.w[LOW_128W] = x;
331 BID_RETURN (res);
334 #if DECIMAL_CALL_BY_REFERENCE
335 void
336 bid128_from_uint64 (UINT128 * pres, UINT64 * px
337 _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
338 UINT64 x = *px;
339 #else
340 UINT128
341 bid128_from_uint64 (UINT64 x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
342 #endif
344 UINT128 res;
346 res.w[HIGH_128W] = 0x3040000000000000ull;
347 res.w[LOW_128W] = x;
348 BID_RETURN (res);