OSDN Git Service

2007-12-19 Etsushi Kato <ek.kato@gmail.com>
[pf3gnuchains/gcc-fork.git] / libgcc / config / libbid / bid_from_int.c
1 /* Copyright (C) 2007  Free Software Foundation, Inc.
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
7 Software Foundation; either version 2, or (at your option) any later
8 version.
9
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.)
18
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.
23
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.  */
28
29 #include "bid_internal.h"
30
31 /*****************************************************************************
32  *  BID64_round_integral_exact
33  ****************************************************************************/
34
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;
45
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
55   }
56   BID_RETURN (res);
57 }
58
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;
69
70   res = x | 0x31c0000000000000ull;      // (exp << 53)) = biased exp. is 0
71   BID_RETURN (res);
72 }
73
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
89
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;
96
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);
109     }
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
122     }
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)
139                ||
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)
144                   ||
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;
152         }
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;
163         }
164       } else {
165         ;       // exact, the result is already correct
166       }
167     }
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);
174     }
175   }
176   BID_RETURN (res);
177 }
178
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
194
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;
201
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);
207     }
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
223     }
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
238     }
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;
254         }
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;
263         }
264       } else {
265         ;       // exact, the result is already correct
266       }
267     }
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);
273     }
274   }
275   BID_RETURN (res);
276 }
277
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;
288
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;
296   }
297   BID_RETURN (res);
298 }
299
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;
310
311   res.w[HIGH_128W] = 0x3040000000000000ull;
312   res.w[LOW_128W] = x;
313   BID_RETURN (res);
314 }
315
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
325
326   UINT128 res;
327
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;
335   }
336   BID_RETURN (res);
337 }
338
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
348
349   UINT128 res;
350
351   res.w[HIGH_128W] = 0x3040000000000000ull;
352   res.w[LOW_128W] = x;
353   BID_RETURN (res);
354 }