]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/config/libbid/bid_from_int.c
Update copyright years.
[thirdparty/gcc.git] / libgcc / config / libbid / bid_from_int.c
CommitLineData
99dee823 1/* Copyright (C) 2007-2021 Free Software Foundation, Inc.
200359e8
L
2
3This file is part of GCC.
4
5GCC is free software; you can redistribute it and/or modify it under
6the terms of the GNU General Public License as published by the Free
748086b7 7Software Foundation; either version 3, or (at your option) any later
200359e8
L
8version.
9
200359e8
L
10GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11WARRANTY; without even the implied warranty of MERCHANTABILITY or
12FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13for more details.
14
748086b7
JJ
15Under Section 7 of GPL version 3, you are granted additional
16permissions described in the GCC Runtime Library Exception, version
173.1, as published by the Free Software Foundation.
18
19You should have received a copy of the GNU General Public License and
20a copy of the GCC Runtime Library Exception along with this program;
21see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
22<http://www.gnu.org/licenses/>. */
200359e8
L
23
24#include "bid_internal.h"
25
26/*****************************************************************************
27 * BID64_round_integral_exact
28 ****************************************************************************/
29
30#if DECIMAL_CALL_BY_REFERENCE
31void
b2a00c89 32bid64_from_int32 (UINT64 * pres,
200359e8
L
33 int *px _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
34 int x = *px;
35#else
36UINT64
b2a00c89 37bid64_from_int32 (int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
200359e8
L
38#endif
39 UINT64 res;
40
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
b2a00c89
L
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
200359e8
L
50 }
51 BID_RETURN (res);
52}
53
54#if DECIMAL_CALL_BY_REFERENCE
55void
b2a00c89 56bid64_from_uint32 (UINT64 * pres, unsigned int *px
200359e8
L
57 _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
58 unsigned int x = *px;
59#else
60UINT64
b2a00c89 61bid64_from_uint32 (unsigned int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
200359e8
L
62#endif
63 UINT64 res;
64
b2a00c89 65 res = x | 0x31c0000000000000ull; // (exp << 53)) = biased exp. is 0
200359e8
L
66 BID_RETURN (res);
67}
68
69#if DECIMAL_CALL_BY_REFERENCE
70void
b2a00c89 71bid64_from_int64 (UINT64 * pres, SINT64 * px
200359e8
L
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
79UINT64
b2a00c89 80bid64_from_int64 (SINT64 x
200359e8
L
81 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
82 _EXC_INFO_PARAM) {
83#endif
84
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;
91
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;
b2a00c89
L
98 if (C <= BID64_SIG_MAX) { // |C| <= 10^16-1 and the result is exact
99 if (C < 0x0020000000000000ull) { // C < 2^53
200359e8 100 res = x_sign | 0x31c0000000000000ull | C;
b2a00c89 101 } else { // C >= 2^53
200359e8
L
102 res =
103 x_sign | 0x6c70000000000000ull | (C & 0x0007ffffffffffffull);
104 }
b2a00c89 105 } else { // |C| >= 10^16 and the result may be inexact
200359e8
L
106 // the smallest |C| is 10^16 which has 17 decimal digits
107 // the largest |C| is 0x8000000000000000 = 9223372036854775808 w/ 19 digits
b2a00c89 108 if (C < 0x16345785d8a0000ull) { // x < 10^17
200359e8 109 q = 17;
b2a00c89
L
110 ind = 1; // number of digits to remove for q = 17
111 } else if (C < 0xde0b6b3a7640000ull) { // C < 10^18
200359e8 112 q = 18;
b2a00c89
L
113 ind = 2; // number of digits to remove for q = 18
114 } else { // C < 10^19
200359e8 115 q = 19;
b2a00c89 116 ind = 3; // number of digits to remove for q = 19
200359e8
L
117 }
118 // overflow and underflow are not possible
119 // Note: performace can be improved by inlining this call
b2a00c89 120 round64_2_18 ( // will work for 19 digits too if C fits in 64 bits
200359e8
L
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) {
b2a00c89
L
132 if ((!x_sign
133 && ((rnd_mode == ROUNDING_UP && is_inexact_lt_midpoint)
134 ||
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)
139 ||
140 ((rnd_mode == ROUNDING_TIES_AWAY
141 || rnd_mode == ROUNDING_DOWN)
142 && is_midpoint_gt_even)))) {
200359e8 143 res = res + 1;
b2a00c89
L
144 if (res == 0x002386f26fc10000ull) { // res = 10^16 => rounding overflow
145 res = 0x00038d7ea4c68000ull; // 10^15
200359e8
L
146 ind = ind + 1;
147 }
148 } else if ((is_midpoint_lt_even || is_inexact_gt_midpoint) &&
b2a00c89
L
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)))) {
200359e8
L
153 res = res - 1;
154 // check if we crossed into the lower decade
b2a00c89
L
155 if (res == 0x00038d7ea4c67fffull) { // 10^15 - 1
156 res = 0x002386f26fc0ffffull; // 10^16 - 1
200359e8
L
157 ind = ind - 1;
158 }
159 } else {
b2a00c89 160 ; // exact, the result is already correct
200359e8
L
161 }
162 }
b2a00c89 163 if (res < 0x0020000000000000ull) { // res < 2^53
200359e8 164 res = x_sign | (((UINT64) ind + 398) << 53) | res;
b2a00c89 165 } else { // res >= 2^53
200359e8
L
166 res =
167 x_sign | 0x6000000000000000ull | (((UINT64) ind + 398) << 51) |
168 (res & 0x0007ffffffffffffull);
169 }
170 }
171 BID_RETURN (res);
172}
173
174#if DECIMAL_CALL_BY_REFERENCE
175void
b2a00c89 176bid64_from_uint64 (UINT64 * pres, UINT64 * px
200359e8
L
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
184UINT64
b2a00c89 185bid64_from_uint64 (UINT64 x
200359e8
L
186 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
187 _EXC_INFO_PARAM) {
188#endif
189
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;
196
b2a00c89
L
197 if (x <= BID64_SIG_MAX) { // x <= 10^16-1 and the result is exact
198 if (x < 0x0020000000000000ull) { // x < 2^53
200359e8 199 res = 0x31c0000000000000ull | x;
b2a00c89 200 } else { // x >= 2^53
200359e8
L
201 res = 0x6c70000000000000ull | (x & 0x0007ffffffffffffull);
202 }
b2a00c89 203 } else { // x >= 10^16 and the result may be inexact
200359e8
L
204 // the smallest x is 10^16 which has 17 decimal digits
205 // the largest x is 0xffffffffffffffff = 18446744073709551615 w/ 20 digits
b2a00c89 206 if (x < 0x16345785d8a0000ull) { // x < 10^17
200359e8 207 q = 17;
b2a00c89
L
208 ind = 1; // number of digits to remove for q = 17
209 } else if (x < 0xde0b6b3a7640000ull) { // x < 10^18
200359e8 210 q = 18;
b2a00c89
L
211 ind = 2; // number of digits to remove for q = 18
212 } else if (x < 0x8ac7230489e80000ull) { // x < 10^19
200359e8 213 q = 19;
b2a00c89
L
214 ind = 3; // number of digits to remove for q = 19
215 } else { // x < 10^20
200359e8 216 q = 20;
b2a00c89 217 ind = 4; // number of digits to remove for q = 20
200359e8
L
218 }
219 // overflow and underflow are not possible
220 // Note: performace can be improved by inlining this call
221 if (q <= 19) {
b2a00c89 222 round64_2_18 ( // will work for 20 digits too if x fits in 64 bits
200359e8
L
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);
b2a00c89 226 } else { // q = 20
200359e8
L
227 x128.w[1] = 0x0;
228 x128.w[0] = x;
b2a00c89 229 round128_19_38 (q, ind, x128, &res128, &incr_exp,
200359e8
L
230 &is_midpoint_lt_even, &is_midpoint_gt_even,
231 &is_inexact_lt_midpoint, &is_inexact_gt_midpoint);
b2a00c89 232 res = res128.w[0]; // res.w[1] is 0
200359e8
L
233 }
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) {
b2a00c89
L
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)) {
200359e8 245 res = res + 1;
b2a00c89
L
246 if (res == 0x002386f26fc10000ull) { // res = 10^16 => rounding overflow
247 res = 0x00038d7ea4c68000ull; // 10^15
200359e8
L
248 ind = ind + 1;
249 }
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
b2a00c89
L
255 if (res == 0x00038d7ea4c67fffull) { // 10^15 - 1
256 res = 0x002386f26fc0ffffull; // 10^16 - 1
200359e8
L
257 ind = ind - 1;
258 }
259 } else {
b2a00c89 260 ; // exact, the result is already correct
200359e8
L
261 }
262 }
b2a00c89 263 if (res < 0x0020000000000000ull) { // res < 2^53
200359e8 264 res = (((UINT64) ind + 398) << 53) | res;
b2a00c89 265 } else { // res >= 2^53
200359e8
L
266 res = 0x6000000000000000ull | (((UINT64) ind + 398) << 51) |
267 (res & 0x0007ffffffffffffull);
268 }
269 }
270 BID_RETURN (res);
271}
272
273#if DECIMAL_CALL_BY_REFERENCE
274void
b2a00c89 275bid128_from_int32 (UINT128 * pres,
200359e8
L
276 int *px _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
277 int x = *px;
278#else
279UINT128
b2a00c89 280bid128_from_int32 (int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
200359e8
L
281#endif
282 UINT128 res;
283
284 // if integer is negative, use the absolute value
285 if ((x & SIGNMASK32) == SIGNMASK32) {
286 res.w[HIGH_128W] = 0xb040000000000000ull;
b2a00c89 287 res.w[LOW_128W] = ~((unsigned int) x) + 1; // 2's complement of x
200359e8
L
288 } else {
289 res.w[HIGH_128W] = 0x3040000000000000ull;
b2a00c89 290 res.w[LOW_128W] = (unsigned int) x;
200359e8
L
291 }
292 BID_RETURN (res);
293}
294
295#if DECIMAL_CALL_BY_REFERENCE
296void
b2a00c89 297bid128_from_uint32 (UINT128 * pres, unsigned int *px
200359e8
L
298 _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
299 unsigned int x = *px;
300#else
301UINT128
b2a00c89 302bid128_from_uint32 (unsigned int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
200359e8
L
303#endif
304 UINT128 res;
305
306 res.w[HIGH_128W] = 0x3040000000000000ull;
307 res.w[LOW_128W] = x;
308 BID_RETURN (res);
309}
310
311#if DECIMAL_CALL_BY_REFERENCE
312void
b2a00c89 313bid128_from_int64 (UINT128 * pres, SINT64 * px
200359e8
L
314 _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
315 SINT64 x = *px;
316#else
317UINT128
b2a00c89 318bid128_from_int64 (SINT64 x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
200359e8
L
319#endif
320
321 UINT128 res;
322
323 // if integer is negative, use the absolute value
324 if ((x & SIGNMASK64) == SIGNMASK64) {
325 res.w[HIGH_128W] = 0xb040000000000000ull;
b2a00c89 326 res.w[LOW_128W] = ~x + 1; // 2's complement of x
200359e8
L
327 } else {
328 res.w[HIGH_128W] = 0x3040000000000000ull;
329 res.w[LOW_128W] = x;
330 }
331 BID_RETURN (res);
332}
333
334#if DECIMAL_CALL_BY_REFERENCE
335void
b2a00c89 336bid128_from_uint64 (UINT128 * pres, UINT64 * px
200359e8
L
337 _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
338 UINT64 x = *px;
339#else
340UINT128
b2a00c89 341bid128_from_uint64 (UINT64 x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
200359e8
L
342#endif
343
344 UINT128 res;
345
346 res.w[HIGH_128W] = 0x3040000000000000ull;
347 res.w[LOW_128W] = x;
348 BID_RETURN (res);
349}