Merge -r 127928:132243 from trunk
[official-gcc.git] / libgcc / config / libbid / bid_from_int.c
blobbebc1351c243c9abb715eb96a1ec53ab4e2e84f7
1 /* Copyright (C) 2007 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 2, or (at your option) any later
8 version.
10 In addition to the permissions in the GNU General Public License, the
11 Free Software Foundation gives you unlimited permission to link the
12 compiled version of this file into combinations with other programs,
13 and to distribute those combinations without any restriction coming
14 from the use of this file. (The General Public License restrictions
15 do apply in other respects; for example, they cover modification of
16 the file, and distribution when not linked into a combine
17 executable.)
19 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
20 WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 for more details.
24 You should have received a copy of the GNU General Public License
25 along with GCC; see the file COPYING. If not, write to the Free
26 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
27 02110-1301, USA. */
29 #include "bid_internal.h"
31 /*****************************************************************************
32 * BID64_round_integral_exact
33 ****************************************************************************/
35 #if DECIMAL_CALL_BY_REFERENCE
36 void
37 bid64_from_int32 (UINT64 * pres,
38 int *px _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
39 int x = *px;
40 #else
41 UINT64
42 bid64_from_int32 (int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
43 #endif
44 UINT64 res;
46 // if integer is negative, put the absolute value
47 // in the lowest 32bits of the result
48 if ((x & SIGNMASK32) == SIGNMASK32) {
49 // negative int32
50 x = ~x + 1; // 2's complement of x
51 res = (unsigned int) x | 0xb1c0000000000000ull;
52 // (exp << 53)) = biased exp. is 0
53 } else { // positive int32
54 res = x | 0x31c0000000000000ull; // (exp << 53)) = biased exp. is 0
56 BID_RETURN (res);
59 #if DECIMAL_CALL_BY_REFERENCE
60 void
61 bid64_from_uint32 (UINT64 * pres, unsigned int *px
62 _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
63 unsigned int x = *px;
64 #else
65 UINT64
66 bid64_from_uint32 (unsigned int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
67 #endif
68 UINT64 res;
70 res = x | 0x31c0000000000000ull; // (exp << 53)) = biased exp. is 0
71 BID_RETURN (res);
74 #if DECIMAL_CALL_BY_REFERENCE
75 void
76 bid64_from_int64 (UINT64 * pres, SINT64 * px
77 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
78 _EXC_INFO_PARAM) {
79 SINT64 x = *px;
80 #if !DECIMAL_GLOBAL_ROUNDING
81 unsigned int rnd_mode = *prnd_mode;
82 #endif
83 #else
84 UINT64
85 bid64_from_int64 (SINT64 x
86 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
87 _EXC_INFO_PARAM) {
88 #endif
90 UINT64 res;
91 UINT64 x_sign, C;
92 unsigned int q, ind;
93 int incr_exp = 0;
94 int is_midpoint_lt_even = 0, is_midpoint_gt_even = 0;
95 int is_inexact_lt_midpoint = 0, is_inexact_gt_midpoint = 0;
97 x_sign = x & 0x8000000000000000ull;
98 // if the integer is negative, use the absolute value
99 if (x_sign)
100 C = ~((UINT64) x) + 1;
101 else
102 C = x;
103 if (C <= BID64_SIG_MAX) { // |C| <= 10^16-1 and the result is exact
104 if (C < 0x0020000000000000ull) { // C < 2^53
105 res = x_sign | 0x31c0000000000000ull | C;
106 } else { // C >= 2^53
107 res =
108 x_sign | 0x6c70000000000000ull | (C & 0x0007ffffffffffffull);
110 } else { // |C| >= 10^16 and the result may be inexact
111 // the smallest |C| is 10^16 which has 17 decimal digits
112 // the largest |C| is 0x8000000000000000 = 9223372036854775808 w/ 19 digits
113 if (C < 0x16345785d8a0000ull) { // x < 10^17
114 q = 17;
115 ind = 1; // number of digits to remove for q = 17
116 } else if (C < 0xde0b6b3a7640000ull) { // C < 10^18
117 q = 18;
118 ind = 2; // number of digits to remove for q = 18
119 } else { // C < 10^19
120 q = 19;
121 ind = 3; // number of digits to remove for q = 19
123 // overflow and underflow are not possible
124 // Note: performace can be improved by inlining this call
125 round64_2_18 ( // will work for 19 digits too if C fits in 64 bits
126 q, ind, C, &res, &incr_exp,
127 &is_midpoint_lt_even, &is_midpoint_gt_even,
128 &is_inexact_lt_midpoint, &is_inexact_gt_midpoint);
129 if (incr_exp)
130 ind++;
131 // set the inexact flag
132 if (is_inexact_lt_midpoint || is_inexact_gt_midpoint ||
133 is_midpoint_lt_even || is_midpoint_gt_even)
134 *pfpsf |= INEXACT_EXCEPTION;
135 // general correction from RN to RA, RM, RP, RZ; result uses ind for exp
136 if (rnd_mode != ROUNDING_TO_NEAREST) {
137 if ((!x_sign
138 && ((rnd_mode == ROUNDING_UP && is_inexact_lt_midpoint)
140 ((rnd_mode == ROUNDING_TIES_AWAY
141 || rnd_mode == ROUNDING_UP) && is_midpoint_gt_even)))
142 || (x_sign
143 && ((rnd_mode == ROUNDING_DOWN && is_inexact_lt_midpoint)
145 ((rnd_mode == ROUNDING_TIES_AWAY
146 || rnd_mode == ROUNDING_DOWN)
147 && is_midpoint_gt_even)))) {
148 res = res + 1;
149 if (res == 0x002386f26fc10000ull) { // res = 10^16 => rounding overflow
150 res = 0x00038d7ea4c68000ull; // 10^15
151 ind = ind + 1;
153 } else if ((is_midpoint_lt_even || is_inexact_gt_midpoint) &&
154 ((x_sign && (rnd_mode == ROUNDING_UP ||
155 rnd_mode == ROUNDING_TO_ZERO)) ||
156 (!x_sign && (rnd_mode == ROUNDING_DOWN ||
157 rnd_mode == ROUNDING_TO_ZERO)))) {
158 res = res - 1;
159 // check if we crossed into the lower decade
160 if (res == 0x00038d7ea4c67fffull) { // 10^15 - 1
161 res = 0x002386f26fc0ffffull; // 10^16 - 1
162 ind = ind - 1;
164 } else {
165 ; // exact, the result is already correct
168 if (res < 0x0020000000000000ull) { // res < 2^53
169 res = x_sign | (((UINT64) ind + 398) << 53) | res;
170 } else { // res >= 2^53
171 res =
172 x_sign | 0x6000000000000000ull | (((UINT64) ind + 398) << 51) |
173 (res & 0x0007ffffffffffffull);
176 BID_RETURN (res);
179 #if DECIMAL_CALL_BY_REFERENCE
180 void
181 bid64_from_uint64 (UINT64 * pres, UINT64 * px
182 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
183 _EXC_INFO_PARAM) {
184 UINT64 x = *px;
185 #if !DECIMAL_GLOBAL_ROUNDING
186 unsigned int rnd_mode = *prnd_mode;
187 #endif
188 #else
189 UINT64
190 bid64_from_uint64 (UINT64 x
191 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
192 _EXC_INFO_PARAM) {
193 #endif
195 UINT64 res;
196 UINT128 x128, res128;
197 unsigned int q, ind;
198 int incr_exp = 0;
199 int is_midpoint_lt_even = 0, is_midpoint_gt_even = 0;
200 int is_inexact_lt_midpoint = 0, is_inexact_gt_midpoint = 0;
202 if (x <= BID64_SIG_MAX) { // x <= 10^16-1 and the result is exact
203 if (x < 0x0020000000000000ull) { // x < 2^53
204 res = 0x31c0000000000000ull | x;
205 } else { // x >= 2^53
206 res = 0x6c70000000000000ull | (x & 0x0007ffffffffffffull);
208 } else { // x >= 10^16 and the result may be inexact
209 // the smallest x is 10^16 which has 17 decimal digits
210 // the largest x is 0xffffffffffffffff = 18446744073709551615 w/ 20 digits
211 if (x < 0x16345785d8a0000ull) { // x < 10^17
212 q = 17;
213 ind = 1; // number of digits to remove for q = 17
214 } else if (x < 0xde0b6b3a7640000ull) { // x < 10^18
215 q = 18;
216 ind = 2; // number of digits to remove for q = 18
217 } else if (x < 0x8ac7230489e80000ull) { // x < 10^19
218 q = 19;
219 ind = 3; // number of digits to remove for q = 19
220 } else { // x < 10^20
221 q = 20;
222 ind = 4; // number of digits to remove for q = 20
224 // overflow and underflow are not possible
225 // Note: performace can be improved by inlining this call
226 if (q <= 19) {
227 round64_2_18 ( // will work for 20 digits too if x fits in 64 bits
228 q, ind, x, &res, &incr_exp,
229 &is_midpoint_lt_even, &is_midpoint_gt_even,
230 &is_inexact_lt_midpoint, &is_inexact_gt_midpoint);
231 } else { // q = 20
232 x128.w[1] = 0x0;
233 x128.w[0] = x;
234 round128_19_38 (q, ind, x128, &res128, &incr_exp,
235 &is_midpoint_lt_even, &is_midpoint_gt_even,
236 &is_inexact_lt_midpoint, &is_inexact_gt_midpoint);
237 res = res128.w[0]; // res.w[1] is 0
239 if (incr_exp)
240 ind++;
241 // set the inexact flag
242 if (is_inexact_lt_midpoint || is_inexact_gt_midpoint ||
243 is_midpoint_lt_even || is_midpoint_gt_even)
244 *pfpsf |= INEXACT_EXCEPTION;
245 // general correction from RN to RA, RM, RP, RZ; result uses ind for exp
246 if (rnd_mode != ROUNDING_TO_NEAREST) {
247 if ((rnd_mode == ROUNDING_UP && is_inexact_lt_midpoint) ||
248 ((rnd_mode == ROUNDING_TIES_AWAY || rnd_mode == ROUNDING_UP)
249 && is_midpoint_gt_even)) {
250 res = res + 1;
251 if (res == 0x002386f26fc10000ull) { // res = 10^16 => rounding overflow
252 res = 0x00038d7ea4c68000ull; // 10^15
253 ind = ind + 1;
255 } else if ((is_midpoint_lt_even || is_inexact_gt_midpoint) &&
256 (rnd_mode == ROUNDING_DOWN ||
257 rnd_mode == ROUNDING_TO_ZERO)) {
258 res = res - 1;
259 // check if we crossed into the lower decade
260 if (res == 0x00038d7ea4c67fffull) { // 10^15 - 1
261 res = 0x002386f26fc0ffffull; // 10^16 - 1
262 ind = ind - 1;
264 } else {
265 ; // exact, the result is already correct
268 if (res < 0x0020000000000000ull) { // res < 2^53
269 res = (((UINT64) ind + 398) << 53) | res;
270 } else { // res >= 2^53
271 res = 0x6000000000000000ull | (((UINT64) ind + 398) << 51) |
272 (res & 0x0007ffffffffffffull);
275 BID_RETURN (res);
278 #if DECIMAL_CALL_BY_REFERENCE
279 void
280 bid128_from_int32 (UINT128 * pres,
281 int *px _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
282 int x = *px;
283 #else
284 UINT128
285 bid128_from_int32 (int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
286 #endif
287 UINT128 res;
289 // if integer is negative, use the absolute value
290 if ((x & SIGNMASK32) == SIGNMASK32) {
291 res.w[HIGH_128W] = 0xb040000000000000ull;
292 res.w[LOW_128W] = ~((unsigned int) x) + 1; // 2's complement of x
293 } else {
294 res.w[HIGH_128W] = 0x3040000000000000ull;
295 res.w[LOW_128W] = (unsigned int) x;
297 BID_RETURN (res);
300 #if DECIMAL_CALL_BY_REFERENCE
301 void
302 bid128_from_uint32 (UINT128 * pres, unsigned int *px
303 _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
304 unsigned int x = *px;
305 #else
306 UINT128
307 bid128_from_uint32 (unsigned int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
308 #endif
309 UINT128 res;
311 res.w[HIGH_128W] = 0x3040000000000000ull;
312 res.w[LOW_128W] = x;
313 BID_RETURN (res);
316 #if DECIMAL_CALL_BY_REFERENCE
317 void
318 bid128_from_int64 (UINT128 * pres, SINT64 * px
319 _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
320 SINT64 x = *px;
321 #else
322 UINT128
323 bid128_from_int64 (SINT64 x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
324 #endif
326 UINT128 res;
328 // if integer is negative, use the absolute value
329 if ((x & SIGNMASK64) == SIGNMASK64) {
330 res.w[HIGH_128W] = 0xb040000000000000ull;
331 res.w[LOW_128W] = ~x + 1; // 2's complement of x
332 } else {
333 res.w[HIGH_128W] = 0x3040000000000000ull;
334 res.w[LOW_128W] = x;
336 BID_RETURN (res);
339 #if DECIMAL_CALL_BY_REFERENCE
340 void
341 bid128_from_uint64 (UINT128 * pres, UINT64 * px
342 _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
343 UINT64 x = *px;
344 #else
345 UINT128
346 bid128_from_uint64 (UINT64 x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
347 #endif
349 UINT128 res;
351 res.w[HIGH_128W] = 0x3040000000000000ull;
352 res.w[LOW_128W] = x;
353 BID_RETURN (res);